Overview
Threadbox provides a powerful animation system that supports both custom animations (movement, rotation, scaling) and built-in model animations from GLTF/GLB files. The AnimationManager handles animation queues, timelines, and smooth interpolation.
AnimationManager
Every object added to Threebox is automatically enrolled in the AnimationManager, which provides animation capabilities:
const soldier = await tb . loadObj ({
obj: '/models/soldier.glb' ,
type: 'gltf' ,
scale: 1 ,
units: 'meters'
});
// Object is automatically enrolled and ready for animations
soldier . setCoords ([ - 122.4194 , 37.7749 ]);
tb . add ( soldier );
Custom Animations
Movement Animation
Animate object position changes with smooth interpolation:
// Animate to new coordinates over 2 seconds
soldier . set ({
coords: [ - 122.4200 , 37.7750 , 10 ], // lng, lat, altitude
duration: 2000 // milliseconds
});
Rotation Animation
Animate object rotation:
// Rotate 90 degrees on Z-axis over 1 second
soldier . set ({
rotation: { x: 0 , y: 0 , z: 90 },
duration: 1000
});
Scale Animation
Animate object scaling:
// Scale to 2x size over 1.5 seconds
soldier . set ({
scale: { x: 2 , y: 2 , z: 2 },
duration: 1500
});
Combined Animations
Combine multiple animation properties:
soldier . set ({
coords: [ - 122.4200 , 37.7750 , 20 ],
rotation: { x: 0 , y: 0 , z: 180 },
scale: { x: 1.5 , y: 1.5 , z: 1.5 },
duration: 3000
});
Path Following
Animate objects along a path with automatic heading:
const path = [
[ - 122.4194 , 37.7749 , 0 ],
[ - 122.4200 , 37.7750 , 5 ],
[ - 122.4210 , 37.7755 , 10 ],
[ - 122.4220 , 37.7760 , 5 ]
];
soldier . followPath ({
path: path ,
duration: 5000 ,
trackHeading: true // Automatically rotate to face direction of movement
}, () => {
console . log ( 'Animation complete!' );
});
The followPath method uses Catmull-Rom spline interpolation for smooth curves.
Model Animations (GLTF/GLB)
Playing Default Animation
Many GLTF/GLB models include built-in animations. Threebox automatically detects and manages them:
tb . loadObj ({
obj: '/models/character.glb' ,
type: 'gltf' ,
units: 'meters' ,
defaultAnimation: 0 // Index of animation to play by default
}, ( model ) => {
model . setCoords ( origin );
tb . add ( model );
// Play default animation
model . playDefault ({
duration: 0 , // 0 = loop indefinitely
speed: 1.0 // Playback speed multiplier
});
});
Playing Specific Animation
// Play animation by index
model . playAnimation ({
animation: 2 , // Animation index
duration: 5000 ,
speed: 1.5
});
Animation Control Methods
Stop
Pause
Resume
Deactivate
Activate
// Stop all animations
model . stop ();
Idle Frame
Advance animation by one tick (useful for initialization):
Animation Events
Listen to animation state changes:
model . addEventListener ( 'IsPlayingChanged' , ( e ) => {
const isPlaying = e . detail . isPlaying ;
console . log ( 'Animation playing:' , isPlaying );
// Update UI, trigger other animations, etc.
if ( isPlaying ) {
playButton . textContent = 'Pause' ;
} else {
playButton . textContent = 'Play' ;
}
}, false );
Animation Properties
isPlaying
Check if model animations are currently playing:
if ( model . isPlaying ) {
console . log ( 'Model is animating' );
}
Animation Mixer
Access the underlying Three.js AnimationMixer for advanced control:
if ( model . mixer ) {
// Access mixer directly
model . mixer . timeScale = 2.0 ; // Double speed
}
Animation Actions
Access individual animation actions:
if ( model . actions && model . actions . length > 0 ) {
const firstAction = model . actions [ 0 ];
firstAction . setEffectiveWeight ( 0.5 ); // Blend weight
}
Instant State Changes
Set object state immediately without animation:
// Set rotation instantly (duration = 0)
soldier . setRotation ({ x: 0 , y: 0 , z: 90 });
// Or use set() with duration 0
soldier . set ({
coords: [ - 122.4200 , 37.7750 ],
rotation: { x: 0 , y: 0 , z: 45 },
duration: 0 // Immediate change
});
Animation Queue
Threadbox maintains an animation queue for each object. Animations are executed sequentially:
// First animation
soldier . set ({ coords: [ - 122.420 , 37.775 ], duration: 2000 });
// Second animation (starts after first completes)
soldier . set ({ rotation: { z: 90 }, duration: 1000 });
// Third animation
soldier . set ({ scale: { x: 2 , y: 2 , z: 2 }, duration: 1500 });
Callbacks
Execute code when animations complete:
soldier . followPath ({
path: pathCoordinates ,
duration: 3000
}, () => {
console . log ( 'Reached destination!' );
// Start another animation
soldier . playAnimation ({
animation: 1 ,
duration: 2000
});
});
Optimize Animations
Use duration: 0 for instant state changes when animation isn’t needed
Stop animations when objects are off-screen
Use model.mixer.timeScale to globally control animation speed
Dispose of objects properly with model.dispose() to clean up animation resources
Complete Example
map . on ( 'load' , () => {
const tb = new Threebox ( map , map . getCanvas (). getContext ( 'webgl' ), {
defaultLights: true
});
map . addLayer ({
id: 'custom-layer' ,
type: 'custom' ,
renderingMode: '3d' ,
onAdd : function ( map , gl ) {
const origin = [ - 122.4194 , 37.7749 , 0 ];
tb . loadObj ({
obj: '/models/soldier.glb' ,
type: 'gltf' ,
scale: 3 ,
units: 'meters' ,
rotation: { x: 90 , y: 0 , z: 0 },
defaultAnimation: 0
}, ( model ) => {
model . setCoords ( origin );
tb . add ( model );
// Listen for animation events
model . addEventListener ( 'IsPlayingChanged' , ( e ) => {
console . log ( 'Playing:' , e . detail . isPlaying );
});
// Define patrol path
const path = [
origin ,
[ - 122.4200 , 37.7750 , 0 ],
[ - 122.4210 , 37.7755 , 0 ],
origin
];
// Start patrol with model animation
model . playDefault ({ duration: 0 , speed: 1.0 });
model . followPath ({
path: path ,
duration: 10000 ,
trackHeading: true
}, () => {
console . log ( 'Patrol complete' );
});
});
},
render : function ( gl , matrix ) {
tb . update ();
}
});
});
See Also