Skip to content
Anime.js SVG & Motion Paths — Step-by-Step Tutorial

Anime.js SVG & Motion Paths — Step-by-Step Tutorial

DodaTech Updated Jun 6, 2026 11 min read

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.

Before starting: Complete the Getting Started and Animation Controls tutorials first. Basic SVG knowledge (paths, attributes) helps but isn’t required.

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
  increases
  • cx, cy — Center x and y of a circle
  • r — Radius
  • x, y — Top-left position of a rectangle
  • d — 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:

  1. path.getTotalLength() — Gets the total length of the path in pixels. This is our animation range.
  2. progress: [0, pathLen] — We animate a custom property progress from 0 to the path’s full length.
  3. update: function(anim) — This fires every frame (60fps). anim.currentValue gives us the current progress value.
  4. path.getPointAtLength(len) — SVG’s built-in method. Give it a distance along the path, and it returns { x, y } coordinates.
  5. 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:

Statestroke-dasharraystroke-dashoffsetWhat you see
Initial300 (full length)300Nothing — the dash is shifted entirely out of view
Midway300150First half of the path is visible
Complete3000Entire 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

  1. What does path.getTotalLength() return? The total length of the SVG path in pixels (user units). Used for line drawing and motion path calculations.

  2. Why must two paths for morphing have the same command structure? Anime.js interpolates between corresponding numeric values in the d string. If the number of commands or points differs, the interpolation produces broken shapes.

  3. How does line drawing create the “drawing” illusion? By setting stroke-dasharray to the path length and animating stroke-dashoffset from that length to 0, revealing the path progressively.

  4. What does path.getPointAtLength(distance) return? An SVG point object with .x and .y properties representing the coordinates at that distance along the path.

  5. Can you animate SVG fill color with Anime.js? Yes. Use fill as 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 easeInOutSine easing

FAQ

What path formats can Anime.js morph between?
Any SVG path d strings, as long as both paths have the same number and types of commands. Anime.js interpolates each coordinate numerically.
How do I make an element follow a curved path?
Use the update callback with path.getPointAtLength(). Animate a progress value from 0 to path.getTotalLength() and position the element at each frame.
Why doesn’t my line-drawing animation show anything?
You likely forgot to set strokeDasharray and strokeDashoffset before the animation starts. Both must equal the path’s total length.
Can I animate SVG fill colors?
Yes. Use fill as the property name. Both hex and rgb values work.
Does Anime.js support SVG transform-origin?
No. SVG transform origins work differently from CSS. Set transform-origin via CSS on the SVG element, or use translate to adjust pivot points.

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

TutorialWhat You’ll Learn
Staggering & SynchronizationCascading 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