Doors and windows could only be moved via the floating action menu — their
3D handle rig declared width/height resize arrows but no move grip, and
Ctrl/Meta-drag was a no-op for them. Add a press-drag move cross and make
direct-drag work for every bespoke-mover kind.
- door/window: add a `tap-action` `move-cross` handle (plane node-normal,
portal grandparent, `engageMoveDrag`) mirroring the item wall grip. It
routes through the existing per-kind move tool (3D `affordanceTools.move`,
2D `floorplanMoveTarget`) — wall-bound slide + re-host onto another wall —
so the grip, the floating Move button, and the 2D plan's move dot share one
pipeline. Grab-drag-release commits without a second click.
- canDirectMoveNode: gate Ctrl/Meta-drag on `movable || affordanceTools.move`
(the 3D-mountable move paths) instead of `movable` only, so doors/windows/
walls/slabs/stairs/… are draggable in 3D as they already are in 2D.
Floorplan-only movers (zone) stay excluded — no 3D tool mounts. The
floating helper auto-syncs (it reads canDirectMoveNode).
- TapActionArrow: honor `plane: 'node-normal'` by tilting the move cross
[π/2,0,0] into the wall face — previously ignored, so the item wall grip
rendered flat too. Now door/window/wall-item crosses lie in the wall.
- use-node-events: split the drag-suppression gate. `inputDragging` still
suppresses SELECTION events (the synthesized release-click would re-select),
but no longer suppresses SPATIAL events (enter/move/leave) — a
surface-following move tool runs with `inputDragging` set and needs
wall:move to track the cursor. General consumers that must ignore drags
(viewer hover, box-select) already self-gate on `inputDragging`; the
editor's select-hover and paint-preview enter handlers now gate on it too.
- handle-arrow: make handle hit areas inert while `placementDragMode` is set,
so a move grip riding the dragged node can't intercept the ray and starve
the move tool's surface raycast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>