
Animejs
- 1.6k installs
- 629 repo stars
- Updated November 20, 2025
- freshtechbro/claudedesignskills
animejs is an agent skill for versatile javascript animation engine for dom, css, svg, and javascript objects. use when creating timeline-based animations, stagger effects, svg morphing, keyframe sequences,.
About
The animejs skill is designed for versatile JavaScript animation engine for DOM, CSS, SVG, and JavaScript objects. Use when creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences,. Anime.js Lightweight JavaScript animation library with powerful timeline and stagger capabilities for web animations. Overview Anime.js (pronounced "Anime JS") is a versatile animation engine that works with DOM elements, CSS properties, SVG attributes, and JavaScript objects. Invoke when the user creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences, or complex choreographed animations.
- Timeline-based animation sequences with precise choreography.
- Staggered animations across multiple elements.
- SVG path morphing and drawing animations.
- Keyframe animations with percentage-based timing.
- Framework-agnostic animation (works with React, Vue, vanilla JS).
Animejs by the numbers
- 1,612 all-time installs (skills.sh)
- +130 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #225 of 1,888 Design & UI/UX skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
animejs capabilities & compatibility
- Capabilities
- timeline based animation sequences with precise · staggered animations across multiple elements · svg path morphing and drawing animations · keyframe animations with percentage based timing
- Use cases
- frontend
What animejs says it does
Versatile JavaScript animation engine for DOM, CSS, SVG, and JavaScript objects. Use when creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences, or
Versatile JavaScript animation engine for DOM, CSS, SVG, and JavaScript objects. Use when creating timeline-based animations, stagger effects, SVG morphing, key
npx skills add https://github.com/freshtechbro/claudedesignskills --skill animejsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 629 |
| Security audit | 3 / 3 scanners passed |
| Last updated | November 20, 2025 |
| Repository | freshtechbro/claudedesignskills ↗ |
How do I versatile javascript animation engine for dom, css, svg, and javascript objects. use when creating timeline-based animations, stagger effects, svg morphing, keyframe sequences,?
Versatile JavaScript animation engine for DOM, CSS, SVG, and JavaScript objects. Use when creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences,.
Who is it for?
Developers using animejs workflows documented in SKILL.md.
Skip if: Skip when the task falls outside animejs scope or needs a different stack.
When should I use this skill?
User creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences, or complex choreographed animations.
What you get
Completed animejs workflow with documented commands, files, and expected deliverables.
- Vite project scaffold
- animejs dependency setup
- Starter animation template files
Files
Anime.js
Lightweight JavaScript animation library with powerful timeline and stagger capabilities for web animations.
Overview
Anime.js (pronounced "Anime JS") is a versatile animation engine that works with DOM elements, CSS properties, SVG attributes, and JavaScript objects. Unlike React-specific libraries, Anime.js works with vanilla JavaScript and any framework.
When to use this skill:
- Timeline-based animation sequences with precise choreography
- Staggered animations across multiple elements
- SVG path morphing and drawing animations
- Keyframe animations with percentage-based timing
- Framework-agnostic animation (works with React, Vue, vanilla JS)
- Complex easing functions (spring, steps, cubic-bezier)
Core features:
- Timeline sequencing with relative positioning
- Powerful stagger utilities (grid, from center, easing)
- SVG morphing and path animations
- Built-in spring physics easing
- Keyframe support with flexible timing
- Small bundle size (~9KB gzipped)
Core Concepts
Basic Animation
The anime() function creates animations:
import anime from 'animejs'
anime({
targets: '.element',
translateX: 250,
rotate: '1turn',
duration: 800,
easing: 'easeInOutQuad'
})Targets
Multiple ways to specify animation targets:
// CSS selector
anime({ targets: '.box' })
// DOM elements
anime({ targets: document.querySelectorAll('.box') })
// Array of elements
anime({ targets: [el1, el2, el3] })
// JavaScript object
const obj = { x: 0 }
anime({ targets: obj, x: 100 })Animatable Properties
CSS Properties:
anime({
targets: '.element',
translateX: 250,
scale: 2,
opacity: 0.5,
backgroundColor: '#FFF'
})CSS Transforms (Individual):
anime({
targets: '.element',
translateX: 250, // Individual transform
rotate: '1turn', // Not 'transform: rotate()'
scale: 2
})SVG Attributes:
anime({
targets: 'path',
d: 'M10 80 Q 77.5 10, 145 80', // Path morphing
fill: '#FF0000',
strokeDashoffset: [anime.setDashoffset, 0] // Line drawing
})JavaScript Objects:
const obj = { value: 0 }
anime({
targets: obj,
value: 100,
round: 1,
update: () => console.log(obj.value)
})Timeline
Create complex sequences with precise control:
const timeline = anime.timeline({
duration: 750,
easing: 'easeOutExpo'
})
timeline
.add({
targets: '.box1',
translateX: 250
})
.add({
targets: '.box2',
translateX: 250
}, '-=500') // Start 500ms before previous animation ends
.add({
targets: '.box3',
translateX: 250
}, '+=200') // Start 200ms after previous animation endsCommon Patterns
1. Stagger Animation (Sequential Reveal)
anime({
targets: '.stagger-element',
translateY: [100, 0],
opacity: [0, 1],
delay: anime.stagger(100), // Increase delay by 100ms
easing: 'easeOutQuad',
duration: 600
})2. Stagger from Center
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [14, 5],
from: 'center', // Also: 'first', 'last', index, [x, y]
axis: 'x' // Also: 'y', null
}),
easing: 'easeOutQuad'
})3. SVG Line Drawing
anime({
targets: 'path',
strokeDashoffset: [anime.setDashoffset, 0],
easing: 'easeInOutQuad',
duration: 2000,
delay: (el, i) => i * 250
})4. SVG Morphing
anime({
targets: '#morphing-path',
d: [
{ value: 'M10 80 Q 77.5 10, 145 80' }, // Start shape
{ value: 'M10 80 Q 77.5 150, 145 80' } // End shape
],
duration: 2000,
easing: 'easeInOutQuad',
loop: true,
direction: 'alternate'
})5. Timeline Sequence
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.title',
translateY: [-50, 0],
opacity: [0, 1]
})
.add({
targets: '.subtitle',
translateY: [-30, 0],
opacity: [0, 1]
}, '-=500')
.add({
targets: '.button',
scale: [0, 1],
opacity: [0, 1]
}, '-=300')6. Keyframe Animation
anime({
targets: '.element',
keyframes: [
{ translateX: 100 },
{ translateY: 100 },
{ translateX: 0 },
{ translateY: 0 }
],
duration: 4000,
easing: 'easeInOutQuad',
loop: true
})7. Scroll-Triggered Animation
const animation = anime({
targets: '.scroll-element',
translateY: [100, 0],
opacity: [0, 1],
easing: 'easeOutQuad',
autoplay: false
})
window.addEventListener('scroll', () => {
const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight)
animation.seek(animation.duration * scrollPercent)
})Integration Patterns
With React
import { useEffect, useRef } from 'react'
import anime from 'animejs'
function AnimatedComponent() {
const ref = useRef(null)
useEffect(() => {
const animation = anime({
targets: ref.current,
translateX: 250,
duration: 800,
easing: 'easeInOutQuad'
})
return () => animation.pause()
}, [])
return <div ref={ref}>Animated</div>
}With Vue
export default {
mounted() {
anime({
targets: this.$el,
translateX: 250,
duration: 800
})
}
}Path Following Animation
const path = anime.path('#motion-path')
anime({
targets: '.element',
translateX: path('x'),
translateY: path('y'),
rotate: path('angle'),
easing: 'linear',
duration: 2000,
loop: true
})Advanced Techniques
Spring Easing
anime({
targets: '.element',
translateX: 250,
easing: 'spring(1, 80, 10, 0)', // mass, stiffness, damping, velocity
duration: 2000
})Steps Easing
anime({
targets: '.element',
translateX: 250,
easing: 'steps(5)',
duration: 1000
})Custom Bezier
anime({
targets: '.element',
translateX: 250,
easing: 'cubicBezier(.5, .05, .1, .3)',
duration: 1000
})Direction and Loop
anime({
targets: '.element',
translateX: 250,
direction: 'alternate', // 'normal', 'reverse', 'alternate'
loop: true, // or number of iterations
easing: 'easeInOutQuad'
})Playback Control
const animation = anime({
targets: '.element',
translateX: 250,
autoplay: false
})
animation.play()
animation.pause()
animation.restart()
animation.reverse()
animation.seek(500) // Seek to 500msPerformance Optimization
Use Transform and Opacity
// ✅ Good: GPU-accelerated
anime({
targets: '.element',
translateX: 250,
opacity: 0.5
})
// ❌ Avoid: Triggers layout
anime({
targets: '.element',
left: '250px',
width: '500px'
})Batch Similar Animations
// ✅ Single animation for multiple targets
anime({
targets: '.multiple-elements',
translateX: 250
})
// ❌ Avoid: Multiple separate animations
elements.forEach(el => {
anime({ targets: el, translateX: 250 })
})Use will-change for Complex Animations
.animated-element {
will-change: transform, opacity;
}Disable autoplay for Scroll Animations
const animation = anime({
targets: '.element',
translateX: 250,
autoplay: false // Control manually
})Common Pitfalls
1. Forgetting Unit Types
// ❌ Wrong: No unit
anime({ targets: '.element', width: 200 })
// ✅ Correct: Include unit
anime({ targets: '.element', width: '200px' })2. Using CSS transform Property Directly
// ❌ Wrong: Can't animate transform string
anime({ targets: '.element', transform: 'translateX(250px)' })
// ✅ Correct: Individual transform properties
anime({ targets: '.element', translateX: 250 })3. Not Handling Animation Cleanup
// ❌ Wrong: Animation continues after unmount
useEffect(() => {
anime({ targets: ref.current, translateX: 250 })
}, [])
// ✅ Correct: Pause on cleanup
useEffect(() => {
const anim = anime({ targets: ref.current, translateX: 250 })
return () => anim.pause()
}, [])4. Animating Too Many Elements
// ❌ Avoid: Animating 1000+ elements
anime({ targets: '.many-items', translateX: 250 }) // 1000+ elements
// ✅ Better: Use CSS animations for large sets
// Or reduce element count with virtualization5. Incorrect Timeline Timing
// ❌ Wrong: Missing offset operator
.add({ targets: '.el2' }, '500') // Treated as absolute time
// ✅ Correct: Use relative operators
.add({ targets: '.el2' }, '-=500') // Relative to previous
.add({ targets: '.el3' }, '+=200') // Relative to previous6. Overusing Loop
// ❌ Avoid: Infinite loops drain battery
anime({
targets: '.element',
rotate: '1turn',
loop: true,
duration: 1000
})
// ✅ Better: Use CSS animations for infinite loops
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}Resources
Scripts
animation_generator.py- Generate Anime.js animation boilerplate (8 types)timeline_builder.py- Build complex timeline sequences
References
api_reference.md- Complete Anime.js API documentationstagger_guide.md- Stagger utilities and patternstimeline_guide.md- Timeline sequencing deep dive
Assets
starter_animejs/- Vanilla JS + Vite template with examplesexamples/- Real-world patterns (SVG morphing, stagger grids, timelines)
Related Skills
- gsap-scrolltrigger - More powerful timeline features and scroll integration
- motion-framer - React-specific declarative animations
- react-spring-physics - Physics-based spring animations
- lightweight-3d-effects - Simple 3D effects (Zdog, Vanta.js)
Anime.js vs GSAP: Use Anime.js for SVG-heavy animations, simpler projects, or when bundle size matters. Use GSAP for complex scroll-driven experiences, advanced timelines, and professional-grade control.
Anime.js vs Framer Motion: Use Anime.js for framework-agnostic projects or when working outside React. Use Framer Motion for React-specific declarative animations with gesture integration.
Anime.js - Assets
This directory contains starter templates and example documentation for Anime.js animations.
Contents
Starter Template (Recommended)
For a complete Anime.js starter template with Vite:
# Create new project with Vite (vanilla JS)
npm create vite@latest my-anime-app -- --template vanilla
# Navigate and install
cd my-anime-app
npm install
# Add Anime.js
npm install animejsOfficial Examples
The Anime.js team maintains excellent examples at:
- Documentation: https://animejs.com/documentation/
- CodePen Examples: https://codepen.io/collection/DxpqGJ/
- Official Repository: https://github.com/juliangarnier/anime
Recommended Examples by Category
Basic Animations:
- Simple animation: https://codepen.io/juliangarnier/pen/KRwwOL
- Property parameters: https://codepen.io/juliangarnier/pen/LpWPgj
- Function-based values: https://codepen.io/juliangarnier/pen/gmOwJX
Stagger Animations:
- Basic stagger: https://codepen.io/juliangarnier/pen/PboRJN
- Stagger from center: https://codepen.io/juliangarnier/pen/WNNwQa
- Grid stagger: https://codepen.io/juliangarnier/pen/JXaKpP
- Stagger easing: https://codepen.io/juliangarnier/pen/QMMmQK
Timeline Animations:
- Basic timeline: https://codepen.io/juliangarnier/pen/grVWYq
- Timeline offsets: https://codepen.io/juliangarnier/pen/xLOXJX
- Timeline controls: https://codepen.io/juliangarnier/pen/oWjmWd
SVG Animations:
- Line drawing: https://codepen.io/juliangarnier/pen/XdqyNw
- Path morphing: https://codepen.io/juliangarnier/pen/mWEOmL
- Motion path: https://codepen.io/juliangarnier/pen/NqYKQL
Advanced Patterns:
- Keyframes: https://codepen.io/juliangarnier/pen/QMMmQK
- Scroll-driven: https://codepen.io/juliangarnier/pen/ZqyEJw
- Custom easing: https://codepen.io/juliangarnier/pen/YBBRvG
Quick Start Template
Minimal Anime.js setup:
package.json
{
"name": "animejs-starter",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"animejs": "^3.2.2"
},
"devDependencies": {
"vite": "^5.0.8"
}
}index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime.js Starter</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<h1>Anime.js Animation Demo</h1>
<div class="example basic-animation">
<h2>Basic Animation</h2>
<div class="box box1"></div>
<button id="basic-btn">Play</button>
</div>
<div class="example stagger-animation">
<h2>Stagger Animation</h2>
<div class="stagger-grid">
<div class="stagger-item"></div>
<div class="stagger-item"></div>
<div class="stagger-item"></div>
<div class="stagger-item"></div>
<div class="stagger-item"></div>
<div class="stagger-item"></div>
</div>
<button id="stagger-btn">Play</button>
</div>
<div class="example timeline-animation">
<h2>Timeline Animation</h2>
<div class="timeline-elements">
<div class="timeline-box box1"></div>
<div class="timeline-box box2"></div>
<div class="timeline-box box3"></div>
</div>
<button id="timeline-btn">Play</button>
</div>
</div>
<script type="module" src="/main.js"></script>
</body>
</html>main.js
import anime from 'animejs/lib/anime.es.js'
// Basic Animation
document.getElementById('basic-btn').addEventListener('click', () => {
anime({
targets: '.box1',
translateX: 250,
rotate: '1turn',
scale: [0.75, 1],
duration: 800,
easing: 'easeInOutQuad'
})
})
// Stagger Animation
document.getElementById('stagger-btn').addEventListener('click', () => {
anime({
targets: '.stagger-item',
scale: [0, 1],
delay: anime.stagger(100),
easing: 'easeOutElastic(1, .8)',
duration: 600
})
})
// Timeline Animation
document.getElementById('timeline-btn').addEventListener('click', () => {
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.timeline-box.box1',
translateX: 250
})
.add({
targets: '.timeline-box.box2',
translateX: 250
}, '-=500')
.add({
targets: '.timeline-box.box3',
translateX: 250
}, '-=500')
})style.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
padding: 2rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
margin-bottom: 3rem;
font-size: 3rem;
}
.example {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 12px;
padding: 2rem;
margin-bottom: 2rem;
}
h2 {
margin-bottom: 1.5rem;
font-size: 1.5rem;
}
.box {
width: 80px;
height: 80px;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
border-radius: 8px;
margin-bottom: 1rem;
}
.stagger-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
margin-bottom: 1rem;
}
.stagger-item {
width: 100%;
aspect-ratio: 1;
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
border-radius: 8px;
}
.timeline-elements {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
.timeline-box {
width: 60px;
height: 60px;
}
.timeline-box.box1 { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
.timeline-box.box2 { background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); }
.timeline-box.box3 { background: linear-gradient(135deg, #fa709a 0%, #fee140 100%); }
button {
background: white;
color: #764ba2;
border: none;
padding: 0.75rem 2rem;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s;
}
button:hover {
transform: scale(1.05);
}
button:active {
transform: scale(0.95);
}Common Patterns
Pattern 1: Sequential List Reveal
anime({
targets: '.list-item',
translateY: [30, 0],
opacity: [0, 1],
delay: anime.stagger(80),
easing: 'easeOutQuad',
duration: 600
})Pattern 2: Grid Expand from Center
anime({
targets: '.grid-square',
scale: [0, 1],
delay: anime.stagger(30, {
grid: [10, 10],
from: 'center'
}),
easing: 'easeOutElastic(1, .8)',
duration: 600
})Pattern 3: SVG Line Drawing
anime({
targets: 'path',
strokeDashoffset: [anime.setDashoffset, 0],
easing: 'easeInOutQuad',
duration: 2000,
delay: (el, i) => i * 250
})Pattern 4: Timeline Sequence
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.title',
translateY: [-50, 0],
opacity: [0, 1]
})
.add({
targets: '.subtitle',
translateY: [-30, 0],
opacity: [0, 1]
}, '-=500')
.add({
targets: '.button',
scale: [0, 1]
}, '-=300')Framework Integration
With React
import { useEffect, useRef } from 'react'
import anime from 'animejs/lib/anime.es.js'
function AnimatedComponent() {
const ref = useRef(null)
useEffect(() => {
const animation = anime({
targets: ref.current,
translateX: 250,
duration: 800,
easing: 'easeInOutQuad'
})
return () => animation.pause()
}, [])
return <div ref={ref}>Animated</div>
}With Vue
export default {
mounted() {
anime({
targets: this.$el,
translateX: 250,
duration: 800
})
}
}TypeScript Support
For TypeScript projects, install types:
npm install --save-dev @types/animejsPerformance Tips
1. Use transforms and opacity - GPU-accelerated properties 2. Batch similar animations - One animation for multiple targets 3. Add will-change to CSS for complex animations 4. Use autoplay: false for scroll-driven animations 5. Pause animations on cleanup in frameworks 6. Limit element count - Stagger works best with <100 elements
Additional Resources
- Official Documentation: https://animejs.com/documentation/
- API Reference: https://animejs.com/documentation/#cssProperties
- GitHub Repository: https://github.com/juliangarnier/anime
- CodePen Collection: https://codepen.io/collection/DxpqGJ/
- Community Examples: https://animejs.com/documentation/#communityShowcase
---
For more patterns and reference documentation, see:
api_reference.md- Complete Anime.js APIstagger_guide.md- Stagger utilities deep divetimeline_guide.md- Timeline sequencing guide
Anime.js API Reference
Complete API documentation for Anime.js v3+.
Table of Contents
- anime() Function
- Targets
- Properties
- Property Parameters
- Animation Parameters
- Timeline
- Stagger
- Easing Functions
- Helpers
- Callbacks
---
anime() Function
Main function to create animations.
anime(options)Returns: Animation instance with playback controls.
---
Targets
Specify what to animate.
CSS Selector:
targets: '.element'
targets: '#myId'
targets: 'div.className'DOM Element/NodeList:
targets: document.querySelector('.element')
targets: document.querySelectorAll('.elements')JavaScript Object:
const obj = { prop: 0 }
anime({ targets: obj, prop: 100 })Array:
targets: [el1, el2, el3]
targets: [obj1, obj2]---
Properties
CSS Properties
Transform (individual):
translateX: 250 // pixels
translateY: '10em' // units
translateZ: '50vh'
rotate: '1turn' // turns, deg, rad
rotateX, rotateY, rotateZ
scale: 2
scaleX, scaleY, scaleZ
skew: '10deg'
skewX, skewY
perspective: 1000Other CSS:
opacity: 0.5
backgroundColor: '#FFF' // colors
borderRadius: '50%'
width: '100px'
left: '50%'
// Any valid CSS property (camelCase)SVG Attributes
d: 'M10 80 Q 77.5 10, 145 80' // Path morphing
points: '64 68 8 400 ...' // Polygon points
strokeDashoffset: 100
fill: '#FF0000'
r: 50 // Circle radius
cx, cy // Circle center
// Any SVG attributeDOM Attributes
value: 100 // Input value
volume: 0.5 // Audio/video
textContent: 'Hello' // Text content
innerHTML: '<div></div>'
// Any DOM attributeJavaScript Object Properties
const obj = { x: 0, y: 0 }
anime({
targets: obj,
x: 100,
y: 200
})---
Property Parameters
Define how each property animates.
Value Formats
Single Value:
translateX: 250 // Animate from current to 250From-To Array:
translateX: [0, 250] // Explicit from/to
opacity: [0, 1]Function-Based:
translateX: (el, i) => 50 + (i * 50) // Different per element
delay: (el, i, total) => i * 100Keyframes:
translateX: [
{ value: 100, duration: 500 },
{ value: 200, duration: 500 },
{ value: 0, duration: 500 }
]Units
'250px' // Pixels
'10em' // Ems
'50%' // Percentage
'100vh' // Viewport
'1turn' // Turns
'45deg' // Degrees
'1.5rad' // RadiansRelative Values
translateX: '+=250' // Add 250 to current
translateX: '-=100' // Subtract 100
translateX: '*=2' // Multiply by 2Colors
'#FF0000' // Hex
'rgb(255, 0, 0)' // RGB
'rgba(255, 0, 0, 0.5)' // RGBA
'hsl(0, 100%, 50%)' // HSL---
Animation Parameters
Global animation settings.
anime({
targets: '.element',
translateX: 250,
// Timing
duration: 1000, // Milliseconds
delay: 500, // Start delay
endDelay: 200, // End delay
// Easing
easing: 'easeInOutQuad', // Built-in easing
// Playback
direction: 'normal', // 'normal', 'reverse', 'alternate'
loop: 3, // Number or true for infinite
autoplay: true, // Auto-start
// Advanced
round: 1, // Round values to 1 decimal
specific Property Parameters
specificProperty: {
value: 100,
duration: 2000,
delay: 500,
easing: 'linear'
}
})---
Timeline
Chain multiple animations with precise control.
Create Timeline
const tl = anime.timeline({
duration: 1000,
easing: 'easeOutExpo',
loop: true
})Add Animations
tl.add({
targets: '.el1',
translateX: 250
})
.add({
targets: '.el2',
translateX: 250
}, '-=500') // OffsetTimeline Parameters
All animation parameters plus:
anime.timeline({
duration: 1000, // Default duration
delay: 500, // Default delay
easing: 'linear', // Default easing
direction: 'normal',
loop: false,
autoplay: true
})Offset
Control when animations start:
'+=500' // Start 500ms after previous ends
'-=500' // Start 500ms before previous ends
500 // Start at absolute time 500msTimeline Methods
tl.play()
tl.pause()
tl.restart()
tl.reverse()
tl.seek(1000) // Seek to 1000ms
tl.add(animation) // Add animation---
Stagger
Distribute delays across multiple elements.
Basic Stagger
delay: anime.stagger(100) // Increment by 100msStagger Options
delay: anime.stagger(100, {
start: 500, // Start delay
from: 'center', // 'first', 'last', 'center', index, [x, y]
direction: 'normal', // 'normal', 'reverse'
easing: 'easeOutQuad', // Easing for delay
grid: [10, 10], // Grid dimensions
axis: 'x' // 'x', 'y', null
})Stagger Values
// Stagger delays
delay: anime.stagger(100)
// Stagger values
translateX: anime.stagger([0, 100, 200, 300])
// Stagger ranges
scale: anime.stagger([1, 2], { from: 'center' })Grid Stagger
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [14, 5],
from: 'center'
})
})---
Easing Functions
Built-in Easings
Linear:
'linear'Ease In/Out:
'easeInQuad', 'easeOutQuad', 'easeInOutQuad'
'easeInCubic', 'easeOutCubic', 'easeInOutCubic'
'easeInQuart', 'easeOutQuart', 'easeInOutQuart'
'easeInQuint', 'easeOutQuint', 'easeInOutQuint'
'easeInSine', 'easeOutSine', 'easeInOutSine'
'easeInExpo', 'easeOutExpo', 'easeInOutExpo'
'easeInCirc', 'easeOutCirc', 'easeInOutCirc'
'easeInBack', 'easeOutBack', 'easeInOutBack'
'easeInElastic', 'easeOutElastic', 'easeInOutElastic'
'easeInBounce', 'easeOutBounce', 'easeInOutBounce'Custom Easings
Cubic Bezier:
easing: 'cubicBezier(.5, .05, .1, .3)'Spring Physics:
easing: 'spring(1, 80, 10, 0)'
// mass, stiffness, damping, velocitySteps:
easing: 'steps(5)' // 5 stepsLinear Keyframes:
easing: 'linear(0, 0.5, 1)'---
Helpers
anime.setDashoffset(el)
Calculate strokeDashoffset for line drawing:
anime({
targets: 'path',
strokeDashoffset: [anime.setDashoffset, 0]
})anime.path(path)
Get coordinates and angle from SVG path:
const path = anime.path('#motion-path')
anime({
targets: '.element',
translateX: path('x'),
translateY: path('y'),
rotate: path('angle')
})anime.random(min, max)
Generate random value:
translateX: () => anime.random(0, 100)anime.get(targets, prop)
Get current value:
const currentX = anime.get('.element', 'translateX')anime.set(targets, prop)
Set value without animating:
anime.set('.element', { translateX: 100, opacity: 0.5 })---
Callbacks
Animation Callbacks
anime({
targets: '.element',
translateX: 250,
begin: (anim) => {
console.log('Animation begins')
},
update: (anim) => {
console.log('Animation updates', anim.progress)
},
complete: (anim) => {
console.log('Animation completes')
},
loopBegin: (anim) => {
console.log('Loop begins')
},
loopComplete: (anim) => {
console.log('Loop completes')
},
changeBegin: (anim) => {
console.log('Direction changes')
},
changeComplete: (anim) => {
console.log('Direction change completes')
}
})Callback Parameters
anim Object:
anim.progress // Animation progress (0-100)
anim.currentTime // Current time (ms)
anim.duration // Total duration (ms)
anim.remaining // Remaining loops
anim.reversed // Direction reversed?
anim.paused // Animation paused?
anim.began // Animation began?
anim.finished // Animation finished?---
Animation Instance
Properties
const animation = anime({ ... })
animation.progress // 0-100
animation.currentTime // Milliseconds
animation.duration // Milliseconds
animation.remaining // Remaining loops
animation.reversed // Boolean
animation.paused // Boolean
animation.began // Boolean
animation.finished // Boolean
animation.animatables // Array of targets
animation.animations // Array of property animationsMethods
animation.play()
animation.pause()
animation.restart()
animation.reverse()
animation.seek(time) // Seek to time (ms or %)
animation.tick(time) // Manual tick---
Examples
Basic Animation
anime({
targets: '.box',
translateX: 250,
rotate: '1turn',
duration: 800,
easing: 'easeInOutQuad'
})From-To Animation
anime({
targets: '.element',
translateX: [0, 250],
opacity: [0, 1],
duration: 1000
})Keyframe Animation
anime({
targets: '.element',
keyframes: [
{ translateX: 100 },
{ translateY: 100 },
{ translateX: 0 },
{ translateY: 0 }
],
duration: 4000,
loop: true
})Timeline Animation
const tl = anime.timeline()
tl.add({
targets: '.box1',
translateX: 250
})
.add({
targets: '.box2',
translateX: 250
}, '-=500')Stagger Animation
anime({
targets: '.stagger-item',
translateY: [-50, 0],
opacity: [0, 1],
delay: anime.stagger(100, { from: 'center' })
})SVG Path Animation
anime({
targets: '#morphing-path',
d: 'M10 80 Q 77.5 150, 145 80',
duration: 2000,
easing: 'easeInOutQuad'
})JavaScript Object Animation
const obj = { count: 0 }
anime({
targets: obj,
count: 100,
round: 1,
update: () => {
document.querySelector('.counter').textContent = obj.count
}
})Anime.js Stagger Guide
Complete guide to Anime.js stagger utilities for creating sequential and coordinated animations.
Overview
Stagger distributes animation delays across multiple elements, creating cascading or wave-like effects. Anime.js provides powerful stagger options including grid-based staggering, directional control, and custom easing.
Basic Stagger
Time-Based Stagger
anime({
targets: '.element',
translateX: 250,
delay: anime.stagger(100) // Increment delay by 100ms
})Result: Each element animates 100ms after the previous one.
Value-Based Stagger
anime({
targets: '.element',
translateX: anime.stagger([0, 100, 200, 300])
})Result: Each element animates to a different translateX value.
Stagger Options
Complete Syntax
anime.stagger(value, {
start: 0, // Starting delay (ms)
from: 'first', // Starting point
direction: 'normal', // Direction of stagger
easing: 'linear', // Easing for stagger progression
grid: [rows, cols], // Grid dimensions
axis: null // Grid axis ('x', 'y', or null)
})---
Stagger From
Control where the stagger starts.
from: 'first' (default)
Start from the first element:
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, { from: 'first' })
})from: 'last'
Start from the last element:
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, { from: 'last' })
})from: 'center'
Start from the center and expand outward:
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, { from: 'center' })
})from: index
Start from a specific index:
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, { from: 5 }) // Start from 6th element (0-indexed)
})from: [x, y]
Start from specific grid coordinates:
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [10, 10],
from: [5, 5] // Start from center of grid
})
})---
Grid Stagger
Stagger elements arranged in a grid pattern.
Basic Grid
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [14, 5] // 14 columns, 5 rows
})
})Grid with from: 'center'
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [14, 5],
from: 'center'
})
})Result: Animates from center outward in all directions.
Grid with Axis
Control which axis dominates the stagger:
// Horizontal waves
anime({
targets: '.grid-item',
translateY: [-20, 0],
delay: anime.stagger(30, {
grid: [10, 10],
from: 'center',
axis: 'x' // Stagger primarily along x-axis
})
})
// Vertical waves
anime({
targets: '.grid-item',
translateY: [-20, 0],
delay: anime.stagger(30, {
grid: [10, 10],
from: 'center',
axis: 'y' // Stagger primarily along y-axis
})
})---
Stagger Direction
direction: 'normal' (default)
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, { direction: 'normal' })
})direction: 'reverse'
Reverse the stagger order:
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, {
from: 'first',
direction: 'reverse' // Last to first
})
})---
Stagger Easing
Apply easing to the stagger progression itself.
anime({
targets: '.element',
translateY: [-50, 0],
delay: anime.stagger(100, {
easing: 'easeOutQuad' // Ease the delay distribution
})
})Effect: Early elements have shorter delays, later elements have longer delays (exponential distribution).
---
Stagger Start
Add an initial delay before stagger begins.
anime({
targets: '.element',
scale: [0, 1],
delay: anime.stagger(100, {
start: 500 // Wait 500ms before starting stagger
})
})Result:
- Element 1: 500ms delay
- Element 2: 600ms delay
- Element 3: 700ms delay
---
Common Patterns
1. Sequential List Reveal
anime({
targets: '.list-item',
translateY: [30, 0],
opacity: [0, 1],
delay: anime.stagger(80),
easing: 'easeOutQuad'
})2. Grid Expand from Center
anime({
targets: '.grid-square',
scale: [0, 1],
delay: anime.stagger(30, {
grid: [10, 10],
from: 'center'
}),
easing: 'easeOutElastic(1, .8)'
})3. Wave Effect
anime({
targets: '.wave-element',
translateY: [
{ value: -20, duration: 300 },
{ value: 0, duration: 300 }
],
delay: anime.stagger(50),
loop: true
})4. Diagonal Wipe
anime({
targets: '.tile',
opacity: [0, 1],
translateX: [-50, 0],
delay: anime.stagger(20, {
grid: [10, 10],
from: [0, 0], // Top-left corner
axis: null // Both axes
})
})5. Text Character Reveal
// Split text into characters first
const textWrapper = document.querySelector('.text')
textWrapper.innerHTML = textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>")
anime({
targets: '.letter',
translateY: [100, 0],
opacity: [0, 1],
delay: anime.stagger(30),
easing: 'easeOutExpo'
})6. Circular Stagger
anime({
targets: '.circle-item',
scale: [0, 1],
delay: anime.stagger(100, {
from: 'center',
easing: 'linear'
}),
rotate: anime.stagger([0, 360])
})7. Alternating Direction
anime({
targets: '.row',
translateX: (el, i) => i % 2 === 0 ? [-250, 0] : [250, 0],
opacity: [0, 1],
delay: anime.stagger(100)
})---
Stagger with Different Properties
Stagger Delays, Same Values
anime({
targets: '.element',
translateX: 250, // Same for all
delay: anime.stagger(100) // Different delays
})Stagger Values, Same Timing
anime({
targets: '.element',
translateX: anime.stagger([0, 50, 100, 150]), // Different values
duration: 1000 // Same duration
})Stagger Both
anime({
targets: '.element',
translateX: anime.stagger([0, 50, 100, 150]),
delay: anime.stagger(100)
})---
Advanced Techniques
Dynamic Grid Calculation
function getGridSize() {
const elements = document.querySelectorAll('.grid-item')
const cols = Math.ceil(Math.sqrt(elements.length))
const rows = Math.ceil(elements.length / cols)
return [cols, rows]
}
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: getGridSize(),
from: 'center'
})
})Stagger with Function Values
anime({
targets: '.element',
translateX: anime.stagger((el, i, total) => {
// Custom calculation
return (i / total) * 100
}),
delay: anime.stagger(100)
})Multi-Property Stagger
anime({
targets: '.element',
translateX: anime.stagger([0, 100]),
translateY: anime.stagger([0, 50]),
rotate: anime.stagger([0, 360]),
delay: anime.stagger(100, { from: 'center' })
})---
Performance Tips
1. Use transforms - Stagger translateX, translateY, scale, rotate for GPU acceleration 2. Limit element count - Stagger works best with <100 elements 3. Avoid layout properties - Don't stagger width, height, left, top 4. Use `will-change` - Add will-change: transform for smoother animations 5. Batch similar animations - One stagger for multiple properties is more efficient than separate animations
---
Common Mistakes
❌ Wrong: Stagger on Single Element
anime({
targets: '.single-element', // Only one element
scale: [0, 1],
delay: anime.stagger(100) // No effect
})✅ Correct: Multiple Elements
anime({
targets: '.multiple-elements', // Multiple elements
scale: [0, 1],
delay: anime.stagger(100)
})❌ Wrong: Grid Without Dimensions
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
from: 'center' // Missing grid dimensions!
})
})✅ Correct: Grid With Dimensions
anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [10, 10],
from: 'center'
})
})---
Debugging Tips
Log stagger values:
anime({
targets: '.element',
translateX: 250,
delay: anime.stagger(100),
begin: (anim) => {
anim.animatables.forEach((animatable, i) => {
console.log(`Element ${i}: delay ${animatable.delay}ms`)
})
}
})Visualize stagger:
// Add data-index to elements
document.querySelectorAll('.element').forEach((el, i) => {
el.setAttribute('data-index', i)
})---
Resources
- Official Stagger Documentation: https://animejs.com/documentation/#stagger
- Grid Stagger Demo: https://codepen.io/juliangarnier/pen/JXaKpP
- Stagger Examples: https://animejs.com/documentation/#staggeringBasics
Anime.js Timeline Guide
Complete guide to creating complex animation sequences with Anime.js timelines.
Overview
Timelines allow you to chain multiple animations with precise control over timing and sequencing. They provide a declarative way to choreograph complex multi-step animations.
Creating a Timeline
Basic Timeline
const timeline = anime.timeline()Timeline with Default Parameters
const timeline = anime.timeline({
duration: 1000, // Default duration for all animations
easing: 'easeOutExpo', // Default easing
loop: false, // Loop entire timeline
direction: 'normal', // 'normal', 'reverse', 'alternate'
autoplay: true // Auto-start
})---
Adding Animations
.add() Method
timeline.add({
targets: '.element',
translateX: 250,
duration: 800
})Chaining Animations
timeline
.add({
targets: '.box1',
translateX: 250
})
.add({
targets: '.box2',
translateX: 250
})
.add({
targets: '.box3',
translateX: 250
})---
Timeline Offsets
Control when each animation starts relative to the previous one.
Absolute Time
timeline.add({
targets: '.element',
translateX: 250
}, 1000) // Start at 1000ms from timeline startRelative to Previous (+=)
timeline
.add({
targets: '.box1',
translateX: 250,
duration: 1000
})
.add({
targets: '.box2',
translateX: 250
}, '+=500') // Start 500ms AFTER box1 completesOverlap with Previous (-=)
timeline
.add({
targets: '.box1',
translateX: 250,
duration: 1000
})
.add({
targets: '.box2',
translateX: 250
}, '-=500') // Start 500ms BEFORE box1 completes (overlap)---
Common Patterns
1. Sequential Animations
Each animation starts after the previous completes:
const tl = anime.timeline()
tl.add({
targets: '.title',
translateY: [-50, 0],
opacity: [0, 1]
})
.add({
targets: '.subtitle',
translateY: [-30, 0],
opacity: [0, 1]
})
.add({
targets: '.button',
scale: [0, 1]
})2. Overlapping Animations
Create smooth transitions between animations:
const tl = anime.timeline()
tl.add({
targets: '.section1',
opacity: [1, 0],
duration: 600
})
.add({
targets: '.section2',
opacity: [0, 1],
duration: 600
}, '-=300') // Overlap by 300ms for crossfade3. Staggered Timeline
Combine timeline with stagger:
const tl = anime.timeline()
tl.add({
targets: '.card',
translateY: [100, 0],
opacity: [0, 1],
delay: anime.stagger(100)
})
.add({
targets: '.button',
scale: [0, 1]
}, '-=200')4. Multi-Stage Animation
Complex multi-step sequence:
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.modal',
scale: [0, 1],
opacity: [0, 1]
})
.add({
targets: '.modal-header',
translateY: [-20, 0],
opacity: [0, 1]
}, '-=500')
.add({
targets: '.modal-body',
translateY: [20, 0],
opacity: [0, 1]
}, '-=400')
.add({
targets: '.modal-footer',
opacity: [0, 1]
}, '-=300')5. Looping Timeline
const tl = anime.timeline({
loop: true,
direction: 'alternate'
})
tl.add({
targets: '.ball',
translateY: -200,
duration: 1000
})
.add({
targets: '.ball',
translateX: 200,
duration: 1000
})6. Loading Sequence
const tl = anime.timeline()
tl.add({
targets: '.loader-bg',
scaleY: [0, 1],
duration: 400,
easing: 'easeInOutQuad'
})
.add({
targets: '.loader-text',
opacity: [0, 1],
translateY: [20, 0],
duration: 600
}, '-=200')
.add({
targets: '.loader-spinner',
rotate: '1turn',
duration: 800,
loop: 3
}, '-=400')
.add({
targets: '.loader',
opacity: 0,
duration: 400
}, '+=500')
.add({
targets: '.content',
translateY: [50, 0],
opacity: [0, 1],
duration: 600
})7. Page Transition
function pageTransition(oldPage, newPage) {
const tl = anime.timeline()
tl.add({
targets: oldPage,
translateX: [0, -100],
opacity: [1, 0],
duration: 400,
easing: 'easeInQuad'
})
.add({
targets: newPage,
translateX: [100, 0],
opacity: [0, 1],
duration: 400,
easing: 'easeOutQuad'
}, '-=200')
return tl
}---
Timeline Controls
Playback Methods
const tl = anime.timeline({ autoplay: false })
tl.play() // Play from current position
tl.pause() // Pause
tl.restart() // Restart from beginning
tl.reverse() // Reverse direction
tl.seek(2000) // Seek to 2000msProperties
tl.duration // Total duration
tl.currentTime // Current time
tl.progress // Progress (0-100)
tl.reversed // Is reversed?
tl.paused // Is paused?
tl.began // Has begun?
tl.finished // Is finished?---
Advanced Techniques
Labels
Mark specific points in the timeline:
const tl = anime.timeline()
tl.add({
targets: '.intro',
opacity: [0, 1]
})
.add({}, '+=500') // Add label "intro-done" at this point
.add({
targets: '.content',
translateY: [50, 0],
opacity: [0, 1]
})
// Seek to label
tl.seek('intro-done')Nested Timelines
function createIntroTimeline() {
const tl = anime.timeline({ autoplay: false })
tl.add({
targets: '.logo',
scale: [0, 1]
})
.add({
targets: '.tagline',
opacity: [0, 1]
})
return tl
}
const mainTimeline = anime.timeline()
mainTimeline.add(createIntroTimeline())Timeline Callbacks
const tl = anime.timeline({
begin: () => console.log('Timeline begins'),
update: (tl) => console.log('Progress:', tl.progress),
complete: () => console.log('Timeline completes')
})Conditional Timeline
const tl = anime.timeline()
tl.add({
targets: '.element1',
translateX: 250
})
if (condition) {
tl.add({
targets: '.element2',
opacity: [0, 1]
})
}
tl.add({
targets: '.element3',
scale: [0, 1]
})---
Timeline vs Individual Animations
Without Timeline (Hard to Manage)
anime({
targets: '.box1',
translateX: 250,
duration: 1000
})
setTimeout(() => {
anime({
targets: '.box2',
translateX: 250,
duration: 1000
})
}, 1000)
setTimeout(() => {
anime({
targets: '.box3',
translateX: 250,
duration: 1000
})
}, 2000)With Timeline (Clean & Maintainable)
const tl = anime.timeline()
tl.add({
targets: '.box1',
translateX: 250,
duration: 1000
})
.add({
targets: '.box2',
translateX: 250,
duration: 1000
})
.add({
targets: '.box3',
translateX: 250,
duration: 1000
})---
Performance Optimization
1. Use Relative Offsets
// ✅ Good: Flexible timing
.add({...}, '-=500')
// ❌ Avoid: Brittle absolute timing
.add({...}, 1500)2. Batch Similar Animations
// ✅ Good: Single animation
tl.add({
targets: ['.el1', '.el2', '.el3'],
translateX: 250
})
// ❌ Avoid: Multiple separate animations
tl.add({ targets: '.el1', translateX: 250 })
.add({ targets: '.el2', translateX: 250 })
.add({ targets: '.el3', translateX: 250 })3. Set Default Parameters
// ✅ Good: DRY
const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 800
})
// ❌ Avoid: Repetition
tl.add({ targets: '.el1', easing: 'easeOutExpo', duration: 800 })
.add({ targets: '.el2', easing: 'easeOutExpo', duration: 800 })---
Common Mistakes
❌ Wrong: Missing Offset Operator
tl.add({
targets: '.box1',
translateX: 250
})
.add({
targets: '.box2',
translateX: 250
}, '500') // Treated as absolute time!✅ Correct: Use Relative Operator
tl.add({
targets: '.box1',
translateX: 250
})
.add({
targets: '.box2',
translateX: 250
}, '+=500') // Relative to previous❌ Wrong: Forgetting autoplay: false
const tl = anime.timeline() // Starts immediately
// Later...
button.addEventListener('click', () => {
tl.play() // Already playing!
})✅ Correct: Disable autoplay
const tl = anime.timeline({ autoplay: false })
button.addEventListener('click', () => {
tl.play() // Now it works
})---
Real-World Examples
Hero Section Animation
const heroTimeline = anime.timeline({
easing: 'easeOutExpo'
})
heroTimeline
.add({
targets: '.hero-bg',
scale: [1.2, 1],
opacity: [0, 1],
duration: 1200
})
.add({
targets: '.hero-title',
translateY: [100, 0],
opacity: [0, 1],
duration: 800
}, '-=800')
.add({
targets: '.hero-subtitle',
translateY: [50, 0],
opacity: [0, 1],
duration: 600
}, '-=400')
.add({
targets: '.hero-cta',
scale: [0, 1],
duration: 400
}, '-=200')Card Flip Animation
function flipCard(card) {
const tl = anime.timeline({ autoplay: false })
tl.add({
targets: card.querySelector('.front'),
rotateY: [0, 90],
duration: 300,
easing: 'easeInQuad'
})
.add({
targets: card.querySelector('.back'),
rotateY: [-90, 0],
duration: 300,
easing: 'easeOutQuad'
}, '-=0')
return tl
}Notification Toast
function showToast(toast) {
const tl = anime.timeline()
tl.add({
targets: toast,
translateX: [400, 0],
opacity: [0, 1],
duration: 400,
easing: 'easeOutBack'
})
.add({
targets: toast,
opacity: [1, 0],
duration: 300,
easing: 'easeInQuad'
}, '+=3000')
return tl
}---
Debugging Timelines
Log Timeline Progress
const tl = anime.timeline({
update: (tl) => {
console.log(`Progress: ${tl.progress.toFixed(2)}%`)
console.log(`Current time: ${tl.currentTime}ms`)
}
})Visualize Timeline
const tl = anime.timeline()
tl.add({
targets: '.box1',
translateX: 250,
duration: 1000,
begin: () => console.log('[0ms] Box1 begins'),
complete: () => console.log('[1000ms] Box1 completes')
})
.add({
targets: '.box2',
translateX: 250,
duration: 1000,
begin: () => console.log('[1000ms] Box2 begins'),
complete: () => console.log('[2000ms] Box2 completes')
}, '-=500')---
Resources
- Official Timeline Documentation: https://animejs.com/documentation/#timeline
- Timeline Examples: https://codepen.io/collection/DxpqGJ/
- Advanced Sequencing: https://animejs.com/documentation/#timelineBasics
#!/usr/bin/env python3
"""
Anime.js Animation Generator
Generates Anime.js animation boilerplate code for common animation patterns.
Usage:
./animation_generator.py # Interactive mode
./animation_generator.py --type stagger # Generate stagger animation
./animation_generator.py --type timeline # Generate timeline sequence
Animation Types:
basic - Simple translateX/Y, opacity animation
stagger - Sequential reveal with stagger
grid-stagger - Grid-based stagger animation
svg-line - SVG line drawing animation
svg-morph - SVG path morphing animation
timeline - Multi-step timeline sequence
keyframe - Keyframe animation with multiple steps
scroll - Scroll-triggered animation
"""
import sys
ANIMATION_TYPES = {
'basic': {
'name': 'Basic Animation',
'description': 'Simple translateX/Y, opacity animation',
'code': '''anime({
targets: '.element',
translateX: 250,
rotate: '1turn',
opacity: [0, 1],
duration: 800,
easing: 'easeInOutQuad'
})'''
},
'stagger': {
'name': 'Stagger Animation',
'description': 'Sequential reveal with stagger effect',
'code': '''anime({
targets: '.stagger-element',
translateY: [100, 0],
opacity: [0, 1],
delay: anime.stagger(100), // Increment delay by 100ms
easing: 'easeOutQuad',
duration: 600
})'''
},
'grid-stagger': {
'name': 'Grid Stagger Animation',
'description': 'Grid-based stagger from center',
'code': '''anime({
targets: '.grid-item',
scale: [0, 1],
delay: anime.stagger(50, {
grid: [14, 5], // 14 columns, 5 rows
from: 'center', // Start from center
axis: 'x' // Primary axis
}),
easing: 'easeOutElastic(1, .8)',
duration: 600
})'''
},
'svg-line': {
'name': 'SVG Line Drawing',
'description': 'SVG path line drawing animation',
'code': '''anime({
targets: 'path',
strokeDashoffset: [anime.setDashoffset, 0],
easing: 'easeInOutQuad',
duration: 2000,
delay: (el, i) => i * 250
})'''
},
'svg-morph': {
'name': 'SVG Path Morphing',
'description': 'Morph between SVG path shapes',
'code': '''anime({
targets: '#morphing-path',
d: [
{ value: 'M10 80 Q 77.5 10, 145 80' }, // Start shape
{ value: 'M10 80 Q 77.5 150, 145 80' } // End shape
],
duration: 2000,
easing: 'easeInOutQuad',
loop: true,
direction: 'alternate'
})'''
},
'timeline': {
'name': 'Timeline Sequence',
'description': 'Multi-step timeline with overlapping animations',
'code': '''const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.title',
translateY: [-50, 0],
opacity: [0, 1]
})
.add({
targets: '.subtitle',
translateY: [-30, 0],
opacity: [0, 1]
}, '-=500') // Start 500ms before previous ends
.add({
targets: '.button',
scale: [0, 1],
opacity: [0, 1]
}, '-=300')'''
},
'keyframe': {
'name': 'Keyframe Animation',
'description': 'Multiple keyframes for complex motion',
'code': '''anime({
targets: '.element',
keyframes: [
{ translateX: 100 },
{ translateY: 100 },
{ translateX: 0 },
{ translateY: 0 }
],
duration: 4000,
easing: 'easeInOutQuad',
loop: true
})'''
},
'scroll': {
'name': 'Scroll-Triggered Animation',
'description': 'Animation controlled by scroll position',
'code': '''const animation = anime({
targets: '.scroll-element',
translateY: [100, 0],
opacity: [0, 1],
easing: 'easeOutQuad',
autoplay: false
})
window.addEventListener('scroll', () => {
const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight)
animation.seek(animation.duration * scrollPercent)
})'''
}
}
def print_header():
"""Print script header"""
print("\n" + "="*60)
print("Anime.js Animation Generator")
print("="*60 + "\n")
def list_animation_types():
"""List all available animation types"""
print("Available Animation Types:\n")
for key, anim in ANIMATION_TYPES.items():
print(f" {key:15} - {anim['description']}")
print()
def generate_animation(anim_type):
"""Generate animation code for given type"""
if anim_type not in ANIMATION_TYPES:
print(f"Error: Unknown animation type '{anim_type}'")
print("Use --list to see available types")
sys.exit(1)
anim = ANIMATION_TYPES[anim_type]
print(f"\n{anim['name']}")
print("-" * 60)
print(f"\n{anim['description']}\n")
print("Generated Code:")
print("-" * 60)
print(anim['code'])
print("\n" + "="*60 + "\n")
def interactive_mode():
"""Run in interactive mode"""
print_header()
list_animation_types()
print("Enter animation type (or 'quit' to exit): ", end='')
choice = input().strip().lower()
if choice == 'quit':
sys.exit(0)
generate_animation(choice)
def main():
"""Main entry point"""
args = sys.argv[1:]
# No arguments - interactive mode
if not args:
interactive_mode()
return
# Parse arguments
if '--list' in args:
print_header()
list_animation_types()
return
if '--type' in args:
try:
type_index = args.index('--type')
anim_type = args[type_index + 1]
print_header()
generate_animation(anim_type)
except IndexError:
print("Error: --type requires an animation type")
print("Usage: ./animation_generator.py --type <type>")
sys.exit(1)
return
# Help or unknown arguments
print(__doc__)
if __name__ == '__main__':
main()
#!/usr/bin/env python3
"""
Anime.js Timeline Builder
Build complex Anime.js timeline sequences with interactive configuration.
Usage:
./timeline_builder.py # Interactive mode
./timeline_builder.py --preset hero # Use preset configuration
./timeline_builder.py --preset modal # Modal animation sequence
Timeline Presets:
hero - Hero section entrance animation
modal - Modal popup with content reveal
cards - Card stagger with button reveal
loader - Loading sequence with spinner
page - Page transition animation
toast - Notification toast animation
menu - Menu open/close animation
"""
import sys
TIMELINE_PRESETS = {
'hero': {
'name': 'Hero Section Animation',
'description': 'Hero background, title, subtitle, and CTA reveal',
'code': '''const heroTimeline = anime.timeline({
easing: 'easeOutExpo'
})
heroTimeline
.add({
targets: '.hero-bg',
scale: [1.2, 1],
opacity: [0, 1],
duration: 1200
})
.add({
targets: '.hero-title',
translateY: [100, 0],
opacity: [0, 1],
duration: 800
}, '-=800') // Overlap by 800ms
.add({
targets: '.hero-subtitle',
translateY: [50, 0],
opacity: [0, 1],
duration: 600
}, '-=400')
.add({
targets: '.hero-cta',
scale: [0, 1],
duration: 400
}, '-=200')'''
},
'modal': {
'name': 'Modal Popup Animation',
'description': 'Modal entrance with header, body, and footer reveal',
'code': '''const tl = anime.timeline({
easing: 'easeOutExpo',
duration: 750
})
tl.add({
targets: '.modal',
scale: [0, 1],
opacity: [0, 1]
})
.add({
targets: '.modal-header',
translateY: [-20, 0],
opacity: [0, 1]
}, '-=500')
.add({
targets: '.modal-body',
translateY: [20, 0],
opacity: [0, 1]
}, '-=400')
.add({
targets: '.modal-footer',
opacity: [0, 1]
}, '-=300')'''
},
'cards': {
'name': 'Card Grid Animation',
'description': 'Cards stagger in, then button appears',
'code': '''const tl = anime.timeline()
tl.add({
targets: '.card',
translateY: [100, 0],
opacity: [0, 1],
delay: anime.stagger(100),
duration: 600,
easing: 'easeOutQuad'
})
.add({
targets: '.button',
scale: [0, 1],
duration: 400,
easing: 'easeOutBack'
}, '-=200')'''
},
'loader': {
'name': 'Loading Sequence',
'description': 'Loader background, text, spinner, then fade to content',
'code': '''const tl = anime.timeline()
tl.add({
targets: '.loader-bg',
scaleY: [0, 1],
duration: 400,
easing: 'easeInOutQuad'
})
.add({
targets: '.loader-text',
opacity: [0, 1],
translateY: [20, 0],
duration: 600
}, '-=200')
.add({
targets: '.loader-spinner',
rotate: '1turn',
duration: 800,
loop: 3
}, '-=400')
.add({
targets: '.loader',
opacity: 0,
duration: 400
}, '+=500')
.add({
targets: '.content',
translateY: [50, 0],
opacity: [0, 1],
duration: 600
})'''
},
'page': {
'name': 'Page Transition',
'description': 'Slide out old page, slide in new page',
'code': '''function pageTransition(oldPage, newPage) {
const tl = anime.timeline()
tl.add({
targets: oldPage,
translateX: [0, -100],
opacity: [1, 0],
duration: 400,
easing: 'easeInQuad'
})
.add({
targets: newPage,
translateX: [100, 0],
opacity: [0, 1],
duration: 400,
easing: 'easeOutQuad'
}, '-=200') // Overlap by 200ms for smooth transition
return tl
}'''
},
'toast': {
'name': 'Toast Notification',
'description': 'Toast slides in, stays, then fades out',
'code': '''function showToast(toast) {
const tl = anime.timeline()
tl.add({
targets: toast,
translateX: [400, 0],
opacity: [0, 1],
duration: 400,
easing: 'easeOutBack'
})
.add({
targets: toast,
opacity: [1, 0],
duration: 300,
easing: 'easeInQuad'
}, '+=3000') // Wait 3 seconds before fading out
return tl
}'''
},
'menu': {
'name': 'Menu Open Animation',
'description': 'Menu slides in with staggered items',
'code': '''const tl = anime.timeline({ autoplay: false })
tl.add({
targets: '.menu-overlay',
translateX: ['-100%', 0],
duration: 400,
easing: 'easeOutQuad'
})
.add({
targets: '.menu-item',
translateX: [-50, 0],
opacity: [0, 1],
delay: anime.stagger(80),
duration: 500,
easing: 'easeOutExpo'
}, '-=200')
// Play on button click
document.querySelector('.menu-button').addEventListener('click', () => {
tl.play()
})'''
}
}
def print_header():
"""Print script header"""
print("\n" + "="*60)
print("Anime.js Timeline Builder")
print("="*60 + "\n")
def list_presets():
"""List all available timeline presets"""
print("Available Timeline Presets:\n")
for key, preset in TIMELINE_PRESETS.items():
print(f" {key:12} - {preset['description']}")
print()
def generate_timeline(preset_name):
"""Generate timeline code for given preset"""
if preset_name not in TIMELINE_PRESETS:
print(f"Error: Unknown preset '{preset_name}'")
print("Use --list to see available presets")
sys.exit(1)
preset = TIMELINE_PRESETS[preset_name]
print(f"\n{preset['name']}")
print("-" * 60)
print(f"\n{preset['description']}\n")
print("Generated Timeline:")
print("-" * 60)
print(preset['code'])
print("\n" + "="*60 + "\n")
def generate_custom_timeline():
"""Generate custom timeline with user input"""
print("\nCustom Timeline Builder")
print("-" * 60)
print("\nEnter number of animation steps: ", end='')
try:
num_steps = int(input().strip())
except ValueError:
print("Error: Invalid number")
sys.exit(1)
if num_steps < 1 or num_steps > 10:
print("Error: Number of steps must be between 1 and 10")
sys.exit(1)
print("\nGenerating timeline with", num_steps, "steps...\n")
# Generate timeline code
code = "const tl = anime.timeline({\n"
code += " duration: 750,\n"
code += " easing: 'easeOutExpo'\n"
code += "})\n\n"
for i in range(num_steps):
code += f"tl.add({{\n"
code += f" targets: '.element-{i+1}',\n"
code += f" translateY: [50, 0],\n"
code += f" opacity: [0, 1]\n"
if i > 0:
code += f"}}, '-=300') // Step {i+1}\n"
else:
code += f"}}) // Step {i+1}\n"
if i < num_steps - 1:
code += "\n"
print("Generated Timeline:")
print("-" * 60)
print(code)
print("\n" + "="*60 + "\n")
def interactive_mode():
"""Run in interactive mode"""
print_header()
list_presets()
print("Enter preset name (or 'custom' for custom builder, 'quit' to exit): ", end='')
choice = input().strip().lower()
if choice == 'quit':
sys.exit(0)
elif choice == 'custom':
generate_custom_timeline()
else:
generate_timeline(choice)
def main():
"""Main entry point"""
args = sys.argv[1:]
# No arguments - interactive mode
if not args:
interactive_mode()
return
# Parse arguments
if '--list' in args:
print_header()
list_presets()
return
if '--preset' in args:
try:
preset_index = args.index('--preset')
preset_name = args[preset_index + 1]
print_header()
generate_timeline(preset_name)
except IndexError:
print("Error: --preset requires a preset name")
print("Usage: ./timeline_builder.py --preset <name>")
sys.exit(1)
return
# Help or unknown arguments
print(__doc__)
if __name__ == '__main__':
main()
Related skills
How it compares
Pick animejs for lightweight DOM tweening prototypes; use CSS-only or Framer Motion skills when animations must integrate deeply with React component lifecycles.
FAQ
What does animejs do?
Versatile JavaScript animation engine for DOM, CSS, SVG, and JavaScript objects. Use when creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences,.
When should I use animejs?
User creating timeline-based animations, stagger effects, SVG morphing, keyframe sequences, or complex choreographed animations.
Is animejs safe to install?
Review the Security Audits panel on this page before installing in production.