The last two hot per-pointer-move 2D states still lived in FloorplanPanel's
useState, re-rendering the ~10k-line panel on every move:
- marquee (box-select): the whole drag struct moves to a dedicated
use-floorplan-marquee store; down/move/up/cancel read+write it via
getState() (panel holds nothing), and a FloorplanMarqueeOverlay leaf
subscribes to the moving corner and renders the rect alone. Drops the 3
bounds memos + the useState.
- reference-scale: the rubber-band's moving end was always equal to the
shared cursorPoint (written every move anyway), so drop the `cursor` field
from the draft and read it from useFloorplanDraftPreview in a new
FloorplanReferenceScaleDraftLine leaf. The draft now carries only the
per-click guide + start anchor, so it no longer re-renders the panel.
Closes out the 2D edition perf pass — every build/edit/select hot path now
writes a store, not panel state.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>