feat(scene): shared zoom/pan for control and presentation
Keep effects pinned to map coordinates when the viewport changes; materials/NPC overlays stay screen-fixed. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
clampSceneViewCamera,
|
||||
DEFAULT_SCENE_VIEW_CAMERA,
|
||||
type SceneViewCamera,
|
||||
type SceneViewEvent,
|
||||
type SceneViewState,
|
||||
} from '../../shared/types';
|
||||
|
||||
function emptyState(): SceneViewState {
|
||||
return {
|
||||
revision: 1,
|
||||
...DEFAULT_SCENE_VIEW_CAMERA,
|
||||
};
|
||||
}
|
||||
|
||||
export class SceneViewStore {
|
||||
private state: SceneViewState = emptyState();
|
||||
|
||||
getState(): SceneViewState {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
reset(): SceneViewState {
|
||||
if (
|
||||
this.state.scale === 1 &&
|
||||
this.state.ox === 0.5 &&
|
||||
this.state.oy === 0.5
|
||||
) {
|
||||
return this.state;
|
||||
}
|
||||
this.state = {
|
||||
revision: this.state.revision + 1,
|
||||
...DEFAULT_SCENE_VIEW_CAMERA,
|
||||
};
|
||||
return this.state;
|
||||
}
|
||||
|
||||
dispatch(event: SceneViewEvent): SceneViewState {
|
||||
switch (event.kind) {
|
||||
case 'reset':
|
||||
return this.reset();
|
||||
case 'set': {
|
||||
const camera: SceneViewCamera = clampSceneViewCamera(event.camera);
|
||||
if (
|
||||
camera.scale === this.state.scale &&
|
||||
camera.ox === this.state.ox &&
|
||||
camera.oy === this.state.oy
|
||||
) {
|
||||
return this.state;
|
||||
}
|
||||
this.state = {
|
||||
revision: this.state.revision + 1,
|
||||
...camera,
|
||||
};
|
||||
return this.state;
|
||||
}
|
||||
default: {
|
||||
const _exhaustive: never = event;
|
||||
void _exhaustive;
|
||||
return this.state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user