useViewerAnimations
Controls animation playback for supported GLB/GLTF, FBX, and USDZ models that contain embedded animations.
Usage
import { useViewerAnimations } from "@liveroom-tech/react-immersive";
const {
clips,
currentClip,
isPlaying,
speed,
time,
duration,
play,
pause,
stop,
setSpeed,
seek,
handleAnimationsReady,
} = useViewerAnimations();
<ModelViewer
onAnimationsReady={handleAnimationsReady}
...
/>Returns
| Name | Type | Description |
|---|---|---|
clips | string[] | Animation clip names found in the model file |
currentClip | string | null | The clip played most recently, while it’s active, or null |
isPlaying | boolean | true while any clip is playing (not paused, finished, or stopped) |
speed | number | Playback speed of currentClip (default 1) |
time | number | Live playback position of currentClip in seconds (updates while playing) |
duration | number | Length of currentClip in seconds |
active | AnimationClipState[] | Every active clip (playing, paused, or finished) with its status, time, duration, speed, and reverse, most recently played last |
play | (clipName: string, options?: AnimationPlayOptions) => void | Starts a clip, replacing those already playing unless alongside is set; fade blends over that many seconds, reverse plays it backwards. A paused clip resumes |
pause | (clipName?: string) => void | Pauses one clip, or every active clip |
stop | (clipName?: string) => void | Stops one clip, or every active clip, and resets the pose |
setSpeed | (speed: number, clipName?: string) => void | Changes the speed of one clip, or of every active clip and those played later without their own |
seek | (time: number, clipName?: string) => void | Scrubs one clip, or every active clip, to an absolute time in seconds (works while playing or paused), clamped to the clip length |
handleAnimationsReady | (controls: AnimationControls) => void | Callback to pass to onAnimationsReady |
Playback Controls Example
const { clips, currentClip, isPlaying, play, pause, stop, setSpeed } =
useViewerAnimations();
// Play/pause toggle
<button onClick={() => isPlaying ? pause() : play(currentClip ?? clips[0])}>
{isPlaying ? "Pause" : "Play"}
</button>
// Stop
<button onClick={() => stop()}>Stop</button>
// Speed slider
<input
type="range"
min="0.1"
max="3"
step="0.1"
defaultValue="1"
onChange={(e) => setSpeed(Number(e.target.value))}
/>
// Clip selector
{clips.map((name) => (
<button key={name} onClick={() => play(name)}>
{name} {currentClip === name && isPlaying ? "▶" : ""}
</button>
))}Playing Several Clips
Several clips can play at once. play replaces the clips already playing
unless you pass alongside: true, and the other controls act on one clip when
you name it, or on every active clip when you don’t:
const animations = useViewerAnimations();
// Open both doors together, then close the left one.
animations.play("DoorLeftOpen", { alongside: true });
animations.play("DoorRightOpen", { alongside: true });
animations.play("DoorLeftOpen", { alongside: true, reverse: true });
// Blend from walking to running over half a second.
animations.play("Run", { fade: 0.5 });
animations.pause("Wheels"); // one clip
animations.stop(); // every clip
// What's active, and how far along each clip is
animations.active.map(({ clip, status, time }) => `${clip}: ${status} at ${time}s`);A clip whose loopMode is "once" holds its last pose when it finishes
(status: "finished") until it’s stopped or played again, so an opened door
stays open. "ping-pong" plays forwards then backwards, repeatedly. Playing a
clip that’s already playing in the same direction leaves it running; playing
it the other way turns it around where it is.
onAnimationsReady is called even when the model has no animations, with an empty clips array and no-op control functions.