feat(editor): live floor-stacking, unified handle system, slab-hole editing + interaction polish (#375)

- Live slab-stacking Y previews for all floor-placed kinds (item/shelf/spawn/column/stair) during placement + both move pathways, via a shared core resolver; canonical positions unchanged.
- Unified 3D handle system (one drag pipeline + one visual primitive) with forgiving invisible hit-areas on every handle, kept on EDITOR_LAYER so they don't poison the MRT scene pass.
- Hover + click-to-edit slab holes in 3D (manual hole -> hole editor; stair/elevator hole -> select owner); generic cross-arrow polygon-move grip; normalized handle interaction colors.
- NaN-safe node mutations + non-finite shadow-light bounds guard.
- Built on #373 (level-scoped alignment / registry slab tool); #373 owns X/Z alignment, this owns Y floor-stacking.
This commit is contained in:
Aymeric Rabot
2026-06-05 16:24:48 -04:00
committed by GitHub
parent d1b40aa98d
commit 0b338cf647
51 changed files with 3942 additions and 1418 deletions
@@ -74,7 +74,10 @@ function floorFootprint(
): { dimensions: [number, number, number]; rotation: [number, number, number] } | null {
const capabilities = nodeRegistry.get(node.type)?.capabilities
const floorPlaced = capabilities?.floorPlaced
if (floorPlaced) {
// `footprint` is optional now that floor-placed kinds may instead declare
// composite `footprints` (e.g. stairs); those have no single centred box
// here, so fall through to `alignmentFootprint`.
if (floorPlaced?.footprint) {
if (floorPlaced.applies && !floorPlaced.applies(node)) return null
return floorPlaced.footprint(node)
}