From 5ec73e362d5613d033a5f26ea4a9c5cbd76f6dcd Mon Sep 17 00:00:00 2001 From: Tanish Manku Date: Thu, 30 Apr 2026 23:50:16 -0700 Subject: [PATCH] PageScene: move change_mode + toggleTransformSpace into GizmoController MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GizmoController now reads/writes the store's transformSpace through a new GizmoControllerDeps surface that Editor wires up in initialize(). - changeMode(type) reads the desired space from the store internally (forces local for scale), so callers don't plumb space through. - toggleTransformSpace() owns the read/flip/write/apply loop that used to live on Editor.toggleTransformSpace. Editor.change_mode and Editor.toggleTransformSpace are deleted. Callers updated: - actions/setTransformMode.ts → editor.gizmo.changeMode(...) - Controls3D.tsx → editorEngine?.gizmo.toggleTransformSpace() - keymap.ts → editor.gizmo.changeMode + .toggleTransformSpace; the inline setGizmoMode body shrinks to one line and the duplicate toggleTransformSpace helper is gone. --- .../PageScene/actions/setTransformMode.ts | 2 +- .../PageScene/comps/Controls3D/Controls3D.tsx | 2 +- .../app/src/pages/PageScene/engine/editor.ts | 24 +++---------- .../engine/editor/GizmoController.ts | 35 ++++++++++++++++--- .../app/src/pages/PageScene/engine/keymap.ts | 18 ++-------- 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/actions/setTransformMode.ts b/frontend/apps/artcraft/app/src/pages/PageScene/actions/setTransformMode.ts index ce75ba0f88..06fddd66ee 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/actions/setTransformMode.ts +++ b/frontend/apps/artcraft/app/src/pages/PageScene/actions/setTransformMode.ts @@ -8,7 +8,7 @@ const ENGINE_MODE: Record = { }; export function setTransformMode(editor: Editor, mode: TransformMode): void { - editor.change_mode(ENGINE_MODE[mode]); + editor.gizmo.changeMode(ENGINE_MODE[mode]); const store = usePageSceneStore.getState(); store.setTransformMode(mode); store.setSelectedMode(mode); diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/comps/Controls3D/Controls3D.tsx b/frontend/apps/artcraft/app/src/pages/PageScene/comps/Controls3D/Controls3D.tsx index 08a242afca..6cb4b81db9 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/comps/Controls3D/Controls3D.tsx +++ b/frontend/apps/artcraft/app/src/pages/PageScene/comps/Controls3D/Controls3D.tsx @@ -318,7 +318,7 @@ export const Controls3D = () => { > diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor.ts b/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor.ts index 91d49a7a65..4ca92131d8 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor.ts +++ b/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor.ts @@ -136,7 +136,11 @@ class Editor { // PostProcessingPipeline must exist before Scene because Scene's // load paths invoke updateSurfaceIdAttributeToMesh as a callback. this.postProcessing = new PostProcessingPipeline(); - this.gizmo = new GizmoController(); + this.gizmo = new GizmoController({ + getTransformSpace: () => usePageSceneStore.getState().transformSpace, + setTransformSpace: (space) => + usePageSceneStore.getState().setTransformSpace(space), + }); this.cameraController = new CameraController({ getThreeScene: () => this.activeScene.scene, getHotItems: () => this.activeScene.hot_items ?? null, @@ -823,24 +827,6 @@ class Editor { console.log("3D Editor Engine unmounted"); } - // Facade for actions/setTransformMode + keymap dispatch. Reads the - // store's current transform space and forwards to the gizmo. - change_mode(type: "translate" | "rotate" | "scale") { - const space = - type === "scale" ? "local" : usePageSceneStore.getState().transformSpace; - this.gizmo.changeMode(type, space); - } - - // Facade for Controls3D button + keymap. Toggles the store's - // transform space and pushes the new value into the gizmo. - toggleTransformSpace() { - if (!this.gizmo.canToggleSpace()) return; - const store = usePageSceneStore.getState(); - const next = store.transformSpace === "world" ? "local" : "world"; - store.setTransformSpace(next); - this.gizmo.setSpace(next); - } - // Facades — external callers in actions/* and helper.ts target these // names. Internals reach the bridge directly via this.selection.*. updateOutliner() { diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor/GizmoController.ts b/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor/GizmoController.ts index e7b444b4f0..75fe2cc6d4 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor/GizmoController.ts +++ b/frontend/apps/artcraft/app/src/pages/PageScene/engine/editor/GizmoController.ts @@ -4,9 +4,8 @@ // on Editor), then `configure()` wires it to the camera/renderer once // initialize() has produced them. // -// No `editor` reference, no `import type Editor`. Store access stays on -// Editor's facades (change_mode, toggleTransformSpace); this module only -// translates them into TransformControls calls. +// Store access for the transform-space pref is injected via Deps so the +// controller doesn't import the Zustand store directly. import type * as THREE from "three"; import { TransformControls } from "../TransformControls.js"; @@ -22,9 +21,23 @@ export type GizmoCallbacks = { onDraggingChanged: (dragging: boolean) => void; }; +// Capabilities the gizmo needs from outside its own state. +// Editor wires these in initialize() so GizmoController never imports +// the store directly. +export type GizmoControllerDeps = { + getTransformSpace: () => TransformSpace; + setTransformSpace: (space: TransformSpace) => void; +}; + export class GizmoController { control: TransformControls | undefined; + private deps: GizmoControllerDeps; + + constructor(deps: GizmoControllerDeps) { + this.deps = deps; + } + configure( camera: THREE.PerspectiveCamera | null, domElement: HTMLElement, @@ -45,8 +58,11 @@ export class GizmoController { scene.add(this.control); } - changeMode(type: TransformMode, space: TransformSpace) { + // Apply a transform mode. Reads the desired space from the store so + // callers don't need to plumb it through. Scale is always local. + changeMode(type: TransformMode) { if (this.control == undefined) return; + const space = type === "scale" ? "local" : this.deps.getTransformSpace(); this.control.mode = type; this.control.space = space; } @@ -56,6 +72,17 @@ export class GizmoController { this.control.space = space; } + // Flip the store's transform-space preference and push the new value + // into the live gizmo. No-op when the gizmo is in scale mode (scale + // is always local). + toggleTransformSpace() { + if (!this.canToggleSpace()) return; + const next = + this.deps.getTransformSpace() === "world" ? "local" : "world"; + this.deps.setTransformSpace(next); + this.setSpace(next); + } + // True when the gizmo exists and is in a mode where toggling between // world/local space is meaningful (scale is always local). canToggleSpace(): boolean { diff --git a/frontend/apps/artcraft/app/src/pages/PageScene/engine/keymap.ts b/frontend/apps/artcraft/app/src/pages/PageScene/engine/keymap.ts index 37ecb624ad..3ef85b7dc8 100644 --- a/frontend/apps/artcraft/app/src/pages/PageScene/engine/keymap.ts +++ b/frontend/apps/artcraft/app/src/pages/PageScene/engine/keymap.ts @@ -26,25 +26,11 @@ const setGizmoMode = ( gizmoMode: "translate" | "rotate" | "scale", storeMode: "move" | "rotate" | "scale", ) => { - editor.mouse_controls?.control?.setMode(gizmoMode); - const space = usePageSceneStore.getState().transformSpace; - if (editor.mouse_controls?.control) { - editor.mouse_controls.control.space = space; - } + editor.gizmo.changeMode(gizmoMode); usePageSceneStore.getState().setTransformMode(storeMode); usePageSceneStore.getState().setSelectedMode(storeMode); }; -const toggleTransformSpace = (editor: Editor) => { - if (editor.mouse_controls?.control?.mode === "scale") return; - const next = - usePageSceneStore.getState().transformSpace === "world" ? "local" : "world"; - usePageSceneStore.getState().setTransformSpace(next); - if (editor.mouse_controls?.control) { - editor.mouse_controls.control.space = next; - } -}; - const deleteSelected = (editor: Editor) => { const mc = editor.mouse_controls; if (!mc?.selected) return; @@ -108,7 +94,7 @@ export const buildKeymap = (): KeyBinding[] => [ { code: "KeyG", label: "Scale", group: "Transform", run: (e) => setGizmoMode(e, "scale", "scale") }, { code: "KeyX", label: "Toggle local/world", group: "Transform", - run: toggleTransformSpace }, + run: (e) => e.gizmo.toggleTransformSpace() }, { code: "KeyK", label: "Toggle pose (FK)", group: "Transform", run: (e) => e.mouse_controls?.toggleFKMode() },