UNPKG

@threlte/extras

Version:

Utilities, abstractions and plugins for your Threlte apps

61 lines (60 loc) 2.05 kB
import { useTask, isInstanceOf } from '@threlte/core'; import { fromStore, toStore } from 'svelte/store'; import { AnimationMixer, Object3D } from 'three'; const isStore = (value) => typeof value?.subscribe === 'function'; const isGetter = (value) => typeof value === 'function'; export function useGltfAnimations(gltf, root) { const gltfStore = isStore(gltf) ? fromStore(gltf) : undefined; let _gltf = $derived(isGetter(gltf) ? gltf() : gltfStore?.current); let _root = $derived(isInstanceOf(gltf, 'Object3D') ? gltf : isGetter(root) ? root() : undefined); const actualRoot = $derived(_root ?? _gltf?.scene); let actions = $state.raw({}); const mixer = new AnimationMixer(undefined); $effect(() => { if (!_gltf || _gltf.animations.length === 0 || !actualRoot) return; const newActions = {}; for (const clip of _gltf.animations) { const action = mixer.clipAction(clip, actualRoot); newActions[clip.name] = action; } actions = newActions; return () => { for (const action of Object.values(newActions)) { action.stop(); mixer.uncacheClip(action.getClip()); } }; }); useTask((delta) => { mixer.update(delta); }, { running: () => Object.keys(actions).length > 0 }); return { /** * @deprecated This property will be removed in Threlte 9 */ gltf: { ...toStore(() => _gltf), set(value) { _gltf = value; }, update(updater) { _gltf = updater(_gltf); } }, /** * @deprecated This property will be removed in Threlte 9 */ root: { ...toStore(() => _root), set(value) { _root = value; }, update(updater) { _root = updater(_root); } }, mixer, actions: toStore(() => actions) }; }