Anime.js Staggering & Synchronization — Complete Guide
Anime.js staggering creates cascading animation effects where each element in a group animates with a small offset from its neighbors — producing waves, ripples, rainbows, and grid explosions with minimal code using anime.stagger().
What You’ll Learn
By the end of this tutorial, you’ll use anime.stagger() for linear and grid-based staggering, control direction (from, center, last), stagger on any numeric property (not just delay), combine stagger with timelines, and create wave and ripple effects.
Why Staggering Matters
Think of a stadium wave. One person stands up, then the next, then the next — each delayed by a fraction of a second. The result is a flowing motion that’s more impressive than everyone standing at once.
Security note: Understanding Animejs Staggering helps build more secure applications — a core principle at DodaTech, where tools like Durga Antivirus Pro and Doda Browser rely on solid implementation practices.
That’s staggering. Instead of animating 100 elements simultaneously (which looks boring), you offset each one’s start time by a small amount. The result is a wave, a ripple, or a cascade that feels alive and polished.
Real-world use: Durga Antivirus Pro uses staggering in its scan results grid. Each detected file card fades in sequentially with a subtle scale-up, creating a smooth reveal that doesn’t overwhelm the user. Without staggering, all 200 cards would pop in at once — visually jarring.
Where This Fits in Your Learning Path
flowchart LR
A["Getting Started"] --> B["Animation Controls"]
B --> C["SVG & Motion Paths"]
C --> D["**Staggering & Synchronization**"]
D --> E["Complex Web Animations"]
style D fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
anime.stagger() Basics
anime.stagger() is a utility function that generates an array of offset values — one for each element in your target list.
anime({
targets: '.box',
translateX: 200,
delay: anime.stagger(100) // 0ms, 100ms, 200ms, 300ms, 400ms...
})What this produces: If there are 5 elements with class box, their delays will be:
- Element 0: 0ms
- Element 1: 100ms
- Element 2: 200ms
- Element 3: 300ms
- Element 4: 400ms
The result: elements slide right one after another, creating a cascading wave.
Stagger on Any Numeric Property
Don’t limit stagger to delay — it works on any numeric value:
anime({
targets: '.box',
translateX: anime.stagger(40), // Each box offset by 40px more
rotate: anime.stagger(15), // Each box rotated 15° more
scale: anime.stagger(0.1), // Each box 0.1 larger
delay: anime.stagger(50) // Cascading start
})Each box ends up in a different position, rotation, and size — creating a cascading rainbow effect with just four lines.
Stagger Direction
By default, stagger starts from the first element (index 0). You can change this with the from option.
from: “first” (Default)
Elements animate in order from index 0 to last:
anime({ targets: '.box', translateX: 200, delay: anime.stagger(100, { from: 'first' }) })from: “last”
Reverse order — the last element animates first:
anime({ targets: '.box', translateX: 200, delay: anime.stagger(100, { from: 'last' }) })Good for “dismiss” animations where items should disappear starting from the end.
from: “center”
Elements closest to the center animate first, radiating outward:
anime({ targets: '.box', translateX: 200, delay: anime.stagger(100, { from: 'center' }) })With 9 elements, the order is: 4 (center), 3, 5, 2, 6, 1, 7, 0, 8. This creates a symmetrical outward burst.
from: [index]
Start from a specific index number:
anime({ targets: '.box', translateX: 200, delay: anime.stagger(100, { from: 2 }) })Grid-Based Staggering
When elements are arranged in a grid, stagger along specific axes:
// Stagger left-to-right (X axis)
anime({
targets: '.cell',
scale: 1.5,
delay: anime.stagger(50, { grid: [5, 5], axis: 'x' })
})
// Stagger top-to-bottom (Y axis)
anime({
targets: '.cell',
scale: 1.5,
delay: anime.stagger(50, { grid: [5, 5], axis: 'y' })
})
// Diagonal stagger (both axes)
anime({
targets: '.cell',
scale: 1.5,
delay: anime.stagger(50, { grid: [5, 5], axis: 'xy' })
})The grid option: [rows, columns] tells Anime.js how your elements are arranged. For a 5×5 grid, that’s 25 elements.
Axis behavior:
axis: 'x'— Animates row by row, left to right within each rowaxis: 'y'— Animates column by column, top to bottom within each columnaxis: 'xy'— Animates diagonally (like a wave across the grid)
Grid from Center (Ripple)
Combine grid with from: 'center' for a ripple effect:
anime({
targets: '.cell',
scale: [0, 1],
delay: anime.stagger(30, {
grid: [5, 5],
from: 'center'
})
})The center cell animates first, then rings expand outward — like a stone dropped in water.
Custom Stagger with Functions
For complete control, pass a function instead of anime.stagger():
anime({
targets: '.box',
translateX: 250,
delay: function(el, index, total) {
return Math.sin((index / total) * Math.PI * 2) * 200 + 200
},
duration: 800
})The function receives three arguments:
el— The current DOM elementindex— Its position in the target list (0-based)total— The total number of elements
This example uses a sine wave to create a “bounce forward and back” stagger pattern — middle elements animate first, ends animate last.
Random Stagger
anime({
targets: '.box',
translateX: 200,
delay: function() {
return Math.random() * 500
},
duration: 800
})Each element starts at a random time between 0 and 500ms. Creates a chaotic, organic feel.
Overlapping Animations (Wave Effect)
Create waves by staggering multiple keyframe transitions:
anime({
targets: '.box',
translateY: [
{ value: -100, duration: 600 }, // Move up
{ value: 0, duration: 600 } // Move back down
],
delay: anime.stagger(80),
loop: true,
easing: 'easeInOutQuad'
})Each element bounces up in sequence, creating a visible wave that travels across the group.
Combining Stagger with Timelines
Stagger inside timelines creates multi-phase cascading effects:
const tl = anime.timeline({
duration: 800,
easing: 'easeOutExpo'
})
tl.add({
targets: '.box',
scale: [0, 1],
delay: anime.stagger(60)
}).add({
targets: '.box',
translateX: anime.stagger(30),
delay: anime.stagger(40)
}).add({
targets: '.box',
rotate: anime.stagger(15),
delay: anime.stagger(50)
})Each phase (scale in, move, rotate) cascades through all elements before the next phase begins. The timeline ensures clean sequential ordering.
Easing Per Element
Each element can use a different easing function:
const easings = ['easeOutExpo', 'easeOutElastic', 'easeOutBounce', 'easeOutBack']
anime({
targets: '.box',
translateX: 250,
delay: anime.stagger(120),
easing: function(el, index) {
return easings[index % easings.length]
}
})Elements cycle through the easing types: element 0 uses easeOutExpo, element 1 uses easeOutElastic, element 2 uses easeOutBounce, element 3 uses easeOutBack, element 4 repeats to easeOutExpo.
Common Mistakes Beginners Make
1. Using stagger on a single target
// Stagger on one element = 0 delay, no effect
anime({ targets: '.single-element', delay: anime.stagger(100) })Stagger needs multiple targets to produce visible results. Verify your selector returns multiple elements.
2. Forgetting to specify grid dimensions
// Wrong: grid array is required for axis-based stagger
anime({ targets: '.cell', delay: anime.stagger(50, { axis: 'x' }) })
// Correct
anime({ targets: '.cell', delay: anime.stagger(50, { grid: [5, 5], axis: 'x' }) })Without grid, Anime.js doesn’t know the row/column arrangement and can’t compute axis-based staggering.
3. Confusing from: 'center' with from: 'first'
from: 'center' radiates outward symmetrically. from: 'first' starts at the beginning. With 9 elements, center goes: 4, 3, 5, 2, 6, 1, 7, 0, 8. First goes: 0, 1, 2, 3, 4, 5, 6, 7, 8.
4. Only staggering delay
Stagger works on any numeric property. Staggering only delay means all elements end up in the same final state — just at different times. Staggering position, rotation, or scale creates progressive variation in the final state too.
5. Not accounting for stagger duration in timelines
// This timeline add includes stagger delay
tl.add({ targets: '.box', translateX: 200, delay: anime.stagger(100) })
// Next add starts immediately after the LAST element's delay begins,
// not after all elements complete
When a stagger covers 10 elements with 100ms each, the total stagger time is 900ms (9 × 100ms). Plus the animation duration. Plan your timeline offsets to account for this.
Practice Questions
What does
anime.stagger(50)produce for 5 elements?[0, 50, 100, 150, 200]— element index × stagger value.What’s the difference between
from: 'center'andfrom: 'first'?centerradiates outward from the middle index (symmetrical).firststarts at index 0 (sequential).How does grid stagger differ from linear stagger? Grid stagger uses the element’s row/column position.
axis: 'x'goes row-by-row,axis: 'y'goes column-by-column,axis: 'xy'goes diagonally.What three arguments does the stagger callback function receive?
el(current element),index(its position),total(number of elements).Can you stagger color properties? Yes. Pass an array of colors and delay stagger: targets cycle through the color array with staggered timing.
Challenge
Build a “grid explosion” animation:
- 6×6 grid (36 cells) with random pastel colors
- On click, cells explode outward from center using
from: 'center' - Each cell scales from 0 to 1, rotates randomly, and moves slightly
- Use
easeOutElasticelasticity - After all cells settle, reverse the animation to collapse them back
FAQ
Try It Yourself
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime.js Stagger Demo</title>
<style>
body { font-family: system-ui; background: #0f0f23; color: #e0e0e0; display: flex; flex-direction: column; align-items: center; padding: 20px; }
.row { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; max-width: 600px; }
.box { width: 60px; height: 60px; border-radius: 8px; background: #fd79a8; display: flex; align-items: center; justify-content: center; font-weight: bold; color: #fff; }
button { padding: 10px 18px; border: none; border-radius: 6px; cursor: pointer; background: #6c5ce7; color: #fff; margin: 4px; font-size: 14px; }
button:hover { background: #5a4bd1; }
</style>
</head>
<body>
<h1>Stagger Patterns</h1>
<div>
<button onclick="runLinear()">Linear</button>
<button onclick="runCenter()">From Center</button>
<button onclick="runWave()">Wave Bounce</button>
</div>
<div class="row" style="margin-top: 20px;">
<div class="box">1</div><div class="box">2</div><div class="box">3</div>
<div class="box">4</div><div class="box">5</div><div class="box">6</div>
<div class="box">7</div><div class="box">8</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js"></script>
<script>
function runLinear() {
anime({ targets: '.box', translateY: -60, scale: 1.3, delay: anime.stagger(80), direction: 'alternate', loop: true, easing: 'easeInOutQuad' })
}
function runCenter() {
anime({ targets: '.box', translateY: -60, rotate: 180, delay: anime.stagger(80, { from: 'center' }), direction: 'alternate', loop: true, easing: 'easeInOutCubic' })
}
function runWave() {
anime({ targets: '.box', translateY: [{ value: -80, duration: 600 }, { value: 0, duration: 600 }], delay: anime.stagger(60), loop: true, easing: 'easeInOutQuad' })
}
</script>
</body>
</html>What to expect: Eight numbered boxes. “Linear” cascades left to right. “From Center” radiates outward from the middle. “Wave Bounce” creates a continuous traveling wave.
What’s Next
You’ve completed all Anime.js tutorials!
| Tutorial | What You’ll Learn |
|---|---|
| Next library: Axios | HTTP requests and API communication |
Related topics: JavaScript fundamentals, CSS animations.
What’s Next
Congratulations on completing this Animejs Staggering tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro