Anime.js provides powerful composition controls for combining multiple animations on the same properties.
Composition Modes
Control how new animations interact with existing ones.
Replace (Default)
New animations override previous ones:
import { animate } from 'animejs' ;
// First animation
animate ( '.box' , {
translateX: 100 ,
duration: 1000
});
// This replaces the previous animation
animate ( '.box' , {
translateX: 200 ,
composition: 'replace' , // default
duration: 1000
});
The first animation is automatically cancelled when the second starts.
Blend (Additive)
Animations accumulate on top of each other:
// Base animation
animate ( '.box' , {
translateX: 100 ,
composition: 'replace' ,
duration: 2000
});
// This adds to the base
animate ( '.box' , {
translateX: 50 ,
composition: 'blend' ,
duration: 1000 ,
loop: true ,
alternate: true
});
// Result: oscillates between 100px and 150px
None
No composition - animations run independently:
animate ( '.box' , {
translateX: 100 ,
composition: 'none' ,
duration: 1000
});
animate ( '.box' , {
translateY: 100 ,
composition: 'none' ,
duration: 1000
});
Replace Composition
Replace mode intelligently handles overlapping animations.
Basic Override
const anim1 = animate ( '.box' , {
translateX: 100 ,
duration: 2000
});
// After 500ms, this replaces anim1
setTimeout (() => {
animate ( '.box' , {
translateX: 200 ,
composition: 'replace' ,
duration: 1000
});
}, 500 );
Partial Overlap
Only overlapping portions are replaced:
// Animates 0-100 over 2s
animate ( '.box' , {
translateX: 100 ,
duration: 2000
});
// After 1s, takes over
setTimeout (() => {
animate ( '.box' , {
translateX: 200 ,
duration: 1000
});
}, 1000 );
// First animation plays for 1s, then second takes over
Multiple Properties
animate ( '.box' , {
translateX: 100 ,
translateY: 100 ,
duration: 2000 ,
composition: 'replace'
});
// Only replaces translateX
animate ( '.box' , {
translateX: 200 ,
duration: 1000 ,
composition: 'replace'
});
// translateY continues unaffected
Blend Composition
Create complex effects by layering animations.
Oscillating Effect
// Base movement
animate ( '.box' , {
translateX: 300 ,
duration: 3000 ,
ease: 'out(2)'
});
// Add wobble
animate ( '.box' , {
translateX: 20 ,
composition: 'blend' ,
duration: 300 ,
loop: true ,
alternate: true ,
ease: 'inOut(2)'
});
Breathing Effect
// Main scale animation
animate ( '.element' , {
scale: 1.5 ,
duration: 2000
});
// Add subtle pulse
animate ( '.element' , {
scale: 0.05 ,
composition: 'blend' ,
duration: 800 ,
loop: true ,
alternate: true
});
Multi-layer Animation
const box = '.box' ;
// Layer 1: Main movement
animate ( box , {
translateX: 400 ,
composition: 'replace' ,
duration: 4000
});
// Layer 2: Vertical bounce
animate ( box , {
translateY: - 50 ,
composition: 'blend' ,
duration: 500 ,
loop: true ,
alternate: true
});
// Layer 3: Rotation
animate ( box , {
rotate: 10 ,
composition: 'blend' ,
duration: 800 ,
loop: true ,
alternate: true
});
Timeline Composition
Composition works within timelines:
import { timeline } from 'animejs' ;
const tl = timeline ({
composition: 'blend' // Default for all children
});
tl . add ( '.box' , {
translateX: 100 ,
duration: 1000
});
tl . add ( '.box' , {
translateY: 100 ,
composition: 'replace' , // Override default
duration: 1000
});
Per-Property Composition
animate ( '.box' , {
translateX: {
to: 100 ,
composition: 'replace'
},
translateY: {
to: 50 ,
composition: 'blend'
},
duration: 1000
});
Composition with WAAPI
WAAPI supports composition modes:
import { waapi } from 'animejs' ;
waapi . animate ( '.box' , {
translateX: 100 ,
composition: 'replace' , // 'replace' | 'add' | 'accumulate'
duration: 1000
});
WAAPI composition maps to native Web Animations API composite modes.
Advanced Patterns
Controlled Layering
import { animate } from 'animejs' ;
class AnimationController {
constructor ( target ) {
this . target = target ;
this . layers = [];
}
addLayer ( props ) {
const anim = animate ( this . target , {
... props ,
composition: 'blend'
});
this . layers . push ( anim );
return anim ;
}
clearLayers () {
this . layers . forEach ( anim => anim . cancel ());
this . layers = [];
}
}
const controller = new AnimationController ( '.box' );
controller . addLayer ({ translateX: 100 , duration: 1000 });
controller . addLayer ({ translateY: 50 , duration: 500 , loop: true });
Dynamic Effects
function addWiggle ( element , intensity = 10 ) {
return animate ( element , {
translateX: [ - intensity , intensity ],
composition: 'blend' ,
duration: 100 ,
loop: true ,
alternate: true
});
}
// Use alongside other animations
animate ( '.box' , { translateY: 200 , duration: 2000 });
const wiggle = addWiggle ( '.box' , 15 );
// Remove wiggle later
setTimeout (() => wiggle . cancel (), 1000 );
// Base rotation
const baseRotation = animate ( '.card' , {
rotate: 360 ,
duration: 4000 ,
loop: true ,
ease: 'linear'
});
// Add tilt on hover
card . addEventListener ( 'mouseenter' , () => {
animate ( '.card' , {
rotateX: 10 ,
composition: 'blend' ,
duration: 300
});
});
card . addEventListener ( 'mouseleave' , () => {
animate ( '.card' , {
rotateX: 0 ,
composition: 'blend' ,
duration: 300
});
});
Composition Priority
Animations follow these composition rules:
Replace cancels overlapping animations on same properties
Blend creates additive layers that stack
None runs independently without interaction
Later animations take precedence when replacing
// Timeline
animate ( '.box' , { translateX: 100 , duration: 2000 });
// t=0s: starts
setTimeout (() => {
animate ( '.box' , { translateX: 200 , duration: 1000 });
// t=0.5s: replaces first animation
}, 500 );
setTimeout (() => {
animate ( '.box' , {
translateX: 50 ,
composition: 'blend' ,
duration: 500 ,
loop: true
});
// t=1s: adds oscillation on top
}, 1000 );
Best Practices
Use Replace for User Actions
Replace is best for responding to user input: button . addEventListener ( 'click' , () => {
animate ( '.panel' , {
translateX: 300 ,
composition: 'replace' ,
duration: 400
});
});
Blend is ideal for adding effects to existing animations: // Main animation
animate ( '.box' , { translateX: 500 , duration: 3000 });
// Add shake effect
animate ( '.box' , {
translateY: 5 ,
composition: 'blend' ,
duration: 100 ,
loop: 5 ,
alternate: true
});
Clean Up Blend Animations
Remember to cancel blend animations when no longer needed: const effect = animate ( '.box' , {
rotate: 5 ,
composition: 'blend' ,
duration: 200 ,
loop: true
});
// Clean up
setTimeout (() => effect . cancel (), 2000 );
Too many blend animations can impact performance: // Good: 2-3 layers
animate ( el , { translateX: 100 });
animate ( el , { translateY: 10 , composition: 'blend' });
// Avoid: 10+ layers
Replace : Most efficient, cancels previous animations
Blend : Adds overhead, each layer is calculated
None : Minimal overhead but may cause conflicts
For best performance, use replace mode for primary animations and blend sparingly for effects.
Debugging
View active animations:
import { getActiveAnimations } from 'animejs' ;
// Log all active animations
const active = getActiveAnimations ();
console . log ( 'Active animations:' , active . length );
active . forEach ( anim => {
console . log ( anim . targets , anim . composition );
});