* fix(viewer): tune shadow biases to stop acne without detaching shadows
normalBias 0.02 was too small a texel offset for the building-fit 1024
shadow map and brought back self-shadowing acne. Settle on normalBias 0.08
(0.07 and below acnes, 0.1 reads detached) plus depth bias -0.0005 to
suppress the residual acne that a normal bias alone couldn't clear.
Also adds a `?debug=shadowcamera` diagnostic that draws a CameraHelper for
each shadow camera so the fitted frustum can be inspected while tuning.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(editor): polygon editor handle UX — focus, cursors, visibility
- vertex/midpoint cylinders ignore scene depth like the edge arrows so
they stay visible through walls and slabs; vertex radius 0.1 -> 0.08,
midpoint 0.06 -> 0.05, midpoints use the brighter arrow shade at rest
- during any drag only the active handle stays mounted (other arrows,
vertices, edge bars and the cross disappear) so the gesture reads clearly
- handles set pointer cursors: move for vertices/midpoints/cross, and a
screen-space direction-aware resize cursor for the edge arrows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(editor): keep ceiling affordances quiet during any interaction
The ceiling corner brackets' hit boxes caught drag-time hover (spatial
events keep firing during host drags by design), set hoveredId to the
ceiling and flashed the ceiling grid mid-gesture — e.g. while dragging a
slab polygon vertex. Unmount the brackets while ANY interaction scope is
active, and gate CeilingSystem's hover-driven grid reveal on idle scope +
no inputDragging as a second layer.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(core): stop room detection resurrecting deleted slabs on load
Two holes in the wall-driven auto slab sync:
- initSpaceDetectionSync started with an empty baseline, so scene
hydration (one atomic setScene) read as 'every wall changed' and ran a
full detection pass on every load, recreating auto slabs the user had
deleted. Seed the baseline from the store at init and treat a level's
first snapshot as baseline — detection now only reacts to in-session
wall edits.
- matchesManualFootprint required mutual coverage, so a single manual
slab spanning multiple rooms never suppressed those rooms' auto slabs
(only a fraction of it lies inside each room). Suppression now only
asks whether the ROOM is substantially covered by the union of manual
slabs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>