Executive Summary
anime.js v4.3.6 is a tree-shakeable JavaScript animation engine authored by Julian Garnier. It targets browsers and Node.js, providing CSS/SVG/DOM/object animation, timeline orchestration, scroll-driven animation, draggable interactions, FLIP-style layout transitions, text splitting, and a Web Animations API (WAAPI) bridge. The library ships as ES modules, CommonJS, UMD, and IIFE bundles with full TypeScript declarations. It has zero runtime dependencies; all dev tooling (Rollup, Mocha/Chai, BrowserSync, TypeScript) is devDependencies-only.
| Attribute | Value |
|---|---|
| Version | 4.3.6 |
| License | MIT |
| Source commit | 3b369a4 (2026-02-13) |
| Package name | animejs |
| Entry point | src/index.js |
| Bundle sizes | UMD (anime.umd.min.js), IIFE (anime.iife.min.js), ES modules, CJS |
| Node.js compat | Yes (setImmediate/clearImmediate replaces rAF) |
| TypeScript | Full .d.ts declarations generated via tsc |
| Tree-shaking | "sideEffects": false in package.json |
Architecture
High-Level Design
anime.js is structured as a layered class hierarchy built on a shared timing core with an intrusive linked-list data structure for managing children (tweens, animations, timelines).
┌─────────────────────────────────────────────────────┐
│ Engine (singleton) │
│ requestAnimationFrame / setImmediate │
│ ┌──────────┴──────────┐ │
│ │ Linked-list of │ │
│ │ active Timers │ │
│ └──────────┬──────────┘ │
├─────────────────────────┼───────────────────────────┤
│ Timer ← Clock │ Timeline ← Timer │
│ JSAnimation ← Timer │ WAAPIAnimation │
├─────────────────────────┼───────────────────────────┤
│ Composition Layer (replace/none/blend) │
├─────────────────────────────────────────────────────┤
│ Animatable │ Draggable │ ScrollObserver │
│ AutoLayout │ TextSplitter│ Scope │
└─────────────────────────────────────────────────────┘
Class Hierarchy
Clock Base timing: deltaTime, fps, speed, requestTick()
├── Engine (singleton) RAF loop, document visibility, timeUnit, precision
└── Timer Playback: play/pause/resume/reverse/seek/cancel/revert
├── JSAnimation Property tweening, keyframes, composition, targets
└── Timeline Sequencing: add(), sync(), set(), label(), stretch()
Scope Framework integration, scoped cleanup, media queries
ScrollContainer Scroll position tracking, resize observer
ScrollObserver Scroll-linked playback (sync modes)
Animatable Reactive property animation (getter/setter pattern)
Draggable Pointer-driven drag with snap, bounds, inertia
AutoLayout FLIP-based layout animation
LayoutSnapshot Captures DOM measurements for FLIP
TextSplitter Text segmentation (lines, words, chars)
WAAPIAnimation Web Animations API bridge
DOMProxy Non-DOM target wrapper for Draggable
Transforms Matrix/transform resolution for Draggable
Spring Physics-based easing with mass/stiffness/damping
Module Map
The source is organized into 15 sub-packages under src/, each with its own index.js re-export:
| Module | Path | Files | Chars | Purpose |
|---|---|---|---|---|
| core | src/core/ |
11 | 52,640 | Clock, constants, helpers, colors, globals, render, styles, targets, transforms, units, values |
| animation | src/animation/ |
4 | 44,755 | JSAnimation class, animate() factory, additive blending, composition |
| timer | src/timer/ |
2 | 15,566 | Timer class (playback control base) |
| timeline | src/timeline/ |
3 | 12,812 | Timeline class, position parser |
| engine | src/engine/ |
2 | 4,404 | Engine singleton, RAF/setImmediate loop |
| animatable | src/animatable/ |
2 | 4,710 | Animatable class, createAnimatable() factory |
| draggable | src/draggable/ |
2 | 44,503 | Draggable, DOMProxy, Transforms |
| events | src/events/ |
2 | 32,887 | ScrollContainer, ScrollObserver |
| layout | src/layout/ |
2 | 55,727 | AutoLayout, LayoutSnapshot |
| scope | src/scope/ |
2 | 7,236 | Scope class |
| text | src/text/ |
2 | 19,919 | TextSplitter |
| svg | src/svg/ |
5 | 9,147 | createDrawable, createMotionPath, morphTo, getPath |
| waapi | src/waapi/ |
3 | 20,720 | WAAPIAnimation, easing conversion, composition |
| easings | src/easings/ |
7 sub-dirs | ~18,839 | eases, spring, cubic-bezier, linear, steps, irregular |
| utils | src/utils/ |
7 | 20,329 | Chainable math, stagger, random, target get/set, time sync |
Note
The
src/types/directory contains JSDoc type definitions only — no runtime code. TypeScript.d.tsfiles are generated from these viatsc -p tsconfig.types.json.
Package Exports Map
The library exposes 20 sub-path exports for fine-grained tree-shaking:
| Import path | Module |
|---|---|
animejs |
Full library |
animejs/animation |
JSAnimation + animate() |
animejs/timer |
Timer |
animejs/timeline |
Timeline + createTimeline() |
animejs/animatable |
Animatable + createAnimatable() |
animejs/draggable |
Draggable + createDraggable() |
animejs/scope |
Scope + createScope() |
animejs/engine |
Engine singleton |
animejs/events |
ScrollObserver + onScroll() |
animejs/layout |
AutoLayout + createLayout() |
animejs/text |
TextSplitter + splitText() |
animejs/svg |
createDrawable, createMotionPath, morphTo |
animejs/waapi |
WAAPIAnimation + waapi() |
animejs/utils |
Math utilities, stagger, get/set |
animejs/easings |
All easing exports |
animejs/easings/eases |
Named easings (in/out/inOut/outIn) |
animejs/easings/spring |
Spring physics easing |
animejs/easings/cubic-bezier |
Cubic bezier curves |
animejs/easings/linear |
Linear easing with stops |
animejs/easings/steps |
Step easing functions |
animejs/easings/irregular |
Irregular easing curves |
Each export provides types, require (CJS), import (ESM), and default (CJS fallback) conditions.
Internal Data Structures
Intrusive Linked Lists
The core data structure throughout anime.js is an intrusive doubly-linked list. Every parent-child relationship (Engine→Timer, Timer→Tween, Timeline→child, WAAPI composition lookups) uses the same pattern:
// Parent node
{ _head: firstChild, _tail: lastChild, _hasChildren: true }
// Child node
{ _prev: previousSibling, _next: nextSibling }
Operations are defined in src/core/helpers.js:
| Function | Complexity | Purpose |
|---|---|---|
addChild(parent, child, sortMethod) |
O(n) worst, O(1) append | Insert with optional sort |
removeChild(parent, child) |
O(1) | Unlink from list |
forEachChildren(parent, callback, reverse) |
O(n) | Iterate forward or backward |
Important
The linked list operations use configurable property names (
_prev/_nextby default,_prevRep/_nextRepfor composition siblings,_prevAdd/_nextAddfor additive blending chains). This allows a single tween node to participate in multiple linked lists simultaneously without extra wrapper objects.
Tween Types and Value Types
Tweens are classified by target type and value format:
Tween types (src/core/consts.js):
| Enum | Value | Description |
|---|---|---|
OBJECT |
0 | Plain JavaScript object property |
ATTRIBUTE |
1 | SVG/HTML attribute |
CSS |
2 | CSS property via style |
TRANSFORM |
3 | CSS transform (batched per element) |
CSS_VAR |
4 | CSS custom property |
Value types:
| Enum | Value | Description |
|---|---|---|
NUMBER |
0 | Raw number |
UNIT |
1 | Number + CSS unit (px, rem, %, etc.) |
COLOR |
2 | RGBA color (hex, rgb, hsl → internal [r,g,b,a]) |
COMPLEX |
3 | String with embedded numbers (e.g., "0px 10px 20px rgba(0,0,0,0.5)") |
Composition System
Three composition modes control how overlapping animations interact (src/animation/composition.js):
| Mode | Enum | Behavior |
|---|---|---|
replace |
0 | Default. New animation replaces previous ones on same target+property. Previous tween is unlinked via _prevRep/_nextRep chain. |
none |
1 | No composition tracking. Multiple animations stack independently. |
blend |
2 | Additive blending. Values from all active animations on the same property are summed. Uses _prevAdd/_nextAdd chain and a separate additive animation object. |
Caution
Known issue (#1138):
addChildcan create self-referential_prevRep/_nextReplinks when re-adding an already-linked tween. This can cause infinite loops in composition resolution. Avoid rapidly starting the same animation instance while a previous run is still composing.
Rendering Pipeline
Engine Tick Loop
The Engine singleton (src/engine/engine.js) drives all animation:
engine.wake()— starts the RAF loop (orsetImmediatein Node.js)tickEngine()— recursive RAF callback:- If
engine._headexists, request next frame and callengine.update() - Otherwise, set
reqId = 0(auto-sleep when no active animations)
- If
engine.update():requestTick(time)— framerate gating viaClock._scheduledTimecomputeDeltaTime(time)— calculate time delta- Walk linked list of active tickables (
_head→_next) - For each non-paused tickable: call
tick()with computed time - Paused tickables: remove from engine, set
_running = false, auto-cancel if completed - Call
additive.update()for blend-mode composition
Per-Frame Render (src/core/render.js)
The render() function handles a single tickable per frame:
- Time clamping — clamp absolute time to
[-delay, duration] - Iteration calculation — compute current loop iteration (bitwise
~~for performance) - Direction resolution — XOR of
_reversedand(_alternate && isOdd)determines effective direction - Playback easing — optional
_easeapplied to iteration time - Callbacks —
onBegin,onLoop,onBeforeUpdatefired at appropriate transitions - Tween rendering — walk child tweens via linked list:
- Compute eased progress:
tween._ease(time / duration) - Interpolate:
lerp(fromNumber, toNumber, easedProgress) - For COLOR/COMPLEX types: interpolate each number component
- Apply
_modifierfunction - Set value on target based on tween type
- Compute eased progress:
- Transform batching — CSS transforms are concatenated per-element into a single
transformstring (stored viatransformsSymbolon the target), then applied once - Composition — for
replacemode, resolved tweens overwrite; forblendmode, additive values are summed across the_prevAdd/_nextAddchain
Note
Date.nowis used instead ofperformance.nowthroughout. The source comments note it is "precise enough for timings calculations, performs slightly faster, and works in Node.js environment."
Document Visibility Handling
The engine automatically pauses on document.hidden and resumes on visibility restore (calling resetTime() on all children to prevent time jumps). This can be disabled via engine.pauseOnDocumentHidden = false.
Requirements & Compatibility
Runtime Requirements
| Requirement | Detail |
|---|---|
| Browsers | Any browser supporting ES2015+ (Map, Symbol, Proxy, WeakMap) |
| Node.js | Requires setImmediate (available natively; no polyfill needed) |
| Optional | Intl.Segmenter for accurate Unicode text splitting (TextSplitter) |
| Optional | ResizeObserver for ScrollContainer dimension tracking |
| Optional | element.animate() for WAAPI bridge |
Build Requirements
| Tool | Version | Purpose |
|---|---|---|
| Node.js | Any recent LTS | Build and test runner |
| Rollup | ^4.9.1 | Bundle ESM, CJS, UMD, IIFE |
| TypeScript | ^5.9.2 | Type declaration generation |
| @rollup/plugin-terser | ^0.4.4 | Minification |
| Mocha | ^10.2.0 | Test framework |
| Chai | ^4.3.10 | Assertion library |
| BrowserSync | ^3.0.4 | Browser test server |
| nodemon | ^3.1.10 | Dev watch mode |
| three | ^0.160.0 | Three.js playground tests only |
Configuration Reference
Engine Configuration
The engine singleton exposes these configuration surfaces:
| Property | Type | Default | Description |
|---|---|---|---|
engine.timeUnit |
'ms' | 's' |
'ms' |
Switches global time scale between milliseconds and seconds. Setting to 's' multiplies globals.timeScale by 0.001 and adjusts default duration. |
engine.speed |
Number |
1 |
Global playback speed multiplier. Affects all active tickables. |
engine.precision |
Number |
4 |
Decimal places for rounding interpolated values. |
engine.fps |
Number |
240 |
Maximum frames per second. Lower values skip frames. |
engine.useDefaultMainLoop |
Boolean |
true |
When false, engine does not auto-start RAF. Call engine.update() manually. |
engine.pauseOnDocumentHidden |
Boolean |
true |
Auto-pause when tab is hidden. |
Global Defaults
engine.defaults (alias for globals.defaults in src/core/globals.js):
| Default | Type | Value | Description |
|---|---|---|---|
duration |
Number |
1000 (ms) |
Default animation duration |
delay |
Number |
0 |
Default delay before start |
ease |
String |
'out(2)' |
Default easing function |
loop |
Number|Boolean |
0 |
Loop count (0 = no loop, true = infinite) |
reversed |
Boolean |
false |
Play in reverse |
alternate |
Boolean |
false |
Alternate direction each loop |
autoplay |
Boolean |
true |
Start immediately on creation |
persist |
Boolean |
false |
Keep WAAPI animations after completion |
composition |
Number |
0 (replace) |
Default composition mode |
modifier |
Function |
v => v |
Value modifier applied after interpolation |
loopDelay |
Number |
0 |
Delay between loop iterations |
playbackRate |
Number |
1 |
Per-animation speed multiplier |
frameRate |
Number |
240 |
Per-animation max FPS |
playbackEase |
Function|null |
null |
Easing applied to overall playback progress |
Tip
Override defaults globally for your entire application:
import { engine } from 'animejs'; engine.defaults.duration = 500; engine.defaults.ease = 'inOut(3)'; engine.timeUnit = 's'; // Switch to seconds globally
Build Configuration
The only environment variable is build (checked in rollup.config.js). When build=true, Rollup produces minified production bundles. The npm run build script sets this automatically.
Build & Development
npm Scripts
| Script | Command | Purpose |
|---|---|---|
npm run dev |
nodemon → rollup -c && tsc |
Watch mode: recompile on source changes |
npm run build |
rm -rf dist && build=true rollup -c && tsc |
Production build (clean + minify) |
npm run test:browser |
browser-sync start --startPath tests/index.html |
Browser tests via BrowserSync |
npm run test:node |
mocha -u tdd --timeout 20000 ./tests/suites/node.test.js |
Node.js test suite |
npm run dev:test |
npm run dev & npm run test:browser |
Dev + browser tests in parallel |
Build Output (dist/)
dist/
├── modules/ ES modules + CJS (per sub-package)
│ ├── index.js Main ESM entry
│ ├── index.cjs Main CJS entry
│ ├── index.d.ts TypeScript declarations
│ ├── animation/
│ ├── timer/
│ ├── timeline/
│ ├── ... (one directory per sub-path export)
│ └── waapi/
└── bundles/ Pre-built bundles
├── anime.umd.js
├── anime.umd.min.js
├── anime.iife.js
└── anime.iife.min.js
Note
The
"files"field in package.json restricts npm publish to thedist/directory only. Source code undersrc/is not included in the published package.
TypeScript Configuration
Two tsconfig files:
| File | Purpose |
|---|---|
tsconfig.json |
Base config (ES module resolution, strict checks) |
tsconfig.types.json |
Declaration generation (-p flag in build script) |
tests/tsconfig.json |
Extends base; maps animejs → dist/modules/index.js for test imports |
Testing
Test Architecture
Tests use Mocha (TDD interface) with Chai assertions. Two test environments:
| Environment | Entry point | Runner |
|---|---|---|
| Browser | tests/index.html |
BrowserSync serves files; Mocha runs in-page |
| Node.js | tests/suites/node.test.js |
mocha CLI with --allow-natives-syntax |
Test suites live in tests/suites/ (31 files, 335,861 chars — the largest directory by character count).
Playground Tests
The tests/playground/ directory contains 20+ interactive test pages covering:
- Playback controls, keyframes, lerp, sandbox
- Layout (including clone variants)
- Timeline (nested, test sets, seek)
- ScrollObserver (onscroll with assets)
- Draggables (callbacks)
- WAAPI (composition, eases, playback, values)
- SVG motion path, scope, timekeeper
- Three.js instanced mesh, benchmark
These are manual/visual tests, not part of the automated suite.
Build Validation
tests/suites/build.test.js validates that all module entry points can be loaded without errors. It dynamically imports each sub-path export and catches module loading failures:
Error loading module ${path}: ${error.message}
Security Analysis
Attack Surface
anime.js is a client-side library with no network I/O, no file system access, and no eval/Function constructor usage. The attack surface is minimal:
| Vector | Risk | Mitigation |
|---|---|---|
| DOM XSS via animation values | Low | Values are set via style property or setAttribute, not innerHTML. Color and unit parsing use regex, not eval. |
| Prototype pollution | Low | mergeObjects() uses spread + for...in with hasOwnProperty guard via isKey(). No deep merge. |
| ReDoS (regex denial of service) | Very Low | Regex patterns are anchored and non-backtracking for the most part. Complex value parsing uses multiple simple patterns rather than nested quantifiers. |
| Supply chain | None | Zero runtime dependencies. |
Symbol-Based Caching
Target metadata is stored using Symbol keys (isRegisteredTargetSymbol, isDomSymbol, isSvgSymbol, transformsSymbol, morphPointsSymbol, proxyTargetSymbol) to avoid property name collisions with user objects.
CSS Variable Handling
CSS custom properties are parsed via cssVariableMatchRgx (/var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/), which correctly extracts variable names and fallback values without executing them.
Operations & Performance
Memory Management
- No garbage collection pressure from tween objects: Tween decomposition reuses pre-allocated objects (
fromTargetObject,toTargetObject) rather than creating new ones per frame. - Linked list vs. array: Using intrusive linked lists for children means O(1) insert/remove without array shifting or splicing.
- Transform batching: CSS transforms are concatenated into a single string per element per frame, avoiding multiple style recalculations.
- Engine auto-sleep: When all animations complete and the linked list is empty, the RAF loop stops (
reqId = 0), consuming zero CPU.
Performance Constants
| Constant | Value | Purpose |
|---|---|---|
minValue |
1e-11 |
Minimum non-zero value (prevents division by zero) |
maxValue |
1e12 |
Infinity replacement for duration clamping |
K |
1000 |
Milliseconds constant |
maxFps |
240 |
Maximum framerate cap |
tickThreshold |
200 (ms) |
Large delta detection threshold (tab switching) |
Framerate Control
The Clock.requestTick(time) method implements frame gating:
requestTick(time) {
if (time < this._scheduledTime) return tickModes.NONE; // Skip frame
// Advance scheduled time by at least one frameDuration
this._scheduledTime += frameDelta < frameDuration ? frameDuration : frameDelta;
return tickModes.AUTO;
}
This allows per-animation fps caps. An animation with fps: 30 inside an engine running at 60fps will only update every other frame.
DevTools Integration
If window.AnimeJSDevTools is present at initialization, the engine registers with it:
- Each Timer/Animation registers via
devTools.register(this, parameters, isInfinite) - Infinite loops are capped to
devTools.maxInfiniteLoopsiterations in dev mode - Multiple anime.js instances are tracked via
window.AnimeJSarray (each pushes a{ version, engine }entry)
Module Deep-Dive
Core Module (src/core/)
The 11-file core module is the foundation everything else builds on:
| File | Purpose |
|---|---|
clock.js |
Clock base class: deltaTime, fps, speed, frame gating |
consts.js |
All enums (tweenTypes, valueTypes, tickModes, compositionTypes), regex patterns, transform lists, Symbol keys |
globals.js |
Singleton state: defaults, scope, globals, devTools, version tracking |
helpers.js |
Type checkers, math utilities (clamp, round, snap, lerp), linked list operations (addChild, removeChild, forEachChildren) |
colors.js |
Color conversion: hex→rgba, rgb→rgba, hsl→rgba. All paths produce [r, g, b, a] arrays. |
render.js |
render() — the per-frame interpolation + value application function. tick() — top-level tick dispatcher. |
styles.js |
CSS property name sanitization, inline style management |
targets.js |
Target resolution: CSS selectors, NodeLists, arrays, objects → normalized TargetsArray. Registration via Symbol caching. |
transforms.js |
CSS transform string building and decomposition |
units.js |
CSS unit conversion (px↔rem↔em↔%) via temporary DOM measurement |
values.js |
Value decomposition, function evaluation, relative value resolution (+=, -=, *=), tween value setup |
Easing System (src/easings/)
The easing subsystem is modular with 7 sub-packages:
| Sub-package | Key exports | Description |
|---|---|---|
eases/ |
eases map, parseEase(), named easings |
Power-based easings: in(p), out(p), inOut(p), outIn(p). String parser handles 'out(2)', 'inOut(3)', etc. |
spring/ |
Spring class, spring() factory |
Physics solver: mass, stiffness, damping, velocity. Auto-computes duration from settling time. |
cubic-bezier/ |
cubicBezier() |
Standard CSS cubic-bezier implementation |
linear/ |
linear() |
CSS linear() equivalent with arbitrary stops |
steps/ |
steps() |
Step easing with jump-start/jump-end/jump-both/jump-none |
irregular/ |
irregular() |
Custom curve from array of points |
| (root) | none |
Identity easing (v => v) |
Spring physics: The Spring class uses a damped harmonic oscillator solver. It iterates until the spring settles within globals.precision tolerance, automatically computing the duration. The solver runs at construction time (not per-frame), producing a lookup-based easing function.
Scroll System (src/events/)
ScrollContainer: Wraps a scrollable element (or document.body for window scroll). Tracks scrollX, scrollY, dimensions, and scale. Uses ResizeObserver for dimension updates. Maintains its own linked list of ScrollObserver children.
ScrollObserver: Links a Timer/Animation/Timeline to scroll position. Sync modes:
| Mode | Behavior |
|---|---|
playPause |
Play when entering threshold, pause when leaving |
linear |
Map scroll position linearly to animation progress |
smooth |
lerp-smoothed scroll-to-progress mapping |
easing |
Apply easing function to scroll-to-progress mapping |
Threshold parsing supports absolute pixels, viewport-relative percentages, and callback functions.
Layout System (src/layout/)
LayoutSnapshot: Captures DOM element positions (bounding rect, computed transforms, margins, padding) for FLIP calculation. Handles both regular elements and SVG.
AutoLayout: Implements FLIP (First-Last-Invert-Play) animation:
- Capture "first" state via
LayoutSnapshot - Apply DOM mutation
- Capture "last" state
- Compute delta (translate + scale)
- Apply inverted delta as starting transform
- Animate to identity
Supports enterFrom, leaveTo, and swapAt states for add/remove/reorder transitions. Internally creates a Timeline (or WAAPI animation) to drive the FLIP.
Draggable System (src/draggable/)
DOMProxy: Lightweight wrapper that gives plain objects a DOM-like interface (getBoundingClientRect, classList, x, y, width, height). Used for non-DOM draggable targets.
Transforms: Helper that resolves the current DOMMatrix for an element's parent chain, computes the inverse matrix, and converts screen-space pointer deltas to local-space deltas. This allows correct drag behavior on transformed/rotated/scaled elements.
Draggable: Full drag implementation with:
- Touch and mouse pointer handling
- Configurable axes (
x,y, or both) - Container bounds with overflow modes
- Snap points (grid-based or array-based)
- Momentum/inertia with spring-based settling
- Cursor management (grab/grabbing states)
- Event callbacks:
onGrab,onDrag,onRelease,onSettle,onSnap,onUpdate
Uses Animatable internally for smooth animated property updates.
Text Splitting (src/text/)
TextSplitter: Segments text content into lines, words, and characters using Intl.Segmenter (with fallback to regex splitting). Features:
- Wraps segments in
<span>elements withdata-line,data-word,data-charattributes - Clone mode: creates duplicate elements offset by
top/bottom/left/rightfor reveal effects - Wrap mode: adds overflow-hidden containers around each segment
- Template customization via
classparameter - Line detection: measures element positions post-split to group characters into actual rendered lines
- Preserves
aria-hiddenon decorative duplicates revert()restores original DOM
WAAPI Bridge (src/waapi/)
WAAPIAnimation: Translates anime.js animation parameters into native Element.animate() calls:
- Converts anime.js easing functions to CSS
linear()strings via sampling - Maps
compositionTypesto WAAPIcompositemodes - Manages a global linked list of active WAAPI animations for composition tracking
- Handles
commitStyles()before cancellation to preserve final values - Supports scroll-linked WAAPI via timeline sync
Easing conversion (parseWAAPIEasing): Caches converted easings in WAAPIEasesLookups. Native CSS timing functions (linear, ease, cubic-bezier(), steps()) pass through directly. Spring and custom easings are sampled to 100 points and converted to linear() strings.
Error Messages
The library produces very few runtime errors, all from specific modules:
| Error | Source | Condition |
|---|---|---|
"Can't morph an SVG of type..." |
src/svg/morphto.js:28 |
morphTo() called on non-path SVG element |
"Can't morph between different SVG types" |
src/svg/morphto.js:32 |
Source and target SVG elements have different tag names |
"Can't morph path..." |
src/svg/morphto.js:36 |
Path data cannot be parsed for morphing |
Warning
getPath()insrc/svg/helpers.jsusesconsole.warn(not throw) when a selector doesn't resolve to a validSVGGeometryElement. This means invalid SVG selectors fail silently with anundefinedreturn rather than throwing.
Code Patterns & Conventions
Coding Style
| Pattern | Usage |
|---|---|
| ES modules | import/export throughout; no CommonJS in source |
| JSDoc types | All parameters and return types annotated; @import syntax for cross-module types |
| No classes for utilities | Factory functions (animate(), createTimeline(), etc.) wrap class constructors |
| Enum via objects | tweenTypes, valueTypes, tickModes, compositionTypes — plain objects with number values |
| Bitwise operators | ~~ for Math.floor, ^ for XOR in direction calculation |
| IIFE singletons | engine and shortTransforms use /*#__PURE__*/(() => ...)() for tree-shaking hints |
| Proxy pattern | SVG drawable, chainable utilities, Animatable property access |
| Symbol for metadata | Target registration and transform caching use Symbol keys |
Naming Conventions
| Convention | Examples |
|---|---|
| Prefixed private properties | _currentTime, _head, _tail, _ease, _speed |
$ prefix for DOM elements |
$el, $scalled, $measure |
| Factory functions | createTimeline(), createAnimatable(), createDraggable(), createScope() |
| Short aliases | K = 1000, isUnd = isUndefined, isFnc = isFunction, isStr = isString |
Tree-Shaking Design
"sideEffects": falsein package.json/*#__PURE__*/annotations on singleton IIFEs- Each module re-exports only from its own
index.js - Sub-path exports allow importing only needed functionality
- No circular dependencies between sibling modules (all share
coreas common dependency)
Known Issues & Community Reports
Open Bugs (from GitHub Issues as of source commit)
| Issue | Summary | Impact |
|---|---|---|
| #1138 | addChild self-referential _prevRep/_nextRep on re-add |
Can cause infinite loops in composition |
| #1157 | Draggables restricted to viewport boundaries with container | Bounds calculation incorrect when container is scrollable |
| #1154 | utils.set parses backgroundImage incorrectly |
Incorrect value decomposition for complex CSS values |
| #1118 | Spring easing: perceived complete callback/duration mismatch | Spring may visually settle before onComplete fires |
| #1114 | SVG fill ignored for color names | Named colors (e.g., red) not recognized in SVG fill animation |
| #1121 | WAAPI synced to timeline: looping bugs | Loop count mismatch between WAAPI and timeline |
| #1120 | WAAPI animation repeats on scroll reset | onScroll WAAPI doesn't properly handle reverse scroll |
| #1119 | Inaccurate viewport height in Safari 12.2.1 | 100lvh unit unsupported in older Safari |
| #1137 | Text scramble animation issue | TextSplitter behavior with dynamic content |
| #1124 | Comment syntax error causing crash | Edge case in source parsing |
Notable Feature Requests
| Issue | Request |
|---|---|
| #1161 | Controlling speed of timeline synced to ScrollObserver |
| #1147 | Custom durations/easings per element with Layout |
| #1017 | React Native support |
| #1007 | ScrollObserver: play immediately if target already in viewport |
| #1141 | Option to suppress logs in module builds |
| #1084 | Improving text char option |
Troubleshooting
Animations Not Starting
- Check autoplay: Default is
true, but if overridden globally viaengine.defaults.autoplay = false, you must call.play()manually. - Scope cleanup: If using
Scope, ensure the scope hasn't been reverted. Reverted animations are cancelled. - Engine paused: Check
engine.paused. Tab visibility changes auto-pause the engine. - Zero duration: A duration of
0orminValuecreates a "setter" (instant jump), not an animation.
WAAPI Animations Disappearing
WAAPI animations call commitStyles() then cancel() when they finish (unless persist: true). If styles aren't sticking:
- Set
persist: trueto keep the WAAPI animation alive - Check that
commitStyles()isn't failing silently (wrapped in try/catch in source)
Transform Conflicts
anime.js batches all CSS transforms for an element into a single transform string per frame. If external code modifies element.style.transform between frames, those changes will be overwritten. Use anime.js for all transform manipulation on animated elements.
Spring Duration Calculation
Springs auto-calculate duration based on settling time. If animations appear to end too early or onComplete fires before visual settling:
- Increase
globals.precision(default 4) for tighter convergence - Adjust spring parameters (reduce
stiffness, increasedamping) - Known issue #1118: perceived duration may not match calculated duration
Node.js Usage
anime.js detects non-browser environments via typeof window !== 'undefined'. In Node.js:
requestAnimationFrame→setImmediatecancelAnimationFrame→clearImmediate- DOM-specific features (CSS, SVG, scroll, text splitting, WAAPI) are unavailable
- Object property animation and timer/timeline features work normally
Quick Reference
Factory Functions
| Function | Module | Returns |
|---|---|---|
animate(targets, params) |
animejs/animation |
JSAnimation |
createTimeline(params) |
animejs/timeline |
Timeline |
createAnimatable(targets, params) |
animejs/animatable |
Animatable |
createDraggable(targets, params) |
animejs/draggable |
Draggable[] |
createScope(params) |
animejs/scope |
Scope |
onScroll(params) |
animejs/events |
ScrollObserver |
waapi(targets, params) |
animejs/waapi |
WAAPIAnimation |
createLayout(targets, params) |
animejs/layout |
AutoLayout |
splitText(targets, params) |
animejs/text |
TextSplitter |
createDrawable(selector, start, end) |
animejs/svg |
DrawableSVGGeometry[] |
createMotionPath(pathEl) |
animejs/svg |
Motion path helper |
morphTo(fromPath, toPath) |
animejs/svg |
Morph easing function |
stagger(value, params) |
animejs/utils |
Stagger function |
spring(params) |
animejs/easings/spring |
Spring easing |
cubicBezier(x1, y1, x2, y2) |
animejs/easings/cubic-bezier |
Easing function |
steps(count, position) |
animejs/easings/steps |
Step easing function |
linear(stops) |
animejs/easings/linear |
Linear easing function |
Timer/Animation Methods
| Method | Available on | Description |
|---|---|---|
.play() |
Timer, JSAnimation, Timeline | Start or restart from beginning |
.pause() |
Timer, JSAnimation, Timeline | Pause at current position |
.resume() |
Timer, JSAnimation, Timeline | Resume from paused position |
.reverse() |
Timer, JSAnimation, Timeline | Reverse playback direction |
.seek(time) |
Timer, JSAnimation, Timeline | Jump to specific time (ms) |
.restart() |
Timer, JSAnimation, Timeline | Reset and play from start |
.reset() |
Timer, JSAnimation, Timeline | Reset to initial state (paused) |
.cancel() |
Timer, JSAnimation, Timeline | Cancel and remove from engine |
.revert() |
Timer, JSAnimation, Timeline | Cancel, restore original values, remove composition |
.stretch(newDuration) |
Timer, JSAnimation, Timeline | Scale duration proportionally |
.then |
Timer, JSAnimation, Timeline | Promise interface (resolves on complete) |
.add(targets, params, position) |
Timeline | Add animation at position |
.sync(animation, position) |
Timeline | Sync existing animation to timeline |
.set(targets, params, position) |
Timeline | Instant property set at position |
.call(callback, position) |
Timeline | Execute callback at position |
.label(name, position) |
Timeline | Named position marker |
.remove(targets) |
Timeline | Remove targets from timeline |
Utility Functions
| Function | Module | Description |
|---|---|---|
get(target, property, unit) |
animejs/utils |
Get current animated value |
set(targets, properties) |
animejs/utils |
Set values immediately |
stagger(value, params) |
animejs/utils |
Generate staggered values |
clamp(v, min, max) |
animejs/utils |
Clamp value to range |
round(v, decimals) |
animejs/utils |
Round to decimal places |
snap(v, increment) |
animejs/utils |
Snap to nearest increment |
lerp(start, end, factor) |
animejs/utils |
Linear interpolation |
damp(start, end, factor, dt) |
animejs/utils |
Frame-rate-independent lerp |
wrap(v, min, max) |
animejs/utils |
Wrap value within range |
mapRange(inLow, inHigh, outLow, outHigh, v) |
animejs/utils |
Map value between ranges |
degToRad(v) |
animejs/utils |
Degrees to radians |
radToDeg(v) |
animejs/utils |
Radians to degrees |
roundPad(v, decimals) |
animejs/utils |
Round with zero-padding |
padStart(v, length, char) |
animejs/utils |
String padding (start) |
padEnd(v, length, char) |
animejs/utils |
String padding (end) |
random(min, max, decimals) |
animejs/utils |
Random number in range |
randomPick(array) |
animejs/utils |
Random array element |
shuffle(array) |
animejs/utils |
Fisher-Yates shuffle |
All chainable utilities support a fluent API via Proxy-based chaining:
import { clamp, round, mapRange } from 'animejs/utils';
const transform = mapRange(0, 100, -1, 1).clamp(-0.5, 0.5).round(2);
transform(75); // 0.5
Contributing
Repository Structure
src/ Source modules (ES module)
├── core/ Foundation (11 files)
├── animation/ JSAnimation + composition
├── timer/ Timer base class
├── timeline/ Timeline sequencing
├── engine/ RAF loop singleton
├── animatable/ Reactive animation
├── draggable/ Drag interaction
├── events/ Scroll system
├── layout/ FLIP animations
├── scope/ Framework integration
├── text/ Text splitting
├── svg/ SVG utilities
├── waapi/ WAAPI bridge
├── easings/ Easing functions (7 sub-packages)
├── utils/ Math + DOM utilities
├── types/ JSDoc type definitions
└── index.js Main barrel export
tests/
├── suites/ Automated tests (31 files)
├── playground/ Interactive visual tests
└── index.html Browser test entry
Development Workflow
npm install— install dev dependenciesnpm run dev— watch mode with auto-recompile- Make changes in
src/ npm run test:browser— verify in browsernpm run test:node— verify in Node.jsnpm run build— production build
Adding a New Module
- Create directory under
src/withindex.jsre-export - Add sub-path export to
package.json"exports"map (types, require, import, default) - Export from
src/index.jsif it should be in the main bundle - Add corresponding test file in
tests/suites/ - Rebuild to verify tree-shaking works correctly