Anime.js Animation Controls & Timelines — Practical Guide
Anime.js animation controls let you start, stop, reverse, and seek through animations on demand, while timelines let you sequence multiple animations with precise timing — turning simple movements into orchestrated choreography.
What You’ll Learn
By the end of this tutorial, you’ll control animations with .play(), .pause(), .reverse(), .seek(), and .restart(), understand callbacks (begin, update, complete), build timelines with anime.timeline(), and sequence complex multi-step animations using promises.
anime() creates animations.Why Animation Controls Matter
A simple “move from A to B” animation is nice, but real-world interfaces need more: a button that pauses the animation, a slider that seeks to a specific moment, a “reverse” button that plays it backward. Without control methods, you’d have to destroy and recreate the animation every time.
Timelines solve a different problem: sequencing. Imagine a product page where the image fades in, then the title slides down, then the description appears. Without a timeline, you’d chain callbacks or use nested timeouts — messy and imprecise. Timelines give you clean, declarative sequencing.
Real-world use: Durga Antivirus Pro uses Anime.js timelines for its animated scan results — first the shield icon pulses, then the progress bar fills, then status text fades in, each step precisely timed. The .reverse() control lets users “rewind” the animation to watch it again.
Where This Fits in Your Learning Path
flowchart LR
A["Getting Started"] --> B["**Animation Controls & Timelines**"]
B --> C["SVG & Motion Paths"]
C --> D["Staggering & Synchronization"]
D --> E["Complex Web Animations"]
style B fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
Animation Instance
Every anime() call returns an animation instance — an object with properties and methods you can use to control playback.
const anim = anime({
targets: '.box',
translateX: 300,
duration: 2000,
autoplay: false // Don't start automatically
})The autoplay: false option is crucial when you want to control when the animation starts. Without it, the animation begins immediately and might be finished before you click your “Play” button.
.play() — Start or Resume
anim.play()Calling .play() on a paused animation resumes from where it paused. On a stopped animation, it starts from the beginning.
.pause() — Stop Mid-Animation
anim.pause()The animation freezes at its current position. Calling .play() resumes from there.
.reverse() — Flip Direction
anim.reverse() // Flips the direction flag
anim.play() // Plays in the new direction
Important: .reverse() only flips the internal direction flag — it doesn’t start playing. You must call .play() to begin reversed playback. If the animation was playing forward, after .reverse() it immediately moves backward from the current position.
.seek() — Jump to a Specific Time
anim.seek(500) // Jump to 500ms into the animation
anim.seek(anim.duration) // Jump to the very end
seek lets you jump to any point in the animation timeline. The animation instance remembers the seeked position — calling .play() from there continues forward.
.restart() — Start Over
anim.restart()Resets the animation to the beginning and plays it regardless of autoplay. Useful for “Replay” buttons.
The autoplay Option
By default, animations start as soon as they’re created. This is convenient for simple cases but problematic when you need manual control:
// Without autoplay: false — animation starts immediately
const anim = anime({ targets: '.box', translateX: 400, duration: 2000 })
// With autoplay: false — waits for you to call .play()
const anim = anime({ targets: '.box', translateX: 400, duration: 2000, autoplay: false })
document.querySelector('#startBtn').addEventListener('click', () => {
anim.play()
})Why autoplay: false matters: If you build a UI with Play/Pause/Reverse buttons and the animation starts on page load, the user might miss it entirely. Control animations should only play when the user interacts.
The finished Promise
Every animation instance has a .finished property that returns a Promise. This promise resolves when the animation completes (including all loops):
const anim = anime({
targets: '.box',
translateX: 300,
duration: 1000,
loop: 2
})
anim.finished.then(() => {
console.log('Animation done!')
// Start the next animation
anime({ targets: '.box', rotate: 360 })
})What the promise resolves after:
loop: 2— after both loops finishloop: true(infinite) — never resolves! Usecompletecallback instead- No loop — after the single playback
Callbacks
Callbacks are functions that fire at specific moments during an animation:
anime({
targets: '.box',
translateX: 300,
duration: 2000,
loop: 2,
begin: function(anim) {
console.log('Animation started at', anim.currentTime)
},
update: function(anim) {
console.log('Current progress:', anim.progress + '%')
},
complete: function(anim) {
console.log('All loops finished')
},
loopComplete: function(anim) {
console.log('One loop iteration done')
}
})| Callback | When it fires |
|---|---|
begin | First frame of the animation (after any delay) |
update | Every single frame (60 times per second) |
complete | After all loops have finished |
loopComplete | After each individual loop iteration |
When to use each:
begin— Start a loading spinner, disable a button during animationupdate— Update a progress bar, sync other elementscomplete— Chain the next animation, re-enable controlsloopComplete— Count loop iterations, alternate colors each cycle
anime.timeline() — Sequencing Animations
Timelines let you sequence multiple animations with millisecond precision:
const tl = anime.timeline({
duration: 1000,
easing: 'easeOutExpo'
})
tl.add({ targets: '.box1', translateX: 200 }) // Starts at 0ms
.add({ targets: '.box2', translateX: 200 }, 500) // Starts at 500ms
.add({ targets: '.box3', translateX: 200 }, '+=300') // 300ms after box2 ends
How offsets work:
| Offset | What it means |
|---|---|
500 | Absolute: start at 500ms on the timeline |
'+=200' | Relative: start 200ms after the previous animation ends |
'-=100' | Overlap: start 100ms before the previous animation ends |
'*=2' | Multiplier: start after 2× the previous animation’s duration |
Timeline Defaults Cascade
Options passed to anime.timeline() apply to all children automatically:
const tl = anime.timeline({
duration: 800,
easing: 'easeInOutSine',
loop: true,
direction: 'alternate'
})
tl.add({ targets: '.box1', translateX: 150 })
.add({ targets: '.box2', translateX: 150 })
.add({ targets: '.box3', translateX: 150 })All three animations share the 800ms duration, easeInOutSine easing, infinite looping, and alternate direction. You can still override per-child if needed.
Timeline Controls
Timelines expose the same control methods as individual animations:
const tl = anime.timeline({ autoplay: false })
tl.add({ targets: '.a', translateX: 100 })
.add({ targets: '.b', translateX: 100 }, '+=200')
.add({ targets: '.c', translateX: 100 }, '+=200')
tl.play()
tl.pause()
tl.reverse()
tl.seek(400)
tl.restart()Promise-Based Sequencing (Alternative)
For simpler sequences, you can use Promises and async/await instead of timelines:
async function runSequence() {
await anime({ targets: '.box', translateX: 200, duration: 800 }).finished
await anime({ targets: '.box', rotate: 180, duration: 600 }).finished
await anime({ targets: '.box', scale: 0.5, duration: 400 }).finished
await anime({ targets: '.box', scale: 1, duration: 400 }).finished
console.log('Sequence complete')
}
runSequence()Timeline vs Promises:
- Use timelines when you need precise overlap control (
-=100), shared options across children, or complex multi-element sequences. - Use Promises for simple linear sequences on a single element, or when you want the readability of async/await.
Parallel Groups with Promise.all
Run multiple animations in parallel, then do something when all finish:
async function parallelGroups() {
const group1 = anime({ targets: '.red', translateX: 200, duration: 1000 }).finished
const group2 = anime({ targets: '.blue', translateY: 200, duration: 1000 }).finished
await Promise.all([group1, group2])
await anime({ targets: '.green', scale: 2, duration: 500 }).finished
}Reading Animation State
Animation instances expose properties that tell you what’s happening:
const anim = anime({ targets: '.box', translateX: 300, autoplay: false })
anim.progress // 0–100 (percentage complete)
anim.currentTime // Current time in milliseconds
anim.duration // Total duration in milliseconds
anim.playing // Boolean — is it running right now?
anim.reversed // Boolean — is direction reversed?
anim.paused // Boolean — is it paused?
anim.completed // Boolean — has it finished all loops?
anim.direction // 'normal' or 'reverse'
These are useful for updating UI elements like progress bars or status indicators.
Common Mistakes Beginners Make
1. Not setting autoplay: false when building controls
If you create an animation at page load without autoplay: false, it may complete before the user ever clicks a button. Always use autoplay: false when building a custom control UI.
2. Calling .reverse() without .play()
anim.reverse() // Only flips the direction flag
// anim still not playing!
.reverse() does not auto-play. You must call .play() after .reverse().
3. Using .finished with infinite loops
// This promise NEVER resolves
const anim = anime({ targets: '.box', translateX: 300, loop: true })
anim.finished.then(() => console.log('done')) // Never fires
Use complete callback instead when loop: true.
4. Confusing absolute vs relative timeline offsets
tl.add({ targets: '.box2', translateX: 200 }, 500) // Starts at exactly 500ms
tl.add({ targets: '.box3', translateX: 200 }, '+=200') // Starts 200ms AFTER box2 ends
Absolute offsets (500) are fixed timeline positions. Relative offsets ('+=200') depend on the previous animation’s end time. If the previous animation is 1000ms, '+=200' starts at 1200ms.
5. Forgetting to pass shared options to the timeline
// Repetitive: each child repeats the same easing
tl.add({ targets: '.a', translateX: 100, easing: 'easeOutExpo' })
.add({ targets: '.b', translateX: 100, easing: 'easeOutExpo' })
// Clean: shared options on timeline
const tl = anime.timeline({ easing: 'easeOutExpo' })
tl.add({ targets: '.a', translateX: 100 })
.add({ targets: '.b', translateX: 100 })Practice Questions
What does
autoplay: falsedo? It prevents the animation from starting immediately. You must call.play()to begin.Does
.reverse()start playing the animation? No. It only flips the direction flag. You need to call.play()afterward.What’s the difference between
completeandloopCompletecallbacks?completefires once after all loops finish.loopCompletefires after each individual loop iteration.Why would you use a timeline instead of nested callbacks? Timelines give you precise offset control (absolute, relative, overlap), shared defaults, and the same control methods (play, pause, seek) on the entire sequence.
What happens if you call
.seek()past the animation’s duration? It clamps to the valid range. The animation appears at its end state.
Challenge
Build a “product reveal” animation sequence:
- Box 1 (image) fades in and slides up over 800ms
- Box 2 (title) slides in from the right, 300ms after box 1
- Box 3 (description) fades in, starting 200ms before box 2 ends
- All three pulse gently together (scale 1→1.02) in an infinite alternate loop after the initial reveal
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 Controls Demo</title>
<style>
body { font-family: system-ui; padding: 2rem; background: #0f0f23; color: #e0e0e0; }
.stage { position: relative; height: 200px; background: #1a1a3e; border-radius: 12px; padding: 20px; margin-bottom: 16px; }
.box { width: 60px; height: 60px; border-radius: 8px; position: absolute; top: 50%; margin-top: -30px; }
#box1 { background: #6c5ce7; left: 20px; }
#box2 { background: #fd79a8; left: 100px; }
#box3 { background: #00cec9; left: 180px; }
.controls { display: flex; gap: 8px; flex-wrap: wrap; }
.controls button { padding: 8px 16px; border: none; border-radius: 6px; cursor: pointer; background: #6c5ce7; color: #fff; font-size: 14px; }
.controls button:hover { background: #5a4bd1; }
#status { background: #26264a; padding: 8px 12px; border-radius: 6px; font-size: 13px; color: #ffd700; }
</style>
</head>
<body>
<div class="stage">
<div class="box" id="box1"></div>
<div class="box" id="box2"></div>
<div class="box" id="box3"></div>
</div>
<div class="controls">
<button onclick="tl.play()">▶ Play</button>
<button onclick="tl.pause()">⏸ Pause</button>
<button onclick="tl.reverse(); tl.play()">↻ Reverse</button>
<button onclick="tl.restart()">⏮ Restart</button>
<span id="status">Ready</span>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js"></script>
<script>
const tl = anime.timeline({
duration: 1000, easing: 'easeOutExpo', autoplay: false,
begin: () => document.getElementById('status').textContent = 'Running',
complete: () => document.getElementById('status').textContent = 'Complete'
})
tl.add({ targets: '#box1', translateX: 500 })
.add({ targets: '#box2', translateX: 500 })
.add({ targets: '#box3', translateX: 500 })
</script>
</body>
</html>What to expect: Three colored boxes. “Play” starts a sequential animation (box1 moves, then box2, then box3). “Pause” freezes. “Reverse” plays backward. “Restart” resets.
What’s Next
| Tutorial | What You’ll Learn |
|---|---|
| SVG & Motion Paths | Animate along paths, morph shapes, line drawing |
| Staggering & Synchronization | Cascading effects, grid patterns, radial stagger |
Related topics: JavaScript Promises, SVG basics.
What’s Next
Congratulations on completing this Animejs Controls 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