feat(scene): keep map tokens with preview rotation

When previewRotationDeg changes, remap non-player, NPC and trap
markers (plus live session token overrides) so they stay on the art.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-08-11 12:29:20 +08:00
parent 7362a36fe5
commit 46bec1a86a
11 changed files with 312 additions and 1 deletions
+28
View File
@@ -20,6 +20,10 @@ import {
} from '../shared/project/projectZipExtension';
import type { Project } from '../shared/types';
import { asNpcId } from '../shared/types/ids';
import {
asPreviewRotationDeg,
previewRotationStepsCw,
} from '../shared/types/scenePreviewRotation';
import { EffectsStore, effectsDefaultTool } from './effects/effectsStore';
import { SceneDarknessStore } from './effects/sceneDarknessStore';
@@ -678,6 +682,7 @@ async function main() {
};
});
registerHandler(ipcChannels.project.updateScene, async ({ sceneId, patch }) => {
const before = projectStore.getOpenProject()?.scenes[sceneId];
const next = await projectStore.updateScene(sceneId, patch);
const project = projectStore.getOpenProject();
if (project?.currentSceneId === sceneId && patch.darkenScene !== undefined) {
@@ -688,6 +693,29 @@ async function main() {
syncSceneTrapsForProject(project);
emitSceneTrapsState();
}
if (
project?.currentSceneId === sceneId &&
patch.previewRotationDeg !== undefined &&
before
) {
const steps = previewRotationStepsCw(
asPreviewRotationDeg(before.previewRotationDeg),
asPreviewRotationDeg(patch.previewRotationDeg),
);
if (steps !== 0) {
sceneTokensSessionStore.rotateMapCwSteps(steps);
sceneNpcTokensSessionStore.rotateMapCwSteps(steps);
scenePlayerTokensSessionStore.rotateMapCwSteps(steps);
emitSceneTokensSessionState();
emitSceneNpcTokensSessionState();
emitScenePlayerTokensSessionState();
}
}
if (project && project.currentSceneId === sceneId && patch.previewRotationDeg !== undefined) {
// Trap ids stay the same; runtime statuses remain valid after coordinate remap in project.
syncSceneTrapsForProject(project);
emitSceneTrapsState();
}
emitSessionState();
return { scene: next };
});