How to Compose Multiple Animations on the Same Elements in Anime.js
Anime.js enables multiple tweens on the same element through three composition modes—replace (default), blend, and none—which determine whether animations override, add to, or ignore each other.
When building complex web animations, you often need to layer effects on a single element or property. The anime library (juliangarnier/anime) handles these overlapping timelines through a sophisticated animation composition system defined in src/core/consts.js. Understanding how to compose multiple animations allows you to create sophisticated interactions where motion effects mix additively or sequentially replace one another.
Understanding Animation Composition Types
Anime.js defines composition behavior in src/core/consts.js (lines 41–45) through three distinct modes:
replace(0): The default mode. New tweens override overlapping tweens on the same target and property. The previous animation is trimmed or cancelled so only one value applies at any given time.blend(2): New tweens add their delta to the current value using additive blending. All active tweens contribute to the final computed value.none(1): No composition handling. Tweens run independently, used internally for performance optimization on massive target sets.
The default replace mode matches the most common use case: later animations override earlier ones for the overlapped time range.
How Composition Works Internally
The composition system relies on three core modules that manage tween registration, storage, and rendering.
Tween Registration and Sibling Lists
When you create an animation, the composeTween function in src/animation/composition.js determines how the new tween interacts with existing ones. The system maintains lookup maps (lookups._rep for replace mode, lookups._add for blend mode) that store doubly-linked lists of sibling tweens per target/property.
The getTweenSiblings(target, property, lookup) function returns an object with _head and _tail pointers representing the chain of tweens affecting the same property. This structure enables O(1) insertion and removal without scanning every tween in the scene.
For replace mode, addChild inserts the tween sorted by start time using _prevRep and _nextRep pointers. When overlaps occur, overrideTween trims or cancels conflicting siblings. For blend mode, the system creates a lookup tween representing the accumulated base value and links additive tweens using _prevAdd and _nextAdd pointers.
Tween Creation and Storage
In src/animation/animation.js (lines 260–263 and 551–564), the library normalizes the composition option supplied by users and stores it on the tween instance as _composition. This flag determines which logic path the engine uses during the render loop.
The Render Loop
The rendering engine in src/core/render.js reads the _composition flag to determine value calculation. At lines 158–166, the engine detects the composition type, and at lines 231–236, it handles the special summation logic for blend mode. For replace, it uses the latest tween's computed value directly. For blend, it sums the contributions of every active tween (tween._fromNumber, tween._toNumber, etc.) before applying the final value to the DOM element.
This architecture ensures O(k) rendering cost, where k represents the number of active tweens on a specific property—typically a very low number in practice.
Practical Examples of Animation Composition
Replace Mode: Sequential Overrides
By default, Anime.js uses replace composition, allowing later animations to take precedence:
// First animation moves element 0→200px over 2s
anime({
targets: '.box',
translateX: 200,
duration: 2000
});
// Second animation starts at 1s, overriding translateX
anime({
targets: '.box',
translateX: 0,
duration: 2000,
delay: 1000
});
From 0–1 seconds, the box moves toward 200px. At the 1-second mark, the second tween takes over, bringing the element back to 0px while the first tween remains alive in the timeline but no longer controls the property.
Blend Mode: Additive Animations
To combine motion effects, use composition: 'blend':
// Base tween adds 100px to translateX
anime({
targets: '.ball',
translateX: 100,
duration: 3000,
composition: 'blend'
});
// Independent tween adds another 50px
anime({
targets: '.ball',
translateX: 50,
duration: 2000,
delay: 500,
composition: 'blend'
});
The ball ends up at 150px because both deltas sum together. If the second animation ends earlier, the ball continues at 100px from the remaining active tween. Both animations must specify blend mode to participate in additive composition.
Mixed Composition Strategies
You can apply different composition modes to different properties on the same element:
anime({
targets: '.star',
rotate: '1turn',
duration: 4000
});
anime({
targets: '.star',
scale: 2,
duration: 4000,
composition: 'blend',
delay: 1000
});
anime({
targets: '.star',
scale: 0.5,
duration: 2000,
composition: 'blend',
delay: 2000
});
Here, rotation follows replace semantics (default), while the two scale animations combine multiplicatively (2 × 0.5 = 1). The star completes one full rotation while scaling up then down to its original size.
Performance Considerations
The composition system in juliangarnier/anime is optimized for real-time performance. By maintaining doubly-linked lists per property via lookups._rep and lookups._add in src/animation/composition.js, the engine achieves constant-time insertion and removal. During the render loop in src/core/render.js, the engine only processes active tweens for specific properties, keeping the per-frame cost proportional to the number of conflicting animations rather than the total tween count.
Summary
- Composition modes (
replace,blend,none) insrc/core/consts.jscontrol how multiple animations interact on the same element. replace(default) overrides overlapping values, whileblendsums deltas additively.- The sibling list architecture in
src/animation/composition.jsuses_prevRep,_nextRep,_prevAdd, and_nextAddpointers for efficient tween management. - Rendering logic in
src/core/render.js(lines 158–166 and 231–236) determines final values based on the_compositionflag stored during tween creation insrc/animation/animation.js. - Additive animations require all participating tweens to specify
composition: 'blend'.
Frequently Asked Questions
What happens when two animations target the same property without specifying composition?
By default, Anime.js applies replace composition. The second animation overrides the first during their overlap period. According to the source code in src/animation/animation.js (lines 260–263), the library automatically defaults to replace mode when no composition is specified.
Can I mix replace and blend modes on different properties of the same element?
Yes. The composition mode is evaluated per property, not per element. You can animate translateX with replace while animating scale with blend on the same target. The lookup maps in src/animation/composition.js maintain separate sibling lists for each property.
How does blend mode calculate the final value?
During each frame, the render loop in src/core/render.js (lines 231–236) iterates through all active tweens in the additive list and sums their individual contributions (_fromNumber, _toNumber interpolated by progress) before applying the result to the DOM element. This creates true additive animation where multiple motion vectors combine.
Is there a performance penalty for using blend mode?
No significant penalty exists for typical use cases. The system maintains O(1) insertion/removal and O(k) rendering costs, where k is the small number of active tweens on a specific property. The none composition type exists in src/core/consts.js specifically for edge cases involving massive target sets where even minimal composition overhead should be avoided.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →