# How to Handle Animation Callbacks and Events in Anime.js: A Complete Guide

> Master Anime.js callbacks and events like onBegin, onUpdate, and onComplete. Learn how to hook into every animation phase with this complete guide and enhance your project's interactivity.

- Repository: [Julian Garnier/anime](https://github.com/juliangarnier/anime)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Anime.js exposes a rich callback system through `onBegin`, `onUpdate`, `onComplete`, and scroll-specific handlers that let you hook into every phase of an animation's lifecycle, all wired into the core rendering loop in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js).**

The **juliangarnier/anime** library provides granular control over animation workflows through its comprehensive **animation callbacks and events** system. Whether you need to trigger logic when an animation begins, monitor progress during each frame, or respond to scroll position changes, the engine's architecture ensures your functions execute at precisely the right moment. This guide examines the implementation details from the source code to help you leverage these hooks effectively.

## Core Animation Callbacks

The seven primary lifecycle callbacks are defined in [`src/core/globals.js`](https://github.com/juliangarnier/anime/blob/main/src/core/globals.js) and invoked by the rendering engine in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js). Each callback receives the **tickable instance** (the animation object) as its sole argument, allowing real-time introspection of properties like `_currentTime`, `progress`, and `completed`.

### The Seven Lifecycle Callbacks

| Callback | Invocation Timing | Implementation Location |
|----------|------------------|-------------------------|
| **onBegin** | When current time becomes > 0 for the first time | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 107-110 |
| **onBeforeUpdate** | Before tweens are evaluated for the current frame | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 136-138 |
| **onUpdate** | After tweens have been rendered | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 285-287 |
| **onLoop** | When animation loops to a new iteration (leaf animations only) | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 118-120 |
| **onComplete** | When animation reaches final state or setter finishes | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 94-104 and 301-311 |
| **onRender** | Immediately after first render when `autoplay:false` or forcing tweens | [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 80-82 |
| **onPause / onResume** | When animation is paused or resumed | [`src/timer/timer.js`](https://github.com/juliangarnier/anime/blob/main/src/timer/timer.js) (Timer class) |

If you omit a callback, the engine substitutes a **noop** function from `globals.defaults`, ensuring the render loop executes safely without conditional checks.

### Callback Registration in the Constructor

When you invoke `anime()`, the `JSAnimation` constructor in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) merges user-supplied callbacks with defaults:

```javascript
// src/animation/animation.js – constructor (excerpt)
const {
  onBegin, onBeforeUpdate, onUpdate,
  onLoop, onComplete, onRender, …
} = params;               // user parameters

const animDefaults = parent ? parent.defaults : globals.defaults;

// The callbacks are attached to the instance:
this.onRender = onRender || animDefaults.onRender;

```

This pattern guarantees that the render loop can call `tickable.onBegin(...)` and other handlers without existence checks.

## Timeline-Level Callbacks

A **Timeline** ([`src/timeline/timeline.js`](https://github.com/juliangarnier/anime/blob/main/src/timeline/timeline.js)) is itself a `Tickable` instance. Its callbacks (`onBegin`, `onUpdate`, `onComplete`, `onLoop`) are invoked from the same render loop as leaf animations. When a timeline finishes, the engine resolves its internal **Promise** (`_resolve`), enabling `await anime.timeline(...)` syntax.

## Scroll-Based Events and Callbacks

The `ScrollObserver` class in [`src/events/scroll.js`](https://github.com/juliangarnier/anime/blob/main/src/events/scroll.js) provides event-driven callbacks based on viewport position. The `handleScroll()` method (around line 200) calculates `isInView`, updates `progress`, and dispatches the appropriate handlers.

Key scroll callbacks include:

- **onEnter / onEnterForward / onEnterBackward**: Trigger when the target enters the viewport at the defined threshold.
- **onLeave / onLeaveForward / onLeaveBackward**: Trigger when the target exits the viewport.
- **onUpdate**: Fires on every scroll tick while the observer is active.
- **onSyncEnter / onSyncLeave / onSyncComplete**: Helper callbacks when the observer is synced to a linked animation.

The observer computes thresholds via `updateBounds()`, then in `handleScroll()` detects entry/exit and calls the corresponding callbacks. When linked to an animation via `link()`, the observer drives `animation.seek()` based on scroll progress.

## Practical Code Examples

### Basic Animation with All Lifecycle Callbacks

```javascript
anime({
  targets: '.dot',
  translateX: 400,
  rotate: [0, 360],
  duration: 1500,
  easing: 'easeInOutQuad',
  onBegin: anim => console.log('▶️ started', anim.id),
  onBeforeUpdate: anim => console.log('🔄 before frame', anim.currentTime),
  onUpdate: anim => console.log('📊 progress', anim.progress),
  onLoop: anim => console.log('🔁 looped', anim._currentIteration),
  onComplete: anim => console.log('✅ done', anim.id)
});

```

Internally, these map to `tickable.onBegin(...)` at [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) line 107, `tickable.onBeforeUpdate(...)` at line 136, `tickable.onUpdate(...)` at line 285, `tickable.onLoop(...)` at line 118, and the completion logic at lines 301-311.

### Timeline with Nested Callbacks

```javascript
const tl = anime.timeline({
  easing: 'easeOutExpo',
  duration: 800,
  onBegin: t => console.log('Timeline start'),
  onComplete: t => console.log('Timeline end')
});

tl
  .add({ targets: '.circle', translateY: -200 })
  .add({ targets: '.square', rotate: 180 }, '-=400')
  .add({
    targets: '.triangle',
    opacity: [0, 1],
    onBegin: t => console.log('Triangle enters')
  });

```

The timeline aggregates child animations while maintaining its own callback lifecycle through the `Tickable` interface.

### Scroll-Driven Animation with Event Callbacks

```javascript
import { onScroll } from 'animejs';

const anim = anime({
  targets: '.panel',
  translateY: [0, -200],
  autoplay: false,
  duration: 2000
});

onScroll({
  target: '.panel',
  container: window,
  enter: 'top 80%',
  leave: 'bottom 20%',
  onEnter: () => console.log('Entered view'),
  onLeave: () => console.log('Left view'),
  sync: true,
  link: anim
});

```

In [`src/events/scroll.js`](https://github.com/juliangarnier/anime/blob/main/src/events/scroll.js), the `ScrollObserver` creates a `ScrollContainer`, computes offsets via `updateBounds()`, and calls `linked.seek()` during `handleScroll()` when `sync` is enabled (lines 57-61).

### Custom Restart Logic in onComplete

```javascript
anime({
  targets: '.bounce',
  translateY: [0, -100],
  direction: 'alternate',
  loop: false,
  duration: 600,
  onComplete: function (anim) {
    console.log('Bounced once – restarting');
    anim.restart(); // Inherited from Timer class
  }
});

```

The `restart()` method resets internal timers and triggers `onBegin` again, demonstrating that callbacks receive fully-featured instances capable of self-manipulation.

## Summary

- Anime.js provides seven core lifecycle callbacks (`onBegin`, `onBeforeUpdate`, `onUpdate`, `onLoop`, `onComplete`, `onRender`, `onPause`/`onResume`) implemented in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) and [`src/timer/timer.js`](https://github.com/juliangarnier/anime/blob/main/src/timer/timer.js).
- Callbacks are merged with defaults in the `JSAnimation` constructor ([`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js)) and receive the tickable instance as their argument.
- **Timelines** inherit the same callback system as individual animations and resolve a Promise upon completion.
- **ScrollObserver** ([`src/events/scroll.js`](https://github.com/juliangarnier/anime/blob/main/src/events/scroll.js)) adds viewport-based callbacks (`onEnter`, `onLeave`, `onUpdate`) that can synchronize animations with scroll position via the `link()` method.
- All callbacks execute with zero conditional overhead in the render loop, using noop fallbacks from [`src/core/globals.js`](https://github.com/juliangarnier/anime/blob/main/src/core/globals.js) when not specified.

## Frequently Asked Questions

### What arguments do Anime.js callbacks receive?

All animation callbacks receive a single argument: the **tickable instance** that triggered the event. This object exposes properties like `currentTime`, `progress`, `began`, and `completed`, allowing you to inspect or manipulate the animation state in real time according to the implementation in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js).

### How do I run code when an animation starts playing?

Use the **onBegin** callback, which fires when the animation's current time becomes greater than zero for the first time. According to [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 107-110, this triggers immediately after the animation transitions from a pending state to active playback.

### Can I use async/await with Anime.js timelines?

Yes. The `Timeline` class in [`src/timeline/timeline.js`](https://github.com/juliangarnier/anime/blob/main/src/timeline/timeline.js) implements a Promise-based completion system. When the timeline finishes, the engine resolves its internal `_resolve` function, allowing you to write `await anime.timeline({...}).add(...)` and pause execution until all animations complete.

### What is the difference between onUpdate and onBeforeUpdate?

**onBeforeUpdate** fires before the engine evaluates tweens for the current frame ([`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) lines 136-138), making it ideal for preprocessing or modifying target values. **onUpdate** fires after tweens have been rendered (lines 285-287), providing access to the final computed values for the frame.