Anime.js SVG & Motion Paths — Step-by-Step Tutorial
Anime.js SVG animations bring graphics to life — moving objects along curves, morphing one shape into another, and drawing paths progressively — all with the same simple API you already know.
What You’ll Learn
By the end of this tutorial, you’ll animate elements along SVG paths using getPointAtLength(), morph between different shapes with path interpolation, create line-drawing effects with stroke-dashoffset, and animate SVG transforms and viewBox.
Why SVG Animation Matters
SVG (Scalable Vector Graphics) is the standard format for icons, logos, charts, illustrations, and data visualizations on the web. Unlike raster images (PNG, JPG), SVGs are resolution-independent, small in file size, and every element is accessible to JavaScript — meaning you can animate individual points, paths, and shapes.
Security note: Understanding Animejs Svg Motion helps build more secure applications — a core principle at DodaTech, where tools like Durga Antivirus Pro and Doda Browser rely on solid implementation practices.
Think of the loading animations you see everywhere — the spinning circles, the progress rings, the morphing logos. Those are SVG animations. Without a library like Anime.js, each one would require complex JavaScript math.
Real-world use: Durga Antivirus Pro uses SVG line-drawing animations for its “scan complete” checkmark — the circle draws around, then the checkmark stroke appears. This same technique powers animated icons, logo reveals, and data visualization transitions across the web.
Where This Fits in Your Learning Path
flowchart LR
A["Getting Started"] --> B["Animation Controls"]
B --> C["**SVG & Motion Paths**"]
C --> D["Staggering & Synchronization"]
D --> E["Complex Web Animations"]
style C fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
Understanding SVG Coordinates
Before we animate, let’s understand how SVG positioning works. Unlike HTML where elements are placed by CSS layout, SVG uses a coordinate system:
(0,0) ──────────→ x increases ────→
│
│ <circle cx="100" cy="80" r="40" />
│
↓ (100, 80) is the center
y
increasescx,cy— Center x and y of a circler— Radiusx,y— Top-left position of a rectangled— Path data (the “drawing instructions” for a<path>)viewBox— The visible area of the SVG
Anime.js can animate all of these using its standard API.
Motion Along a Path
Anime.js 3.x doesn’t have a built-in motionPath property. Instead, you create a progress value and use the update callback to sample the path at each frame.
Think of it as having a train on a track. The path is the track, and you’re moving the train along it by advancing a progress counter. At each step, you ask the path: “What point is at this distance along your length?”
const path = document.querySelector('#track')
const dot = document.querySelector('#dot')
const pathLen = path.getTotalLength()
anime({
targets: {}, // We're not animating a DOM property directly
progress: [0, pathLen], // Animate a synthetic value
duration: 3000,
loop: true,
easing: 'linear',
update: function(anim) {
const point = path.getPointAtLength(anim.currentValue)
dot.setAttribute('cx', point.x)
dot.setAttribute('cy', point.y)
}
})Step-by-step breakdown:
path.getTotalLength()— Gets the total length of the path in pixels. This is our animation range.progress: [0, pathLen]— We animate a custom propertyprogressfrom 0 to the path’s full length.update: function(anim)— This fires every frame (60fps).anim.currentValuegives us the currentprogressvalue.path.getPointAtLength(len)— SVG’s built-in method. Give it a distance along the path, and it returns{ x, y }coordinates.dot.setAttribute('cx', point.x)— Move the dot to the computed position.
Rotating to Face the Path Direction
To make the element rotate as it follows curves (like a car on a road), calculate the angle between two nearby points:
function getAngle(path, len) {
const p1 = path.getPointAtLength(Math.max(0, len - 1))
const p2 = path.getPointAtLength(Math.min(path.getTotalLength(), len + 1))
return Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI
}
anime({
targets: {},
progress: [0, pathLen],
duration: 4000,
loop: true,
easing: 'linear',
update: function(anim) {
const len = Math.min(anim.currentValue, pathLen)
const point = path.getPointAtLength(len)
const angle = getAngle(path, len)
dot.setAttribute('transform',
`translate(${point.x}, ${point.y}) rotate(${angle})`)
}
})What getAngle does: It samples the path 1px before and 1px after the current position, then uses Math.atan2 (a trigonometry function) to calculate the angle between those two points. This gives the tangent direction at the current point.
Path Morphing (Shape-Shifting)
Path morphing animates the d attribute of a <path> element, smoothly transitioning between two shapes.
Critical rule: The two paths must have the same number and types of commands (same count of M, C, Q, L, Z). If one path has 3 cubic curves and the other has 2, Anime.js can’t interpolate them.
anime({
targets: '#morphPath',
d: [
{ value: 'M 30 100 C 30 50, 170 50, 170 100 C 170 150, 30 150, 30 100 Z' },
{ value: 'M 100 30 C 150 30, 170 70, 170 100 C 170 130, 150 170, 100 170 C 50 170, 30 130, 30 100 C 30 70, 50 30, 100 30 Z' }
],
duration: 2000,
easing: 'easeInOutQuad',
direction: 'alternate',
loop: true
})What’s actually happening: Anime.js parses both d strings into arrays of numbers, then interpolates each corresponding number independently. Command C 30 50, 170 50, 170 100 becomes six numbers — 30, 50, 170, 50, 170, 100 — and each is animated to its counterpart in the target path.
Controlling Multi-Step Morphs
You can morph through multiple intermediate shapes:
anime({
targets: '#morphPath',
d: [
{ value: circlePath },
{ value: squarePath },
{ value: trianglePath },
{ value: circlePath }
],
duration: 3000,
easing: 'easeOutExpo'
})Each { value } object is a keyframe. The animation moves from one to the next, then to the next, etc.
Line Drawing (Stroke Animation)
Line drawing creates the illusion of a path being drawn by a pen. It works by manipulating SVG’s stroke-dasharray and stroke-dashoffset properties:
const path = document.querySelector('#line')
const length = path.getTotalLength()
// Set up the initial state: dashed line with gap equal to full length
path.style.strokeDasharray = length
path.style.strokeDashoffset = length
anime({
targets: path,
strokeDashoffset: [length, 0],
duration: 3000,
easing: 'easeInOutSine'
})How the trick works:
| State | stroke-dasharray | stroke-dashoffset | What you see |
|---|---|---|---|
| Initial | 300 (full length) | 300 | Nothing — the dash is shifted entirely out of view |
| Midway | 300 | 150 | First half of the path is visible |
| Complete | 300 | 0 | Entire path is visible |
The strokeDashoffset is the “scroll position” of the dashed pattern. When it equals the path length, the visible portion is shifted entirely off-screen.
Multiple Simultaneous Line Drawings
When animating multiple paths, compute each path’s length individually:
const paths = document.querySelectorAll('.draw-line')
paths.forEach(path => {
const len = path.getTotalLength()
path.style.strokeDasharray = len
path.style.strokeDashoffset = len
})
anime({
targets: paths,
strokeDashoffset: function(el) {
return [el.getTotalLength(), 0]
},
duration: 2500,
delay: function(el, i) { return i * 400 },
easing: 'easeOutExpo'
})Using a function callback for strokeDashoffset lets each element start from its own length, even if paths are different sizes. The delay function staggers the start times — each path starts drawing 400ms after the previous one.
SVG Transforms
SVG elements support the same transform properties as HTML elements:
anime({
targets: 'svg circle',
translateX: 100,
translateY: 50,
scale: 1.5,
rotate: 180,
duration: 1500
})Animating viewBox
The viewBox attribute controls the visible portion of the SVG canvas. Animating it creates zoom/pan effects:
anime({
targets: 'svg',
viewBox: '0 0 500 500',
duration: 2000,
easing: 'easeInOutQuad'
})For individual viewBox values, use a custom property and update:
anime({
targets: {},
zoom: [0, 200],
duration: 2000,
update: function(anim) {
const v = Math.round(anim.currentValue)
svg.setAttribute('viewBox', `${v} ${v} 200 200`)
}
})This zooms into the top-left corner of the SVG.
Common Mistakes Beginners Make
1. Morphing paths with incompatible structures
// Wrong: first path uses C (cubic), second uses Q (quadratic)
const path1 = 'M 50 50 C 80 20, 120 20, 150 50'
const path2 = 'M 50 50 Q 100 20, 150 50'
// Correct: both use same command types
const path1 = 'M 50 50 C 80 20, 120 20, 150 50'
const path2 = 'M 50 50 C 60 80, 140 80, 150 50'Always match the command structure exactly. Export from an SVG editor to ensure consistency.
2. Forgetting to set stroke properties before line drawing
// Wrong: path is already fully visible
anime({ targets: path, strokeDashoffset: [len, 0] })
// Correct: set dasharray and dashoffset BEFORE the animation
path.style.strokeDasharray = len
path.style.strokeDashoffset = len
anime({ targets: path, strokeDashoffset: [len, 0] })Without pre-setting these properties, the path appears fully drawn from the start, and no animation is visible.
3. Assuming motionPath is built-in
Anime.js 3.x does NOT include a built-in motionPath property. Use the update callback with getPointAtLength() as shown above, or install the anime-path plugin.
4. Using inconsistent path data formatting
// Can cause parsing issues
const d = 'M10 20 C30 40,50 60,70 80'
// More reliable with consistent spacing
const d = 'M 10 20 C 30 40, 50 60, 70 80'5. Animating SVG fill without the right syntax
// Works fine
anime({ targets: 'circle', fill: '#ff6b6b' })
// Also works for color cycling
anime({ targets: 'circle', fill: ['#ff6b6b', '#48dbfb', '#ff9ff3'] })SVG fill colors animate the same as CSS background colors.
Practice Questions
What does
path.getTotalLength()return? The total length of the SVG path in pixels (user units). Used for line drawing and motion path calculations.Why must two paths for morphing have the same command structure? Anime.js interpolates between corresponding numeric values in the
dstring. If the number of commands or points differs, the interpolation produces broken shapes.How does line drawing create the “drawing” illusion? By setting
stroke-dasharrayto the path length and animatingstroke-dashoffsetfrom that length to 0, revealing the path progressively.What does
path.getPointAtLength(distance)return? An SVG point object with.xand.yproperties representing the coordinates at that distance along the path.Can you animate SVG
fillcolor with Anime.js? Yes. Usefillas the property name:anime({ targets: 'circle', fill: '#ff6b6b' }).
Challenge
Create an SVG “loading spinner” that:
- Draws a circular arc (not a full circle) progressively using line drawing
- Has a dot at the leading edge of the arc
- Rotates the entire group continuously
- Morphs the arc length from short to long as it rotates
- Uses
easeInOutSineeasing
FAQ
Try It Yourself
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Anime.js SVG Demo</title>
<style>
body { font-family: system-ui; display: flex; flex-direction: column; align-items: center; background: #0f0f23; color: #e0e0e0; padding: 20px; }
svg { background: #1a1a3e; border-radius: 12px; margin: 10px; }
button { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; background: #6c5ce7; color: #fff; margin: 4px; font-size: 14px; }
button:hover { background: #5a4bd1; }
</style>
</head>
<body>
<h1>SVG Animation Demo</h1>
<svg width="300" height="300" viewBox="0 0 300 300">
<path id="myPath" d="M 50 150 Q 100 50, 150 150 T 250 150"
fill="none" stroke="#00cec9" stroke-width="3" />
<circle id="myDot" r="8" fill="#ffd700" cx="50" cy="150" />
</svg>
<div>
<button onclick="runPathFollow()">Path Follow</button>
<button onclick="runLineDraw()">Line Draw</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.2/anime.min.js"></script>
<script>
function runPathFollow() {
const path = document.querySelector('#myPath')
const dot = document.querySelector('#myDot')
const len = path.getTotalLength()
anime({
targets: {},
progress: [0, len],
duration: 3000, loop: true, easing: 'linear',
update: function(anim) {
const p = path.getPointAtLength(anim.currentValue)
dot.setAttribute('cx', p.x)
dot.setAttribute('cy', p.y)
}
})
}
function runLineDraw() {
const path = document.querySelector('#myPath')
const len = path.getTotalLength()
path.style.strokeDasharray = len
path.style.strokeDashoffset = len
anime({
targets: path,
strokeDashoffset: [len, 0],
duration: 2500,
easing: 'easeInOutSine'
})
}
</script>
</body>
</html>What to expect: Two SVG demos. “Path Follow” moves the yellow dot along the teal curve. “Line Draw” progressively reveals the curve as if it’s being drawn by a pen.
What’s Next
| Tutorial | What You’ll Learn |
|---|---|
| Staggering & Synchronization | Cascading effects, grid patterns, radial stagger |
Related topics: SVG fundamentals, CSS animations.
What’s Next
Congratulations on completing this Animejs Svg Motion tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro