feat(bake): bake catalog item clips (fan spin) into the GLB + play in viewer
A catalog GLB ships its own animation clips (a ceiling fan's spin), but those clips aren't in the editor scene graph, so the bake couldn't see them. Add an `itemClipRegistry` (core, type-only three) that the item renderer fills with the resolved clip per node while the scene is live; the GLB export reads it and re-emits each item's clip onto the baked subtree, rebinding tracks to the cloned spinning node's uuid. Catalog node names repeat across instances and the glTF roundtrip rebinds by name, so the targeted node is uniquified per item (`<id>__lamp_018`) — every fan animates independently. The baked viewer plays these as looping ambient motion: `<id>: loop` clips are set to LoopRepeat (not the door/window LoopOnce) and GlbItemAnimation drives them off each item's toggle (lit/spinning by default). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d80ffd67d5
commit
0514ec1858
@@ -8,6 +8,7 @@ import {
|
||||
type Interactive,
|
||||
type ItemNode,
|
||||
isSlotMaterialName,
|
||||
itemClipRegistry,
|
||||
LIBRARY_MATERIAL_REF_PREFIX,
|
||||
type LightEffect,
|
||||
SCENE_MATERIAL_REF_PREFIX,
|
||||
@@ -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 (
|
||||
|
||||
Reference in New Issue
Block a user