@threlte/extras
Version:
Utilities, abstractions and plugins for your Threlte apps
61 lines (60 loc) • 2.05 kB
JavaScript
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)
};
}