Merge origin/main into feat/placement-interaction-overhaul

Resolve 7 conflicts keeping our snapping migration + floorplan perf work as
source of truth, combined with main's MEP run-continuation / Alt-detach /
latch handles. Rebuilt two import blocks the auto-merge silently truncated
(node-arrow-handles.tsx, duct-fitting/move-tool.tsx).

Verified: tsc clean across core/viewer/editor/nodes/mcp, 451 tests pass,
biome clean. Floorplan view-transform re-render storm confirmed pre-existing
(not introduced by this merge).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-06-28 16:22:47 -04:00
co-authored by Claude Opus 4.8
171 changed files with 19294 additions and 2224 deletions
+16 -1
View File
@@ -8,6 +8,7 @@ import {
type Interactive,
type ItemNode,
isSlotMaterialName,
itemClipRegistry,
LIBRARY_MATERIAL_REF_PREFIX,
type LightEffect,
SCENE_MATERIAL_REF_PREFIX,
@@ -379,7 +380,7 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
mesh.castShadow = !hasGlass
mesh.receiveShadow = !hasGlass
}
}, [ref, scene, shading, textures, colorPreset, node.slots, sceneMaterials])
}, [shading, textures, colorPreset, node.slots, sceneMaterials])
const interactive = interactiveRef.current
const animEffect =
@@ -387,6 +388,20 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
const lightEffects =
interactive?.effects.filter((e): e is LightEffect => e.kind === 'light') ?? []
// Expose this item's ambient clip (e.g. a fan's spin) to the GLB bake. The
// catalog GLB owns the clip; it isn't in the scene graph, so the export can't
// find it without this registry. The bake retargets it onto the baked subtree.
useEffect(() => {
if (!animEffect) return
const clipName = animEffect.clips.on ?? animEffect.clips.loop
const clip = clipName ? animations.find((c) => c.name === clipName) : undefined
if (!clip) return
itemClipRegistry.set(node.id, { clip, loop: true })
return () => {
itemClipRegistry.delete(node.id)
}
}, [node.id, animEffect, animations])
// useGLTF caches scenes, and Clone shares child geometry/material references.
// Undo can unmount one item while another clone of the same asset still needs them.
return (