feat(editor): unify placement/move facing triangle into one editor-side renderer

Every placement and move path now publishes its ghost pose to a single
`useFacingPose` store, drawn by one editor-side `<FacingPoseIndicator>` overlay,
instead of each path drawing its own triangle (which left the nodes-package and
PlacementBox paths invisible):

- column/shelf presets + all moves (PlacementBox via move-registry, and
  DragBoundingBox) now publish the pose, so the triangle finally shows
- stair create + move use a declarative `facingIndicator: { reversed: true }`
  (new registry resolver) so the triangle sits before the entry pointing out —
  resolved in one place, so create and move match automatically
- stair placement defaults to single and respects the shared `point`
  continuation (C) toggle, like the other placement tools

Checkpoint on the placement-interaction epic: also carries the in-flight
continuation-profile extraction (lib/continuation), grid surface (item #8), and
HUD work. Door/window still render their own legacy inline triangle and are
migrated to the overlay next.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-06-26 21:48:58 -04:00
co-authored by Claude Opus 4.8
parent 76089d85ea
commit 68e5c6ca67
47 changed files with 1285 additions and 505 deletions
+2 -2
View File
@@ -500,7 +500,7 @@ export const FenceTool: React.FC = () => {
// While drafting, the segment locks to 15° rays from its start.
// Snapping is governed by the snapping mode (`'off'` is the bypass);
// there is no Shift hold-to-bypass. Alignment follows the magnetic snap
// mode, not Alt (Alt-tap toggles continuous/single chaining).
// mode, not Alt (continuation is cycled through the HUD / C).
const bypassAlign = !isMagneticSnapActive()
if (buildingState.current === 1) {
@@ -614,7 +614,7 @@ export const FenceTool: React.FC = () => {
// Single mode commits one segment per click: stop drafting so the next
// click starts a fresh segment instead of chaining off this endpoint.
if (useEditor.getState().fenceChainMode === 'single') {
if (useEditor.getState().getContinuation('fence') === 'single') {
stopDrafting()
return
}