Animate elements using Anime.js. USE WHEN user asks about animations, transitions, motion effects, or interactive UI movement. TRIGGER WORDS: animate, animation, transition, motion, keyframe, timeline, stagger, tween, fade, slide, bounce, spring, easing, scroll animation, draggable, SVG animation, path drawing, morphing, entrance animation, page transition, loading spinner, hover effect.
Anime.js is a fast, lightweight JavaScript animation library (current stable: v4.x). This skill covers both v4 (current) and v3 (legacy). Always use v4 patterns unless the user is explicitly on v3.
npm install animejs
// ES Module (v4 — preferred)
import { animate, createTimeline, stagger, svg, createScope, onScroll, createDraggable, utils, engine } from 'animejs';
// CDN — ES Module
import { animate } from 'https://cdn.jsdelivr.net/npm/animejs/+esm';
import { animate } from 'https://esm.sh/animejs';
// CDN — UMD (global `anime` object)
// <script src="https://cdn.jsdelivr.net/npm/animejs/dist/bundles/anime.umd.min.js"></script>
const { animate } = anime;
// CommonJS
const { animate } = require('animejs');
Subpath imports (tree-shakable, smaller bundles):
import { animate } from 'animejs/animation';
import { createTimeline } from 'animejs/timeline';
import { stagger } from 'animejs/utils';
import { svg } from 'animejs/svg';
import { createScope } from 'animejs/scope';
import { onScroll } from 'animejs/events';
import { createDraggable } from 'animejs/draggable';
WAAPI lightweight alternative (3KB vs 10KB full):
import { waapi } from 'animejs';
const animation = waapi.animate(targets, parameters);
CRITICAL differences — always use v4 syntax unless told otherwise.
| Concept | v3 (legacy) | v4 (current) |
|---|---|---|
| Main function | anime({ targets, ...props }) | animate(targets, props) |
| Timeline | anime.timeline(opts) | createTimeline(opts) |
| Easing key | easing: 'easeOutQuad' | ease: 'outQuad' |
| Easing prefix | easeInOutElastic | inOutElastic |
| Direction reverse | direction: 'reverse' | reversed: true |
| Direction alternate | direction: 'alternate' | alternate: true |
| End delay | endDelay: 500 | loopDelay: 500 |
| Loop count | loop: 1 = 1 iteration | loop: 1 = repeat once (2 total) |
| Round | round: 100 | modifier: utils.round(2) |
| Callbacks | update, begin, complete | onUpdate, onBegin, onComplete |
| Loop callbacks | loopBegin / loopComplete | onLoop (single) |
| Promise | animation.finished.then() | animation.then() |
| SVG path | anime.path('path') | svg.createMotionPath('path') |
| SVG draw | anime.setDashoffset | svg.createDrawable() + draw prop |
| Remove | anime.remove(target) | utils.remove(target) |
| Get value | anime.get(el, prop) | utils.get(el, prop) |
| Set value | anime.set(el, props) | utils.set(el, props) |
| Engine hidden | anime.suspendWhenDocumentHidden | engine.pauseOnDocumentHidden |
| Property value | { value: 100 } | { to: 100 } |
| Imports | import anime from 'animejs/lib/anime.es.js' | import { animate } from 'animejs' |
v3 example:
import anime from 'animejs/lib/anime.es.js';
anime({
targets: '.box',
translateX: 250,
rotate: '1turn',
easing: 'easeInOutQuad',
direction: 'alternate',
loop: true
});
v4 equivalent:
import { animate } from 'animejs';
animate('.box', {
x: 250,
rotate: '1turn',
ease: 'inOutQuad',
alternate: true,
loop: true
});
const animation = animate(targets, parameters);
// CSS selector
animate('.card', { opacity: 0 });
// DOM element
animate(document.querySelector('#hero'), { y: -20 });
// NodeList / array of elements
animate(document.querySelectorAll('.item'), { x: 100 });
// Array of elements
animate([el1, el2, el3], { scale: 1.2 });
// Plain JavaScript object (non-DOM)
const obj = { count: 0 };
animate(obj, {
count: 100,
onUpdate: () => console.log(Math.round(obj.count))
});
animate('.el', {
// CSS transforms (shorthand preferred)
x: 100, // translateX — default unit: px
y: -50, // translateY — default unit: px
z: 0, // translateZ — default unit: px
rotate: '1turn', // or 360 (degrees), '3.14rad'
rotateX: 45,
rotateY: 45,
scale: 1.5,
scaleX: 2,
scaleY: 0.5,
skew: 15,
skewX: 10,
skewY: 10,
perspective: '500px',
// CSS properties
opacity: 0,
width: '100%',
height: '200px',
backgroundColor: '#ff0000',
color: 'rgb(255, 0, 0)',
borderRadius: '50%',
fontSize: '2rem',
// CSS variables
'--custom-prop': '100px',
// HTML attributes
'data-value': 100,
// SVG attributes
cx: 50,
r: 10,
fill: '#ff0000',
});
| Shorthand | Full name | Default unit |
|---|---|---|
x | translateX | px |
y | translateY | px |
z | translateZ | px |
rotate | rotate | deg |
rotateX | rotateX | deg |
rotateY | rotateY | deg |
scale | scale | — |
scaleX | scaleX | — |
scaleY | scaleY | — |
skew | skew | deg |
skewX | skewX | deg |
skewY | skewY | deg |
perspective | perspective | px |
animate('.el', {
x: 100, // Numeric (uses default unit)
x: '10rem', // With unit
x: '+=50', // Relative add
x: '-=50', // Relative subtract
x: '*=2', // Relative multiply
opacity: [0, 1], // From → To (array shorthand)
x: { from: -100, to: 100 }, // Explicit from/to object
backgroundColor: '#ff0000', // Color (hex, rgb, hsl)
x: (target, index, length) => index * 50, // Function-based
});
Function-based values — callback receives (target, index, length):
animate('.card', {
x: (el, i, total) => (i - total / 2) * 100,
delay: (el, i) => i * 50,
rotate: (el, i, total) => (i / total) * 360,
});
// Recalculate without recreating animation:
animation.refresh();
animate('.el', {
x: 100,
duration: 1000, // ms, default: 500
delay: 200, // ms before start
loopDelay: 500, // ms pause between loops (v4) — was endDelay in v3
ease: 'outQuad', // easing function
loop: true, // infinite loop
loop: 3, // repeat 3 times (plays 4 total in v4)
alternate: true, // reverse direction each loop
reversed: false, // start in reverse
autoplay: true, // start immediately (default: true)
frameRate: 60, // custom fps cap
playbackRate: 1, // speed multiplier (0.5 = half speed)
playbackEase: 'linear', // easing applied across full playback
composition: 'replace', // 'replace' | 'add' | 'blend'
});
animate('.el', {
x: 100,
onBegin: (anim) => console.log('started'),
onComplete: (anim) => console.log('done'),
onUpdate: (anim) => console.log(anim.progress),
onLoop: (anim) => console.log('looped'),
onPause: (anim) => console.log('paused'),
onBeforeUpdate: (anim) => {}, // JS only, before value updates
onRender: (anim) => {}, // JS only, during render phase
});
// Promise-like chaining
animate('.el', { x: 100 }).then(() => {
animate('.el', { y: 100 });
});
const anim = animate('.el', { x: 100, autoplay: false });
anim.play(); // Play forward from current position
anim.pause(); // Pause at current position
anim.resume(); // Resume from paused position (respects direction)
anim.restart(); // Reset to start and play
anim.reverse(); // Play backward
anim.alternate(); // Toggle direction
anim.complete(); // Jump to end state
anim.reset(); // Return to initial values, stop
anim.cancel(); // Stop and clear
anim.revert(); // Undo all changes, return to DOM original
anim.seek(500); // Jump to 500ms position
anim.stretch(2000); // Change total duration to 2000ms
anim.refresh(); // Recalculate function-based values
// Properties
anim.duration; // Total duration in ms
anim.currentTime; // Current position in ms
anim.progress; // 0 to 1
anim.paused; // boolean
anim.completed; // boolean
// Format: 'in', 'out', 'inOut', 'outIn' + curve name
// Parametric: pass strength value like out(3) or inOut(2)