Anime.js Callbacks and Events — Complete Guide
In this tutorial, you'll learn about Anime.js callbacks and events. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Anime.js callbacks let you hook into animation lifecycle events: when it starts, updates each frame, completes, and loops, giving you precise control over side effects during animations.
What You'll Learn
By the end of this tutorial, you'll use begin, complete, update, loopBegin, loopComplete, and changeBegin callbacks to trigger code at specific animation moments.
Why It Matters
Callbacks connect animations to the rest of your application. Start a sound when an animation begins, update a progress bar each frame, or navigate to a new page when the animation completes.
Real-World Use
Durga Antivirus Pro uses the update callback during the scanning animation to update the real-time progress percentage. The complete callback triggers the scan results report to slide in.
Where This Fits in Your Learning Path
flowchart LR
A["Timeline & Controls"] --> B["**Easing & Callbacks**"]
B --> C["SVG & Morph"]
C --> D["Scroll & Performance"]
D --> E["Advanced Anime.js"]
style B fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
begin Callback
Fires once when the animation starts playing, after any initial delay.
anime({
targets: '.box',
translateX: 300,
duration: 1000,
begin: function(anim) {
console.log('Animation started at', anim.currentTime)
document.querySelector('.status').textContent = 'Animating...'
}
})
Expected output: The console logs the start time and the status text updates immediately when the animation begins.
complete Callback
Fires once when the animation finishes playing all iterations.
anime({
targets: '.box',
translateX: 300,
duration: 1000,
complete: function(anim) {
console.log('Animation completed at', anim.currentTime)
document.querySelector('.status').textContent = 'Done!'
}
})
Expected output: The console logs the completion time and the status updates after the box finishes moving.
update Callback
Fires on every frame during the animation, giving you the current progress.
anime({
targets: '.box',
translateX: 300,
duration: 2000,
update: function(anim) {
const progress = Math.round(anim.progress)
document.querySelector('.progress').textContent = progress + '%'
}
})
Expected output: The progress percentage updates smoothly from 0% to 100% over 2 seconds.
loopBegin and loopComplete
Fire at the start and end of each loop iteration.
anime({
targets: '.box',
scale: 1.5,
duration: 500,
loop: 3,
direction: 'alternate',
loopBegin: function(anim) {
console.log('Loop iteration', anim.currentIteration, 'started')
},
loopComplete: function(anim) {
console.log('Loop iteration', anim.currentIteration, 'completed')
}
})
Expected output: The console logs the start and end of each of the 3 loop iterations.
changeBegin and changeComplete
Fire when the animation's current value changes direction or completes a change.
anime({
targets: '.box',
translateX: [0, 200, 100],
duration: 2000,
changeBegin: function(anim) {
console.log('Value began changing at', anim.currentTime)
},
changeComplete: function(anim) {
console.log('Value finished changing at', anim.currentTime)
}
})
Expected output: The callbacks fire as the box moves from 0 to 200, then from 200 to 100.
Using Callbacks with Timelines
Timelines also support the same callbacks, firing for the entire sequence.
const tl = anime.timeline({
duration: 600,
update: function(anim) {
console.log('Timeline progress:', Math.round(anim.progress) + '%')
},
complete: function() {
console.log('Entire timeline done')
}
})
tl.add({ targets: '.a', translateX: 100 })
tl.add({ targets: '.b', translateX: 100 })
tl.add({ targets: '.c', translateX: 100 })
Expected output: The update callback fires for the entire timeline, not per step. Progress goes from 0 to 100% across all three segments.
Common Mistakes
1. Using callbacks for heavy DOM operations every frame
The update callback fires 60 times per second. Heavy DOM operations cause frame drops. Keep update callbacks lightweight.
2. Expecting begin to fire before the initial delay
begin fires after the delay, not immediately on creation. Use a separate function call before anime() if you need pre-delay logic.
3. Mixing begin and complete with loop
begin fires once for the entire animation (including loops). loopBegin fires per iteration. Use the right one for your use case.
4. Forgetting that 'this' inside callbacks refers to the animation
Inside callback functions, 'this' is the anime animation instance. Use arrow functions if you need the outer scope.
5. Not checking anim.progress for partial updates
The update callback fires on every frame. Compare anim.progress or anim.currentTime with previous values to avoid redundant work.
Practice Questions
Which callback fires 60 times per second? The update callback fires on every animation frame.
How is loopBegin different from begin? begin fires once when the entire animation starts. loopBegin fires at the start of each loop iteration.
What information does the anim parameter contain? The anim object has properties like currentTime, progress, currentIteration, and reversed.
Can callbacks access the animation's target elements? Yes. Use anim.animatables to access the animated objects and their properties.
Do timeline callbacks cover the entire sequence? Yes. The timeline's update callback reports progress across the entire sequence, not individual steps.
Challenge
Build a progress bar that fills from 0 to 100%. The update callback writes the percentage to a display. The complete callback changes the bar color to green and logs "Loading complete!".
FAQ
Mini Project
Build a multi-step progress indicator. Each step in a 4-step Process animates sequentially. Use complete callbacks on each step to highlight the next step in the UI. Use a final complete callback to show a congratulations message.
const steps = document.querySelectorAll('.step')
const status = document.querySelector('.status')
const tl = anime.timeline({
easing: 'easeOutQuad',
duration: 400
})
steps.forEach((step, i) => {
tl.add({
targets: step,
scale: [1, 1.3, 1],
backgroundColor: ['#e0e0e0', '#4ecdc4'],
complete: function() {
status.textContent = 'Step ' + (i + 1) + ' completed'
}
})
})
tl.add({
targets: '.done-banner',
translateY: [20, 0],
opacity: [0, 1],
complete: function() {
status.textContent = 'All steps done!'
status.style.color = '#4ecdc4'
}
})
<div style="display:flex;gap:10px;justify-content:center">
<div class="step" style="width:40px;height:40px;background:#e0e0e0;border-radius:50%"></div>
<div class="step" style="width:40px;height:40px;background:#e0e0e0;border-radius:50%"></div>
<div class="step" style="width:40px;height:40px;background:#e0e0e0;border-radius:50%"></div>
<div class="step" style="width:40px;height:40px;background:#e0e0e0;border-radius:50%"></div>
</div>
<p class="status">Waiting to start...</p>
<p class="done-banner" style="opacity:0;color:#4ecdc4;font-weight:bold">All Steps Complete!</p>
<button onclick="tl.restart()">Restart</button>
What's Next
Move into SVG and scroll animations:
| Tutorial | What You'll Learn |
|---|---|
| SVG and Motion Paths | Animate SVG elements along motion paths |
| Easing Functions | Deep dive into all easing functions and custom curves |
Related topics: requestAnimationFrame and frame timing, event-driven programming.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro