* Add roof surface placement support for items
Items (e.g. solar panels) can now be placed on sloped roof surfaces.
The placement system computes euler rotation from the roof surface
normal so items sit flush on the slope instead of going inside.
- Add roofStrategy to placement-strategies with enter/move/click/leave
- Wire roof:enter/move/click/leave events in the placement coordinator
- Add calculateRoofRotation in placement-math using surface normals
- Support full 3D cursor rotation for sloped surfaces
- Items on roofs are parented to the level with world-space rotation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fixed conflict
* fix(editor): anchor floorplan cursor to snapped point
* fix(nodes): preview floorplan edits through live overrides
* feat(editor): add context-aware floorplan modes
* fix(nodes): render crisp wall selection hatching
* fix(editor): cap floorplan handles at extreme zoom
* fix(editor): keep zone labels upright after rotation
* refactor(editor): make referenced annotations registry-driven
* refactor(nodes): colocate contextual dimension builders
* fix(editor): use mode-driven angle snapping
* fix(nodes): use mode-driven move snapping
* chore(editor): update react scan tooling
* refactor(floorplan): streamline construction documentation
* refactor(floorplan): remove wall assembly roadmap
* fix(floorplan): migrate retired scene data
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Roof-segment edit/move ignored the active snap mode and showed no chip:
- add snapProfile:'structural' so a body-move resolves the no-angle polygon
context (grid/lines/off) like every other structural move;
- resize uses getSegmentGridStep() (0 outside grid mode = the "smooth" resize
that used to need a held Shift), dropping the captured gridSnapStep + Shift;
- move drops its Shift bypass;
- the affordance dispatcher opens a boundary reshape scope for the resize so
the snapping chip shows and the context resolves.
2D rotation handles now match the 3D gizmo across all six rotate affordances
(column / elevator / roof-segment / shelf / spawn / stair): a shared
rotateAffordanceDelta snaps to the 15° step unless Shift (free), the
dispatcher opens the same ROTATE_HANDLE_DRAG_LABEL handle-drag scope the 3D
gizmo uses so the contextual HUD shows the "Shift = rotate freely" hint, and
the live degree readout snaps to match the committed rotation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>