fix: game audio persistence and editor perf

- Keep game/campaign audio assets referenced (no prune)
- Flush pending project save on quit/switch/export to avoid losing campaignAudios
- Control: prevent game music restarts on scene changes; allow always-on controls; handle autoplay-after-scene-audio
- Editor: reduce ReactFlow churn with stable scene card map; lazy/async image decode
- Add contract/unit tests and update test script

Made-with: Cursor
This commit is contained in:
Ivan Fontosh
2026-04-22 19:06:16 +08:00
parent f823a7c05f
commit 1d051f8bf9
19 changed files with 1164 additions and 115 deletions
+10
View File
@@ -29,6 +29,8 @@ export const ipcChannels = {
setCurrentScene: 'project.setCurrentScene',
setCurrentGraphNode: 'project.setCurrentGraphNode',
importMedia: 'project.importMedia',
importCampaignAudio: 'project.importCampaignAudio',
updateCampaignAudios: 'project.updateCampaignAudios',
importScenePreview: 'project.importScenePreview',
clearScenePreview: 'project.clearScenePreview',
assetFileUrl: 'project.assetFileUrl',
@@ -120,6 +122,14 @@ export type IpcInvokeMap = {
req: { sceneId: SceneId };
res: { project: Project; imported: MediaAsset[] };
};
[ipcChannels.project.importCampaignAudio]: {
req: Record<string, never>;
res: { canceled: boolean; project: Project; imported: MediaAsset[] };
};
[ipcChannels.project.updateCampaignAudios]: {
req: { audios: Project['campaignAudios'] };
res: { project: Project };
};
[ipcChannels.project.importScenePreview]: {
req: { sceneId: SceneId };
res: { project: Project };
+2
View File
@@ -112,6 +112,8 @@ export type Project = {
meta: ProjectMeta;
scenes: Record<SceneId, Scene>;
assets: Record<AssetId, MediaAsset>;
/** Аудио кампании: играет в пульте на протяжении всей презентации, если в сцене нет своей музыки. */
campaignAudios: SceneAudioRef[];
currentSceneId: SceneId | null;
/** Текущая нода графа (важно, когда одна сцена имеет несколько нод). */
currentGraphNodeId: GraphNodeId | null;