Phase 5 Stage D fence: port MoveFenceTool to DragAction (whole-fence move)

Third Stage D affordance port (302 LoC legacy → action + thin wrapper).

The action (`actions/move.ts`) uses the live-drag exception documented
in editor/wiki/architecture/tools.md: visual-only updates via
`sceneRegistry.nodes.get(id).position` + `useLiveTransforms` during
the drag, no scene mutations. Avoids re-rebuilding the fence geometry
(many posts + infill panels) every pointer tick. Commit performs the
single-undo dance — writes final start/end to scene, geometry rebuilds
once, Ctrl-Z reverses the whole drag.

Linked-fence cascade follows the same shape as MoveFenceEndpoint —
any fence in the same parent that shared an endpoint at activation
moves with the drag.

`getRegistryAffordanceTool` extracted to
`tools/shared/affordance-dispatch.ts` so move-tool.tsx and
tool-manager.tsx share the lazy-load helper (no duplicate caches).

MoveTool dispatch gains a generic `affordanceTools.move` check after
the capability-driven `movable` shortcut — fence routes through here;
wall / slab / etc. fall through to their legacy per-kind chain until
their D ports land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-05-15 18:19:51 -04:00
co-authored by Claude Opus 4.7
parent 36c48b7fc9
commit c16878c876
6 changed files with 383 additions and 20 deletions
+7
View File
@@ -80,6 +80,13 @@ export const fenceDefinition: NodeDefinition<typeof FenceNode> = {
// actions/move-endpoint.ts (linked-fence cascade, alt-detach,
// single-undo dance). Wrapper owns the angle label + detach badge.
'move-endpoint': () => import('./move-endpoint-tool'),
// Triggered by useEditor.movingNode when the moving node is a
// fence. Whole-fence rigid translation with linked-fence cascade.
// Pure logic in actions/move.ts uses the live-drag exception
// (mesh.position + useLiveTransforms) to avoid rebuilding fence
// geometry every pointer tick; commits the final start/end with
// the single-undo dance.
move: () => import('./move-tool'),
},
toolHints: [