Three.js AnimationMixer Loop Event Tracking
In Three.js, tracking when an animation cycle completes and loops is
essential for synchronizing game logic, triggering audio, or chaining
character behaviors. This article explains how to listen for the
'loop' event dispatched by the AnimationMixer,
identify which specific animation action triggered the event, and
implement this logic efficiently in your JavaScript code.
Listening to the Loop Event
The AnimationMixer dispatches a 'loop'
event every time an individual animation action finishes a single loop
cycle. To track this event, you must add an event listener directly to
your AnimationMixer instance.
Here is the basic implementation:
// Initialize your mixer and actions
const mixer = new THREE.AnimationMixer(characterMesh);
const walkAction = mixer.clipAction(walkClip);
const runAction = mixer.clipAction(runClip);
// Play the animations
walkAction.play();
runAction.play();
// Add the event listener to the mixer
mixer.addEventListener('loop', (event) => {
// Identify which specific animation looped
if (event.action === walkAction) {
console.log('Walk animation completed a cycle.');
} else if (event.action === runAction) {
console.log('Run animation completed a cycle.');
}
});Understanding the Event Object
When the 'loop' event listener is triggered, it passes
an event object to the callback function. This object contains crucial
properties that allow you to determine exactly what occurred:
event.type: A string representing the event name ('loop').event.action: The specificAnimationActioninstance that completed its loop. Comparing this directly against your stored actions (e.g.,event.action === walkAction) is the most reliable way to target specific animations.event.loopDelta: The execution time delta since the loop actually happened, which is useful for precise timing calculations.
Managing Loop Settings
For the 'loop' event to trigger repeatedly, the action’s
loop mode must be set to repeat. By default, Three.js actions are
configured to loop indefinitely. You can control this behavior using the
setLoop method:
// Set action to loop a specific number of times
walkAction.setLoop(THREE.LoopRepeat, 3); // Loops 3 times, then stops
// Set action to loop infinitely (default behavior)
runAction.setLoop(THREE.LoopRepeat, Infinity);If you need to detect when an animation finishes completely and stops
playing (rather than looping), you should listen for the
'finished' event instead of 'loop':
mixer.addEventListener('finished', (event) => {
console.log('Animation action has finished playing:', event.action);
});