threlte logo
@threlte/extras

useGltfAnimations

Convenience hook to use animations loaded with a <GLTF> Threlte component or 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()
  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

Basic

<script lang="ts">
  import { GLTF, useGltfAnimations } from '@threlte/extras'
  // `useGltfAnimations` returns stores that populate
  // when the `<GLTF>` component finished loading.
  const { gltf, actions, mixer } = useGltfAnimations<'All Animations'>()

  // Play them whenever you need
  export const triggerAnimation = () => {
    if ($mixer) {
      $mixer.timeScale = 0.5
    }
    $actions['All Animations']?.play()
  }
</script>

<!-- Bind the store `gltf` -->
<GLTF
  url="/Bengal.glb"
  bind:gltf={$gltf}
/>

Using the useGltf Hook

Sometimes you might want to use the hook useGltf to reuse parts of a model or use the embedded camera. In this case, the hook useGltf returns an object with a property gltf which you can pass as the first argument to the hook useGltfAnimations.

<script lang="ts">
  import { T } from '@threlte/core'
  import { useGltfAnimations, useGltf } from '@threlte/extras'

  // In this example, the useGltf hook returns a Writable<THREE.GLTF> store
  const gltf = useGltf('/path/to/model.glb')

  // Provide that store to the hook useGltfAnimations
  const { actions, mixer } = useGltfAnimations<'All Animations'>(gltf)

  // play the animation as soon as it's loaded
  $effect(() => {
    $actions['All Animations']?.play()
  })
</script>

{#await gltf then { scene }}
  <T is={scene} />
{/await}

Applying Animations to a Different Root

Sometimes you want to apply the animations to a root other than the GLTF scene. In this case, pass the root as the second argument.

<script>
  import { useGltfAnimations, useGltf } from '@threlte/extras'
  import { Group } from 'three'

  const gltf = useGltf('/path/to/model.glb')

  const group = new Group()

  const { root } = useGltfAnimations(gltf, group)
</script>

{#await gltf then { scene }}
  <T is={group}>
    <T is={scene} />
  </T>
{/await}

This can also be done after the animations have been loaded. In this case, you can use the bind:ref directive to bind the root to the root store returned by the hook.

<script>
  import { useGltfAnimations, useGltf } from '@threlte/extras'
  import { Group } from 'three'

  const gltf = useGltf('/path/to/model.glb')

  const { root } = useGltfAnimations(gltf, group)
</script>

{#await gltf then { scene }}
  <T.Group bind:ref={$root}>
    <T is={scene} />
  </T.Group>
{/await}

Types

const {
  gltf, // Writable<GLTF | undefined>
  mixer, // AnimationMixer
  actions, // CurrentWritable<Record<string, AnimationAction>>
  root // CurrentWritable<Root | undefined>
} = useGLtfAnimations()