From d254582597fc4d14a625ccf5600cf0a0beba35ff Mon Sep 17 00:00:00 2001 From: Wassim SAMAD Date: Thu, 14 May 2026 16:26:29 -0400 Subject: [PATCH] MoveTool: dispatch registry-first so spawn move uses MoveRegistryNodeTool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shim ordering bug: the `nodeRegistry.has(movingNode.type)` check sat at the END of the dispatch chain, AFTER the per-kind `if (movingNode.type === 'spawn') return ` branches. Spawn (now registered in builtinPlugin) was therefore still routing to the legacy MoveSpawnTool — which uses the broken useLiveTransforms pattern and makes the spawn mesh disappear during drag. Moved the registry check to the TOP, matching the registry-first dispatch model the Phase 0 shims use everywhere else (NodeRenderer, ToolManager, system guards). Now any kind registered via @pascal-app/nodes routes to MoveRegistryNodeTool — same smooth imperative drag for shelf, spawn, and every future kind. Legacy per-kind movers below run only for kinds not yet in the registry. This is exactly how the Phase 5 progressive consolidation works: as kinds migrate to the registry, their legacy movers stop being reached and can be deleted. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/tools/item/move-tool.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/editor/src/components/tools/item/move-tool.tsx b/packages/editor/src/components/tools/item/move-tool.tsx index 193df651..b7eddca1 100644 --- a/packages/editor/src/components/tools/item/move-tool.tsx +++ b/packages/editor/src/components/tools/item/move-tool.tsx @@ -102,6 +102,17 @@ export const MoveTool: React.FC<{ const movingNode = useEditor((state) => state.movingNode) if (!movingNode) return null + + // Registry-first dispatch. Any kind registered via @pascal-app/nodes + // gets the imperative MoveRegistryNodeTool (smooth, framerate-locked + // motion via sceneRegistry — see plan: "Validated patterns from the + // spike"). The legacy per-kind movers below are short-circuited for + // any kind in the registry — that's how Phase 5 will progressively + // delete them as kinds migrate. + if (nodeRegistry.has(movingNode.type)) { + return + } + if (movingNode.type === 'building') return if (movingNode.type === 'door') return @@ -119,13 +130,5 @@ export const MoveTool: React.FC<{ return if (movingNode.type === 'stair' || movingNode.type === 'stair-segment') return - // Registry-driven kinds (any NodeDefinition with `capabilities.movable`) - // get a generic position+rotation mover. Phase 4 may consolidate this - // with the per-kind movers above when they all collapse to the same - // shape. Must come BEFORE the MoveItemContent fallback because that - // assumes the node is an ItemNode. - if (nodeRegistry.has(movingNode.type)) { - return - } return }