Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Anime.js User Guide

Generated May 2026 from juliangarnier/anime at 3b369a4

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Quick Start

Anime.js is a lightweight, high-performance JavaScript animation engine that handles CSS properties, SVG attributes, DOM attributes, and JavaScript objects with a simple, unified API. Version 4 introduces timelines, draggables, scroll-linked animations, FLIP-style layout animations, text splitting, and Web Animations API (WAAPI) integration.

Key features:

  • Animate CSS transforms, colors, SVG attributes, and plain objects
  • Spring physics, cubic-bezier, steps, and 20+ built-in easing functions
  • Timelines with labels, position offsets, and sync
  • Scroll-linked animations via ScrollObserver
  • Drag interactions with snap, inertia, and container bounds
  • FLIP-style automatic layout animations (AutoLayout)
  • Text splitting into lines, words, and characters
  • Native WAAPI bridge for GPU-accelerated animations
  • Stagger utility with grid support
  • Tree-shakeable ES module architecture

Prerequisites: A modern browser (Chrome 84+, Firefox 75+, Safari 14+, Edge 84+) or Node.js 18+.

Install and animate in under a minute:

npm install animejs
import { animate } from 'animejs';

animate('.box', {
  translateX: 250,
  rotate: '1turn',
  duration: 800,
  ease: 'out(3)',
});
// The .box element slides 250px right and rotates one full turn over 800ms

Tip

For quick prototyping, load the UMD bundle directly from a CDN: <script src="https://cdn.jsdelivr.net/npm/animejs@4/dist/bundles/anime.umd.min.js"></script>. The global anime object exposes all exports.

What to try next: Jump to Installation for all delivery methods, or skip straight to Core Usage to explore animations, timelines, and scroll-linked effects.

2. Installation

System Requirements

Requirement Minimum
Node.js (for npm) 18+
Browser Chrome 84+, Firefox 75+, Safari 14+, Edge 84+
Module system ES Modules or CommonJS

Installation Methods

npm

npm install animejs

yarn

yarn add animejs

pnpm

pnpm add animejs

CDN (UMD)

<script src="https://cdn.jsdelivr.net/npm/animejs@4/dist/bundles/anime.umd.min.js"></script>

CDN (ES Module)

<script type="module">
  import { animate } from 'https://cdn.jsdelivr.net/npm/animejs@4/dist/modules/index.js';
</script>

Module Imports

Anime.js v4 supports tree-shaking. Import only what you need:

// Full library
import { animate, createTimeline, createTimer, engine } from 'animejs';

// Individual modules for smaller bundles
import { animate } from 'animejs/animation';
import { createTimeline } from 'animejs/timeline';
import { createTimer } from 'animejs/timer';
import { createAnimatable } from 'animejs/animatable';
import { Draggable } from 'animejs/draggable';
import { createScope } from 'animejs/scope';
import { engine } from 'animejs/engine';
import { ScrollObserver } from 'animejs/events';
import { AutoLayout } from 'animejs/layout';
import * as easings from 'animejs/easings';
import * as utils from 'animejs/utils';
import * as svg from 'animejs/svg';
import * as text from 'animejs/text';
import { waapi } from 'animejs/waapi';

Important

The package uses "type": "module" in package.json. CommonJS consumers should use require('animejs') which resolves to dist/modules/index.cjs.

Post-Install Verification

import { engine } from 'animejs';
console.log(engine.timeUnit); // 'ms'
ms

Install Troubleshooting

Q: I get "Cannot find module 'animejs'" after install.

Verify the package is in node_modules/animejs and your bundler supports the exports field in package.json. Older bundlers may need the module field: animejs/dist/modules/index.js.

Q: TypeScript types are missing.

Types ship at dist/modules/index.d.ts. Ensure your tsconfig.json has "moduleResolution": "bundler" or "node16".

Q: The UMD bundle doesn't expose anime globally.

Make sure you're loading anime.umd.min.js (not the ES module build) via a regular <script> tag (not type="module").

3. Configuration

Global Defaults

Override global defaults through the engine.defaults object. These apply to every new animation unless overridden per-instance:

import { engine } from 'animejs';

// Change the default easing and duration
engine.defaults.ease = 'inOut(3)';
engine.defaults.duration = 600;
engine.defaults.autoplay = true;
Default Type Value Description
duration Number 1000 Animation duration in ms
delay Number 0 Delay before start in ms
ease String/Function 'out(2)' Default easing
loop Number/Boolean 0 Number of extra iterations (true = infinite)
alternate Boolean false Reverse direction on each loop
reversed Boolean false Start playing in reverse
autoplay Boolean true Start immediately on creation
playbackRate Number 1 Playback speed multiplier
frameRate Number 240 Max frames per second
composition String/Number 'replace' Tween composition mode ('replace', 'none', 'blend')
loopDelay Number 0 Delay between loop iterations

Engine Settings

import { engine } from 'animejs';

// Switch to seconds-based timing
engine.timeUnit = 's';

// Control rounding precision (decimal places)
engine.precision = 4;

// Adjust global playback speed
engine.speed = 1.5;

// Disable auto-pause when the browser tab is hidden
engine.pauseOnDocumentHidden = false;

Tip

When using engine.timeUnit = 's', all duration and delay values are interpreted in seconds. For example, duration: 1 means 1 second. The default is 'ms' (milliseconds).

See the Admin Guide for the full configuration reference including all engine properties and composition internals.

4. Core Usage

Creating Animations

The animate() function is the primary way to create animations:

import { animate } from 'animejs';

// Animate CSS properties
animate('.element', {
  translateX: 250,
  opacity: [0, 1],
  duration: 1000,
  ease: 'out(3)',
});

Targets can be:

  • CSS selectors: '.class', '#id', 'div'
  • DOM elements: document.querySelector('.box')
  • NodeLists: document.querySelectorAll('.items')
  • Arrays: [el1, el2, el3]
  • JavaScript objects: { x: 0, y: 0 }

Animatable properties include:

  • CSS transforms: translateX, translateY, translateZ, rotate, rotateX, rotateY, rotateZ, scale, scaleX, scaleY, scaleZ, skew, skewX, skewY
  • Short transforms: x (translateX), y (translateY), z (translateZ)
  • CSS properties: opacity, width, height, color, backgroundColor, etc.
  • CSS variables: '--custom-property'
  • SVG attributes: cx, r, d, points, fill, stroke, etc.
  • DOM attributes: any attribute via setAttribute
  • Object properties: any numeric property on a JS object

Value Types

// Unitless numbers
animate('.box', { translateX: 250 }); // defaults to 'px' for transforms

// With units
animate('.box', { width: '80%', rotate: '1turn' });

// From-to values (array syntax)
animate('.box', { translateX: [0, 250] });

// Multiple keyframes (array of values)
animate('.box', { translateX: [0, 100, 50, 250] });

// Relative values (operators)
animate('.box', { translateX: '+=200' }); // add 200 to current
animate('.box', { translateX: '-=100' }); // subtract 100
animate('.box', { translateX: '*=2' });   // multiply by 2

// Colors (hex, rgb, rgba, hsl, hsla)
animate('.box', { backgroundColor: '#FF0000' });
animate('.box', { color: 'rgb(255, 0, 0)' });

// CSS variables
animate('.box', { '--my-var': [0, 100] });

// Function-based values (per-target)
animate('.items', {
  translateX: (target, index, total) => index * 50,
  duration: (target, index, total) => 500 + index * 100,
});

Note

Color transitions always convert to RGBA internally. Named CSS colors (like red, blue) are not supported — use hex, rgb(), rgba(), hsl(), or hsla() notation.

Keyframes

Anime.js supports two keyframe formats:

// Duration-based keyframes (array of objects)
animate('.box', {
  keyframes: [
    { translateX: 100, rotate: '45deg' },
    { translateX: 250, rotate: '90deg' },
    { translateX: 0, rotate: '0deg' },
  ],
  duration: 2000,
});

// Percentage-based keyframes (object with percent keys)
animate('.box', {
  keyframes: {
    '0%':   { translateX: 0 },
    '50%':  { translateX: 250, ease: 'out(3)' },
    '100%': { translateX: 100 },
  },
  duration: 2000,
});

Easing Functions

Anime.js includes a comprehensive set of easing functions:

Easing Syntax Description
Power 'out(2)', 'in(3)', 'inOut(4)' Customizable power curves
Named 'inQuad', 'outCubic', 'inOutQuart' Standard Robert Penner easings
Back 'inBack(1.7)', 'outBack' Overshoot easing
Elastic 'inElastic(1, 0.3)', 'outElastic' Springy bounce
Bounce 'inBounce', 'outBounce', 'inOutBounce' Ball-drop bounce
Sine 'inSine', 'outSine', 'inOutSine' Sinusoidal
Circ 'inCirc', 'outCirc', 'inOutCirc' Circular
Expo 'inExpo', 'outExpo', 'inOutExpo' Exponential
Linear 'linear' Constant speed
Steps steps(5) Step function
Cubic Bezier cubicBezier(0.42, 0, 0.58, 1) CSS-style bezier
Spring spring({ mass: 1, stiffness: 100, damping: 10 }) Physics-based spring
import { animate, spring } from 'animejs';

// Spring easing with physics parameters
animate('.box', {
  translateX: 250,
  ease: spring({ mass: 1, stiffness: 100, damping: 10, velocity: 0 }),
});

// Springs also accept bounce + duration shorthand
animate('.box', {
  translateX: 250,
  ease: spring({ bounce: 0.5, duration: 628 }),
});

Warning

The spring() easing automatically calculates its own duration based on the physics simulation. Any duration parameter you set on the animation will be overridden by the spring's settling duration.

Easing Directions

Every easing supports four direction variants:

Direction Effect
in Starts slow, ends fast
out Starts fast, ends slow (default for power)
inOut Slow at both ends
outIn Fast at both ends
animate('.box', { translateX: 250, ease: 'inOutQuart' });
animate('.box', { translateX: 250, ease: 'outIn(3)' });

Playback Controls

Every animation, timer, and timeline returns an instance with full playback control:

const anim = animate('.box', {
  translateX: 250,
  autoplay: false,
});

anim.play();       // Play forward
anim.pause();      // Pause
anim.resume();     // Resume from current position
anim.reverse();    // Play backward
anim.alternate();  // Toggle direction
anim.restart();    // Reset and play
anim.seek(500);    // Jump to 500ms
anim.reset();      // Reset to initial state
anim.cancel();     // Cancel and detach
anim.revert();     // Cancel and restore original CSS
anim.complete();   // Jump to end and cancel

// Properties (get and set)
anim.currentTime = 500;
anim.progress = 0.5;         // 0 to 1
anim.iterationProgress = 0.5;
anim.currentIteration = 2;
anim.speed = 2;              // 2x playback speed
anim.reversed = true;

Callbacks

animate('.box', {
  translateX: 250,
  duration: 1000,
  loop: 2,
  onBegin: (anim) => console.log('Animation started'),
  onBeforeUpdate: (anim) => {},
  onUpdate: (anim) => console.log(`Progress: ${anim.progress}`),
  onRender: (anim) => console.log('Frame rendered'),
  onLoop: (anim) => console.log(`Loop ${anim.currentIteration}`),
  onPause: (anim) => console.log('Paused'),
  onComplete: (anim) => console.log('Done!'),
});

Promises

Animations are thenable — use await or .then():

const anim = animate('.box', { translateX: 250 });

// Await completion
await anim;
console.log('Animation finished');

// Or use .then()
anim.then(() => console.log('Animation finished'));

Timers

createTimer() creates a time-based ticker without animation targets. Useful for countdowns, progress bars, or orchestrating custom logic:

import { createTimer } from 'animejs';

const timer = createTimer({
  duration: 5000,
  loop: true,
  onUpdate: (self) => {
    console.log(`Time: ${self.currentTime}ms, Progress: ${self.progress}`);
  },
});

5. Common Tasks

Timelines

Chain and orchestrate multiple animations on a shared timeline:

import { createTimeline } from 'animejs';

const tl = createTimeline({
  defaults: { duration: 600, ease: 'out(3)' },
});

tl.add('.box-1', { translateX: 250 })
  .add('.box-2', { translateY: 100 }, '<')       // Start with previous
  .add('.box-3', { rotate: '1turn' }, '<<')      // Start at previous start
  .add('.box-4', { scale: [0, 1] }, '-=200')     // 200ms before end
  .add('.box-5', { opacity: [0, 1] }, '+=100');  // 100ms after end

Position syntax:

Position Meaning
(omitted) After previous child ends
'<' At the end of the previous child
'<<' At the start of the previous child
'+=200' 200ms after the current end
'-=200' 200ms before the current end
500 Absolute position at 500ms
'labelName' At a named label
'labelName+=200' 200ms after a label

Timeline methods:

// Set values instantly (0-duration animation)
tl.set('.box', { opacity: 1 }, 0);

// Add labels for referencing positions
tl.label('halfway', '50%');

// Call a function at a position
tl.call(() => console.log('Reached this point'), '+=0');

// Sync a native WAAPI animation or another timer
tl.sync(existingAnimation, 0);

// Remove targets from the timeline
tl.remove('.box');

// Stretch timeline to a new total duration
tl.stretch(5000);

// Refresh function-based values
tl.refresh();

Tip

Set composition: false on the timeline to disable internal composition rendering, which can improve performance for very complex timelines with many children.

Stagger

Distribute values across multiple targets with fine-grained control:

import { animate, stagger } from 'animejs';

// Basic stagger: 100ms between each target
animate('.items', {
  translateY: [-20, 0],
  opacity: [0, 1],
  delay: stagger(100),
});

// Range stagger: spread values from 0 to 500ms
animate('.items', {
  translateX: 250,
  delay: stagger([0, 500]),
});

// Stagger from center
animate('.items', {
  scale: [0, 1],
  delay: stagger(100, { from: 'center' }),
});

// Grid stagger (for grid layouts)
animate('.grid-items', {
  scale: [0, 1],
  delay: stagger(50, { grid: [10, 10], from: 'center', axis: 'y' }),
});

// Stagger with easing
animate('.items', {
  translateX: 250,
  delay: stagger(500, { ease: 'out(3)' }),
});

Stagger from options: 'first' (default), 'center', 'last', 'random', or a numeric index.

Stagger axis options (grid only): 'x', 'y', or omit for radial distance.

Scroll-Linked Animations

Use ScrollObserver to trigger or sync animations based on scroll position:

import { animate, ScrollObserver } from 'animejs';

// Play/pause on enter/leave
const anim = animate('.element', {
  translateX: 250,
  autoplay: false,
});

const observer = new ScrollObserver({
  target: '.element',
  sync: 'play pause',     // Play on enter, pause on leave
});
observer.link(anim);

// Or pass the observer directly as autoplay
animate('.element', {
  translateX: 250,
  autoplay: new ScrollObserver({ target: '.element' }),
});

// Sync progress to scroll (scrubbing)
animate('.element', {
  translateX: [0, 500],
  autoplay: new ScrollObserver({
    target: '.element',
    sync: 'linear',        // Smooth linear sync
  }),
});

// Sync with easing (smooth scroll-linked)
animate('.element', {
  translateX: [0, 500],
  autoplay: new ScrollObserver({
    target: '.element',
    sync: 2,               // Numeric = smooth factor
  }),
});

ScrollObserver sync modes:

Mode Behavior
'play pause' Play on enter, pause on leave
'play reverse' Play on enter, reverse on leave
'play restart' Play on enter, restart on leave
'play pause reverse restart' Directional: enter-fwd, leave-fwd, enter-bwd, leave-bwd
'linear' Direct 1:1 scroll-to-progress mapping
true or 1 Smooth interpolated scroll sync (factor=1)
2 Smoother interpolation (higher = smoother)
Easing function Custom easing applied to scroll progress

Threshold configuration:

new ScrollObserver({
  target: '.element',
  enter: 'top bottom',     // When top of element hits bottom of viewport
  leave: 'bottom top',     // When bottom of element hits top of viewport
  container: '.scroll-container', // Custom scroll container
  horizontal: true,        // Watch horizontal scroll
  repeat: true,            // Re-trigger on every enter/leave cycle
});

Warning

When using sync: 'linear' or numeric smooth modes, the linked animation's duration is ignored — progress is driven entirely by scroll position between the enter and leave thresholds.

ScrollObserver callbacks:

new ScrollObserver({
  target: '.element',
  onEnter: (observer) => console.log('Entered'),
  onLeave: (observer) => console.log('Left'),
  onEnterForward: (observer) => {},
  onLeaveForward: (observer) => {},
  onEnterBackward: (observer) => {},
  onLeaveBackward: (observer) => {},
  onUpdate: (observer) => {},
  onResize: (observer) => {},
  onSyncComplete: (observer) => {},
});

Draggable Elements

Create interactive drag interactions with inertia and snap:

import { Draggable } from 'animejs';

// Basic draggable
const drag = new Draggable('.box');

// Constrained to a container with snap
const drag = new Draggable('.box', {
  container: '.container',
  snapX: 50,              // Snap to 50px grid
  snapY: 50,
  releaseEase: spring({ stiffness: 80, damping: 20 }),
});

// Single-axis drag
const drag = new Draggable('.slider-thumb', {
  y: false,               // Disable vertical dragging
  container: '.slider-track',
});

// Custom property mapping
const drag = new Draggable('.element', {
  x: { mapTo: 'translateX' },
  y: { mapTo: 'translateY' },
});

Draggable callbacks:

new Draggable('.box', {
  onGrab: (d) => console.log('Grabbed'),
  onDrag: (d) => console.log(`Position: ${d.x}, ${d.y}`),
  onRelease: (d) => console.log('Released'),
  onUpdate: (d) => {},
  onSettle: (d) => console.log('Settled'),
  onSnap: (d) => console.log('Snapped'),
  onResize: (d) => {},
});

Draggable properties:

Property Type Description
x Boolean/Object Horizontal drag config (false to disable)
y Boolean/Object Vertical drag config (false to disable)
container Selector/Element Bounding container
trigger Selector/Element Element that initiates the drag
snapX Number/Array Horizontal snap increment or snap points
snapY Number/Array Vertical snap increment or snap points
containerFriction Number Friction when hitting container edges
releaseStiffness Number Spring stiffness on release (default: 80)
releaseDamping Number Spring damping on release (default: 20)
releaseMass Number Spring mass on release (default: 1)
releaseEase Easing/Spring Release animation easing
dragSpeed Number Drag speed multiplier
maxVelocity Number Maximum release velocity
scrollSpeed Number Auto-scroll speed near edges
scrollThreshold Number Distance from edge to trigger auto-scroll
cursor Boolean/Object Cursor style management

Animatables

Create persistent, reactive animation bindings that update instantly when you call them:

import { createAnimatable } from 'animejs';

const box = createAnimatable('.box', {
  translateX: 500,     // Duration in ms for the transition
  translateY: 500,
  rotate: 300,
});

// Animate to a new value
box.translateX(200);         // Animate translateX to 200 over 500ms
box.translateY(100, 200);    // Animate translateY to 100 over 200ms
box.rotate(45, 300, 'out(3)'); // With custom easing

// Read current value
const currentX = box.translateX(); // Returns current number

Note

Animatables are ideal for interactive animations (mouse tracking, game loops) where you need to smoothly transition to new values on every frame without creating new animation instances.

SVG Animations

Line Drawing

import { animate } from 'animejs';
import { createDrawable } from 'animejs/svg';

const paths = createDrawable('svg path');

animate(paths, {
  draw: ['0 0', '0 1'],    // Draw from nothing to full path
  duration: 2000,
  ease: 'inOut(3)',
});

Motion Paths

import { animate } from 'animejs';
import { createMotionPath } from 'animejs/svg';

const motionPath = createMotionPath('svg #motionPath');

animate('.element', {
  ...motionPath,            // Spreads translateX, translateY, rotate
  duration: 3000,
});

SVG Morphing

import { animate } from 'animejs';
import { morphTo } from 'animejs/svg';

animate('svg #shape1', {
  d: morphTo('svg #shape2', 0.33),   // Morph with precision 0.33
  duration: 1000,
});

Important

morphTo() only works with <path>, <polygon>, and <polyline> SVG elements. Attempting to morph other SVG elements (like <rect> or <circle>) will throw an error.

Text Splitting

Split text elements into individually animatable lines, words, and characters:

import { TextSplitter } from 'animejs/text';
import { animate, stagger } from 'animejs';

const splitter = new TextSplitter('.text-element', {
  split: 'chars words lines',
});

// Animate characters
animate(splitter.chars, {
  opacity: [0, 1],
  translateY: [20, 0],
  delay: stagger(30),
});

TextSplitter options:

Option Type Description
split String What to split: 'chars', 'words', 'lines', or combinations
char Object Template options for character wrappers
word Object Template options for word wrappers
line Object Template options for line wrappers

Template options support class, clone (for clone-based reveals), and wrap (for overflow-clip containers).

Layout Animations (FLIP)

Automatically animate DOM layout changes with AutoLayout:

import { AutoLayout } from 'animejs/layout';

const layout = new AutoLayout('.container', {
  duration: 600,
  ease: 'out(3)',
  children: '.item',
  properties: ['backgroundColor', 'borderRadius'],
});

// Now any DOM mutation inside .container is automatically animated:
// - Reordering elements
// - Adding/removing elements
// - Resizing
// - Visibility changes

AutoLayout options:

Option Type Description
children Selector Elements inside root to track
properties Array Extra CSS properties to animate during transitions
duration Number/Function Animation duration
delay Number/Function Animation delay
ease Easing Animation easing
enterFrom Object Properties for entering elements
leaveTo Object Properties for leaving elements
swapAt Object Properties at the swap midpoint

WAAPI Bridge

Use the native Web Animations API with anime.js's syntax and composition system:

import { waapi } from 'animejs/waapi';

const anim = waapi('.box', {
  translateX: 250,
  opacity: [0, 1],
  duration: 1000,
  ease: 'out(3)',
});

// Playback controls work the same
anim.play();
anim.pause();
anim.reverse();
anim.seek(500);

// Sync with a timeline
import { createTimeline } from 'animejs';
const tl = createTimeline();
tl.sync(anim, 0);

Tip

WAAPI animations run on the browser's compositor thread, which can provide smoother performance for simple transform and opacity animations. Use waapi() instead of animate() when you need maximum rendering performance and don't need additive composition or complex value types.

Scopes

Group animations and clean them up together — essential for component-based frameworks (React, Vue, Angular):

import { createScope, animate } from 'animejs';

const scope = createScope({ root: '#my-component' });

scope.add(() => {
  // All selectors are scoped to #my-component
  animate('.item', { translateX: 250 });
  animate('.title', { opacity: [0, 1] });

  // Return a cleanup function
  return () => console.log('Cleaned up');
});

// Define named methods
scope.add('enter', () => {
  animate('.item', { translateX: [0, 250] });
});

// Call named methods (executes within scope context)
scope.methods.enter();

// Clean up all animations in the scope
scope.revert();

Scope with media queries:

const scope = createScope({
  root: '#app',
  mediaQueries: {
    isSmall: '(max-width: 640px)',
    prefersReduced: '(prefers-reduced-motion: reduce)',
  },
});

scope.add((self) => {
  if (self.matches.prefersReduced) return;
  animate('.hero', {
    translateY: self.matches.isSmall ? 50 : 200,
  });
});
// Scope automatically refreshes when media queries change

Utility Functions

import * as utils from 'animejs/utils';

// Get/set CSS and DOM values
utils.get('.box', 'translateX');        // Read current value
utils.set('.box', { opacity: 0.5 });   // Set without animation

// Number utilities (all are chainable)
utils.clamp(150, 0, 100);              // 100
utils.round(3.14159, 2);               // 3.14
utils.snap(27, 10);                    // 30
utils.snap(27, [0, 25, 50, 75, 100]);  // 25
utils.lerp(0, 100, 0.5);              // 50
utils.mapRange(5, 0, 10, 0, 100);     // 50
utils.wrap(370, 0, 360);              // 10
utils.degToRad(180);                   // 3.14159...
utils.radToDeg(Math.PI);              // 180
utils.roundPad(3.1, 3);               // "3.100"
utils.padStart(5, 3, '0');            // "005"
utils.damp(0, 100, 16, 0.1);         // Frame-rate independent damped lerp

// Chainable utilities
const transform = utils.clamp(0, 100).round(2).mapRange(0, 100, 0, 1);
transform(75.555); // 0.76

// Random numbers
utils.random(0, 100);                  // Random integer 0-100
utils.random(0, 1, 2);                // Random float 0-1, 2 decimal places
utils.randomPick(['a', 'b', 'c']);    // Random array element
utils.shuffle([1, 2, 3, 4, 5]);      // Fisher-Yates shuffle (in-place)

// Seeded random (deterministic)
const seeded = utils.createSeededRandom(42);
seeded(0, 100);  // Always produces the same sequence for seed 42

Additive Animations (Composition: Blend)

Layer multiple animations on the same property:

import { animate } from 'animejs';

animate('.box', {
  translateX: 100,
  composition: 'blend',
});

// This adds to the first, not replaces
animate('.box', {
  translateX: 50,
  composition: 'blend',
});
// Result: translateX animates toward 150 (100 + 50)

Composition modes:

Mode Behavior
'replace' New animation overrides previous (default)
'none' No composition tracking (fastest, no override)
'blend' Additive — values stack on top of each other

Note

When targeting 1000+ elements, composition automatically switches to 'none' for performance. You can override this by explicitly setting composition: 'replace' or 'blend'.

6. Troubleshooting

Diagnostic Decision Tree

  1. Animation not playing? Check autoplay (default true), verify the target exists in the DOM before animate() runs, and check the browser console for the "No target found" warning.
  2. Animation looks wrong? Inspect the ease and duration values. Verify units match (e.g., '90deg' not 90 for rotation angles).
  3. Performance issues? Reduce composition to 'none' for large target counts. Use waapi() for simple transform/opacity animations. Lower engine.fps to cap frame rate.
  4. Scroll animation not syncing? Ensure the target element is in the DOM and within the scroll container's scrollable area. Check enter/leave threshold values.

Error: No target found. Make sure the element you're trying to animate is accessible before creating your animation.

Cause: The CSS selector or target reference doesn't match any elements in the DOM at the time animate() is called.

Solution:

  1. Verify the element exists: document.querySelector('.your-selector') should return an element
  2. If using a framework, ensure the component has mounted before creating animations
  3. Use createScope() to manage animation lifecycle with your component

Prevention: Always create animations inside scope.add() callbacks or after DOMContentLoaded.

Error: Can't morph a <rect> SVG element. Use <path>, <polygon> or <polyline>.

Cause: morphTo() was called on an SVG element that isn't a <path>, <polygon>, or <polyline>.

Solution: Convert your SVG shapes to <path> elements using your SVG editor's "Convert to path" feature.

Prevention: Only use morphTo() with <path>, <polygon>, or <polyline> elements.

Problem: Animation snaps to wrong values on restart

Cause: Previous animations on the same target/property weren't cleaned up. The composition system may hold stale tween siblings.

Solution:

  1. Call .revert() on the previous animation before creating a new one
  2. Use composition: 'replace' (the default) to automatically override previous animations
  3. Use createScope() and call scope.revert() to clean up all animations at once

Problem: Scroll-linked animation jumps or flickers

Cause: The linked animation's autoplay isn't set to the ScrollObserver instance, or the enter/leave thresholds overlap.

Solution:

// Pass the observer directly as autoplay
animate('.element', {
  translateX: 250,
  autoplay: new ScrollObserver({ target: '.element', sync: 'linear' }),
});

Prevention: Always pass the ScrollObserver as the autoplay value rather than linking separately when using scroll sync.

Problem: Spring animation never settles (GitHub #1118)

Cause: Spring physics with very low damping or very high stiffness can produce extremely long settling durations. The onComplete callback fires based on the perceived duration, not the mathematical settling point.

Solution: Increase damping (try 10–30) or decrease stiffness. Use spring({ bounce: 0.3, duration: 800 }) for more predictable results.

Problem: Draggable restricted to viewport with container (GitHub #1157)

Cause: When using a container parameter, the draggable bounds calculation uses the container's bounding rect. If the container has overflow: visible, the bounds may not match expectations.

Solution: Ensure the container element has explicit dimensions and overflow: hidden or overflow: auto if you want visual clipping to match the drag bounds.

Problem: Jittery animations (GitHub #1112)

Cause: Frame rate fluctuations, especially during page load or when many animations run simultaneously.

Solution:

  1. Cap the frame rate: engine.fps = 60
  2. Use waapi() for simple animations to offload to the compositor
  3. Reduce the number of simultaneously animating elements
  4. Use composition: 'none' for large stagger groups

Caution

Calling .cancel() on an animation permanently detaches its tweens from the composition system. The animation cannot be replayed after cancellation. Use .pause() if you need to resume later, or .revert() if you want to cleanly restore original styles.

7. FAQ

Q: How do I use anime.js with React?

Use createScope() with a ref to your component root. Call scope.revert() in the cleanup function:

import { useRef, useEffect } from 'react';
import { createScope, animate } from 'animejs';

function MyComponent() {
  const root = useRef(null);
  const scope = useRef(null);

  useEffect(() => {
    scope.current = createScope({ root: root.current });
    scope.current.add(() => {
      animate('.item', { translateX: 250 });
    });
    return () => scope.current.revert();
  }, []);

  return <div ref={root}><div className="item">Hello</div></div>;
}

Q: How do I use anime.js with Vue?

import { onMounted, onUnmounted, ref } from 'vue';
import { createScope, animate } from 'animejs';

const root = ref(null);
let scope;

onMounted(() => {
  scope = createScope({ root: root.value });
  scope.add(() => {
    animate('.item', { translateX: 250 });
  });
});

onUnmounted(() => scope?.revert());

Q: Can I animate JavaScript objects (not DOM elements)?

Yes. Pass an object as the target and animate any numeric property:

const obj = { x: 0, y: 0, progress: 0 };
animate(obj, {
  x: 100,
  y: 200,
  progress: 1,
  duration: 1000,
  onUpdate: () => console.log(obj.x, obj.y, obj.progress),
});

Q: How do I chain animations sequentially?

Use a timeline:

const tl = createTimeline();
tl.add('.first', { translateX: 100 })
  .add('.second', { translateY: 100 })
  .add('.third', { scale: 2 });

Or use promises:

await animate('.first', { translateX: 100 });
await animate('.second', { translateY: 100 });
await animate('.third', { scale: 2 });

Q: How do I pause all running animations?

import { engine } from 'animejs';
engine.pause();   // Pause everything
engine.resume();  // Resume everything

Q: Does anime.js work in Node.js?

Yes. The library detects the environment and works without a DOM. You can animate JavaScript objects in Node.js. DOM-related features (CSS, SVG, scroll, drag) require a browser.

Q: What is the difference between animate() and waapi()?

animate() uses anime.js's custom JavaScript rendering engine. waapi() delegates to the browser's native Web Animations API. Use waapi() for better performance on simple transform/opacity animations; use animate() when you need additive composition, complex value types, or SVG attribute animations.

Q: How do I animate canvas or WebGL objects?

Animate a plain JavaScript object and use onUpdate to sync values to your render loop:

const state = { rotation: 0, scale: 1 };
animate(state, {
  rotation: Math.PI * 2,
  scale: 2,
  duration: 2000,
  onUpdate: () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.save();
    ctx.rotate(state.rotation);
    ctx.scale(state.scale, state.scale);
    // Draw your scene
    ctx.restore();
  },
});

Q: How do I remove specific targets from a running animation?

Animations and timelines have no public remove() method on JSAnimation directly, but timelines expose .remove(targets, propertyName):

const tl = createTimeline();
tl.add('.items', { translateX: 250 });
tl.remove('.item-3');  // Remove .item-3 from the timeline

Q: How do I handle prefers-reduced-motion?

Use a scope with media queries:

const scope = createScope({
  mediaQueries: { reduced: '(prefers-reduced-motion: reduce)' },
});
scope.add((self) => {
  if (self.matches.reduced) return;
  animate('.hero', { translateY: [50, 0], opacity: [0, 1] });
});