Skip to Content
HooksuseViewerAnimations

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

NameTypeDescription
clipsstring[]Animation clip names found in the model file
currentClipstring | nullThe clip played most recently, while it’s active, or null
isPlayingbooleantrue while any clip is playing (not paused, finished, or stopped)
speednumberPlayback speed of currentClip (default 1)
timenumberLive playback position of currentClip in seconds (updates while playing)
durationnumberLength of currentClip in seconds
activeAnimationClipState[]Every active clip (playing, paused, or finished) with its status, time, duration, speed, and reverse, most recently played last
play(clipName: string, options?: AnimationPlayOptions) => voidStarts 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) => voidPauses one clip, or every active clip
stop(clipName?: string) => voidStops one clip, or every active clip, and resets the pose
setSpeed(speed: number, clipName?: string) => voidChanges the speed of one clip, or of every active clip and those played later without their own
seek(time: number, clipName?: string) => voidScrubs 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) => voidCallback 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.