@threlte/extras
useGltfAnimations
A convenience hook to use gltf animations loaded by a <GLTF> component or by the useGltf hook.
<script lang="ts">
import Scene from './Scene.svelte'
import { Button, Folder, Pane } from 'svelte-tweakpane-ui'
import { Canvas } from '@threlte/core'
let scene = $state.raw<Scene>()
let animating = $state(false)
const actions = $derived(scene?.actions)
const action = $derived($actions?.['Take 001'])
// start animating as soon as the action is ready
$effect(() => {
action?.play()
animating = true
})
</script>
<Pane
position="fixed"
title="littlest tokyo"
>
<Folder title="animation">
<Button
disabled={animating}
on:click={() => {
action?.play()
animating = true
}}
title="play"
/>
<Button
disabled={!animating}
on:click={() => {
action?.stop()
animating = false
}}
title="stop"
/>
<Button
disabled={!animating}
on:click={() => {
action?.reset()
}}
title="reset"
/>
</Folder>
</Pane>
<div>
<Canvas>
<Scene bind:this={scene} />
</Canvas>
</div>
<style>
div {
height: 100%;
}
</style>
<script lang="ts">
import { Environment, OrbitControls, useDraco, useGltf, useGltfAnimations } from '@threlte/extras'
import { T } from '@threlte/core'
const dracoLoader = useDraco()
const gltf = useGltf('/models/LittlestTokyo.glb', { dracoLoader })
export const { actions, mixer } = useGltfAnimations<'Take 001'>(() => $gltf)
</script>
<T.PerspectiveCamera
makeDefault
position={[600, 200, -600]}
near={10}
far={10_000}
>
<OrbitControls
autoRotate
autoRotateSpeed={0.2}
enableDamping
enableZoom={false}
target={[-60, -75, 0]}
/>
</T.PerspectiveCamera>
<Environment
url="/textures/equirectangular/hdr/industrial_sunset_puresky_1k.hdr"
isBackground
/>
{#await gltf then { scene }}
<T is={scene} />
{/await}
Model: Littlest Tokyo by Glen Fox, CC Attribution.
Examples
useGltfAnimations takes the gltf as a getter so that reads are tracked through runes automatically. The hook returns the mixer and an actions store keyed by clip name — type the clip names with a generic to get autocompletion.
With the <GLTF> component
Bind a local $state variable to the <GLTF> component’s gltf prop and pass the getter to useGltfAnimations.
<script lang="ts">
import { GLTF, useGltfAnimations, type ThrelteGltf } from '@threlte/extras'
let gltf = $state<ThrelteGltf>()
const { actions, mixer } = useGltfAnimations<'All Animations'>(() => gltf)
mixer.timeScale = 0.5
$effect(() => {
$actions['All Animations']?.play()
})
</script>
<GLTF
url="/path/to/model.glb"
bind:gltf
/>
With the useGltf hook
When you want to reuse parts of the GLTF such as materials, nodes, or the embedded camera, load it with useGltf and pass the value through the getter.
<script lang="ts">
import { T } from '@threlte/core'
import { useGltfAnimations, useGltf } from '@threlte/extras'
const gltf = useGltf('/path/to/model.glb')
const { actions, mixer } = useGltfAnimations<'All Animations'>(() => $gltf)
$effect(() => {
$actions['All Animations']?.play()
})
</script>
{#await gltf then { scene }}
<T is={scene} />
{/await}
Applying Animations to a Different Root
useGltfAnimations’s second optional argument is a getter for an alternative root Object3D. Use this when you want to retarget the clips onto a separate rig rather than the gltf’s own scene.
<script lang="ts">
import { T } from '@threlte/core'
import { useGltfAnimations, useGltf } from '@threlte/extras'
import { Group } from 'three'
const gltf = useGltf('/path/to/model.glb')
const group = new Group()
const { actions } = useGltfAnimations(
() => $gltf,
() => group
)
</script>
{#await gltf then { scene }}
<T is={group}>
<T is={scene} />
</T>
{/await}