Fix pass over 2D reference-image (guide) handling plus two adjacent repairs:
- North is now world −Z (FLOORPLAN_VIEW_ROTATION_DEG 90 → 0, mirrored in
world-grid-snap + mcp README; floorplan-panel de-dupes its local copy).
A rotation-0 north-up scan reads upright when the compass says aligned,
and "align north" maps to camera azimuth 0 instead of a 90° jump.
- Guide resize cursor: custom double-arrow cursor aimed at the dragged
corner in screen space — accounts for image aspect (was atan2(±1,±1),
square-only), the guide's own rotation, and the floorplan view rotation
the overlay group renders inside (was ignored entirely).
- R/T rotate a selected reference (guide/scan) in ±45° steps; references
live in selectedReferenceId, not the viewer selection, so both arms get
the reference-first branch the Delete arm already had. Locked guides skip.
- 2D-only mode hides the Top View button (drives the display:none 3D
camera); orbit stays — it spins the synced floorplan view.
- Set Scale UX: locked guides stay clickable (calibration auto-lock made
them unselectable until reload); starting the flow from 3D switches to
2D; the length input pre-fills the drawn length in the pre-selected unit
(imperial pre-filled meters labeled feet); Set Scale flips into Cancel
while the flow runs (mirrored via referenceScaleActiveGuideId); Hide/
Clear Scale only render once calibrated; Escape cancels (global arm +
dialog); Clear Scale and Replace Image drop the calibration auto-lock;
discoverability: corner-hint row + panel nudge for uncalibrated guides.
- healSceneNodes: strip child refs whose child's parentId names another
parent (stale reparent leftovers rendered a window twice — duplicate
React keys in 2D, doubled hosted geometry in 3D) and same-array dupes.
- Editor accepts onLoaderChange so hosts can measure open-to-interactive
time (community wires it to a PostHog timing event).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>