feat(editor): precise item dimensions — static bounding boxes, placement-math, remove item-mesh-metadata system

- Replace runtime mesh-based bounding-box computation with static dimension-based polygons for item footprints
- Add snapUpToGridStep() and getGridAlignedDimensions() to placement-math for grid-cell-aligned placement wireframes
- Add expandBoundsToGrid() to use-placement-coordinator for consistent wireframe snapping
- Add currentCursorRotationY to PlacementContext; preserve world orientation across item-surface transitions
- Fix item detach from surface: use worldToBuildingLocal() instead of event.localPosition to avoid coordinate-space jump
- Subscribe to useLiveTransforms in FloorplanPanel during placement so R/T keyboard rotation refreshes the 2D overlay immediately
- Fix FloorplanItemImage rotation (+180° to account for top-down camera capture orientation)
- Simplify spatial-grid-manager: single dimension-based getItemLocalBounds(), removes runtime mesh-metadata path
- Remove item-mesh-metadata system (compute-item-mesh-metadata, item-mesh-metadata-system, sync-request)
This commit is contained in:
Pascal
2026-05-04 19:35:41 +00:00
parent fa38b4af76
commit 1002a0a980
13 changed files with 215 additions and 737 deletions
@@ -21,10 +21,6 @@ import { useNodeEvents } from '../../../hooks/use-node-events'
import { resolveCdnUrl } from '../../../lib/asset-url'
import { baseMaterial, glassMaterial } from '../../../lib/materials'
import { useItemLightPool } from '../../../store/use-item-light-pool'
import {
requestItemMeshMetadataSync,
setItemMeshMetadataSourceRoot,
} from '../../../systems/item-mesh-metadata/sync-request'
import { ErrorBoundary } from '../../error-boundary'
import { NodeRenderer } from '../node-renderer'
@@ -110,19 +106,6 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
useScene.getState().dirtyNodes.add(node.parentId as AnyNodeId)
}, [node.parentId])
// Re-sync when GLTF `scene` or external `metadata` edits should invalidate cached footprint/bounds.
// biome-ignore lint/correctness/useExhaustiveDependencies: intentional — asset load and metadata drive mesh-metadata sync
useEffect(() => {
const cloneRoot = ref.current
if (!cloneRoot) return
setItemMeshMetadataSourceRoot(node.id, cloneRoot)
requestItemMeshMetadataSync(node.id)
return () => {
setItemMeshMetadataSourceRoot(node.id, null)
}
}, [node.id, node.metadata, scene])
useEffect(() => {
const interactive = interactiveRef.current
if (!interactive) return
@@ -11,7 +11,6 @@ import { FenceSystem } from '../../systems/fence/fence-system'
import { GuideSystem } from '../../systems/guide/guide-system'
import { ItemSystem } from '../../systems/item/item-system'
import { ItemLightSystem } from '../../systems/item-light/item-light-system'
import { ItemMeshMetadataSystem } from '../../systems/item-mesh-metadata/item-mesh-metadata-system'
import { LevelSystem } from '../../systems/level/level-system'
import { RoofSystem } from '../../systems/roof/roof-system'
import { ScanSystem } from '../../systems/scan/scan-system'
@@ -239,7 +238,6 @@ const Viewer: React.FC<ViewerProps> = ({
{/* <DebugRenderer /> */}
<ItemLightSystem />
<ItemMeshMetadataSystem />
{selectionManager === 'default' && <SelectionManager />}
{perf && <PerfMonitor />}
{children}