Anime.js Morph Animations — Complete Guide with Examples
In this tutorial, you'll learn about Anime.js morph animations. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Anime.js morph animations smoothly transition SVG shapes from one path to another, creating shape-shifting effects by interpolating the d attribute of path elements.
What You'll Learn
By the end of this tutorial, you'll morph between SVG paths, animate path data attributes, morph polygons and circles, and create complex shape sequences with timelines.
Why It Matters
Morph animations are visually striking and communicate state changes intuitively. A menu icon that morphs into a close icon, a play button that becomes a pause button, or a loading spinner that becomes a checkmark all benefit from morph animations.
Real-World Use
Doda Browser uses Anime.js morph animations for its navigation icons. The hamburger menu smoothly morphs into a back arrow when a submenu opens, providing a polished, app-like feel.
Where This Fits in Your Learning Path
flowchart LR
A["CSS Animations"] --> B["**SVG & Morph**"]
B --> C["Scroll & Performance"]
C --> D["Anime.js Project"]
D --> E["Advanced Anime.js"]
style B fill:#f97316,stroke:#c2410c,color:#fff
style A fill:#e5e7eb,stroke:#9ca3af,color:#374151
style E fill:#22c55e,stroke:#16a34a,color:#fff
Basic Path Morphing
Morph between two SVG paths by animating the d attribute with an array of start and end values.
anime({
targets: '.shape path',
d: [
{ value: 'M10 10 L90 10 L50 90 Z' }, // triangle
{ value: 'M10 10 L90 10 L90 90 L10 90 Z' } // square
],
duration: 2000,
easing: 'easeInOutQuad',
direction: 'alternate',
loop: true
})
<svg width="200" height="200" viewBox="0 0 100 100">
<path class="shape" d="M10 10 L90 10 L50 90 Z" fill="#4ecdc4"/>
</svg>
Expected output: The triangle smoothly morphs into a square, then back to a triangle in a continuous loop.
Morphing Complex Paths
More complex paths with the same number of points morph smoothly.
anime({
targets: '#morph-path',
d: [
{ value: 'M20,50 C20,20 80,20 80,50 C80,80 20,80 20,50' }, // circle-like
{ value: 'M10,50 C10,10 90,10 90,50 C90,90 10,90 10,50' } // larger oval
],
duration: 1500,
direction: 'alternate',
loop: true,
easing: 'easeInOutCubic'
})
Expected output: The circle morphs into an oval shape by interpolating the control points of the cubic bezier curves.
Morphing Polygons
Polygons with the same number of points can morph by animating the points attribute.
anime({
targets: '#polygon',
points: [
{ value: '50,10 90,90 10,90' }, // triangle
{ value: '10,10 90,10 90,90 10,90' }, // square
{ value: '50,0 100,35 80,100 20,100 0,35' } // star
],
duration: 2000,
direction: 'alternate',
loop: true,
easing: 'easeInOutQuad'
})
<svg width="200" height="200" viewBox="0 0 100 100">
<polygon id="polygon" points="50,10 90,90 10,90" fill="#ff6b6b"/>
</svg>
Expected output: The triangle morphs to a square, then to a star, then reverses.
Timeline Morph Sequence
Use a timeline to morph through multiple shapes in sequence.
const tl = anime.timeline({
duration: 1200,
easing: 'easeInOutQuad',
loop: true
})
tl.add({
targets: '#morph-shape',
d: 'M10,50 Q50,10 90,50 Q50,90 10,50' // diamond
}).add({
targets: '#morph-shape',
d: 'M50,10 Q90,10 90,50 Q90,90 50,90 Q10,90 10,50 Q10,10 50,10' // flower
}).add({
targets: '#morph-shape',
d: 'M10,10 L90,10 L90,90 L10,90 Z' // square
}).add({
targets: '#morph-shape',
d: 'M10,50 C10,10 90,10 90,50 C90,90 10,90 10,50' // circle
})
Expected output: The shape transitions through diamond, flower, square, and circle in a continuous loop.
Morphing with Grouped Shapes
Animate multiple path elements within a group simultaneously.
anime({
targets: '#group path',
d: function(el, i) {
const paths = [
['M10,10 L50,10 L50,50 Z', 'M10,10 L50,10 L50,50 L10,50 Z'],
['M60,10 L90,10 L75,50 Z', 'M60,10 L90,10 L90,50 L60,50 Z']
]
return paths[i]
},
duration: 1500,
direction: 'alternate',
loop: true
})
Expected output: Each path in the group morphs independently with its own start and end values.
Common Mistakes
1. Morphing paths with different numbers of points
For smooth morphing, both paths must have the same number of points and control points. Different counts cause jarring transitions.
2. Not keeping path commands consistent
Mix M (move) with L (line) and C (curve) commands inconsistently between paths causes broken morphing. Keep command types the same.
3. Forgetting to wrap values in arrays for timeline adds
Timeline .add() targets need value objects: { value: 'M...' }. Omitting the value wrapper fails silently.
4. Using absolute paths as starting values without setting the initial path
If the element has no initial d attribute, start from current. Always provide an initial path in SVG or set it via JavaScript before animating.
5. Animating non-path SVG elements (rect, circle) as paths
Anime morphs the d attribute of path elements. Rect and circle elements use different attributes. Convert them to paths for morphing.
Practice Questions
What SVG attribute does Anime morph? The d attribute of path elements, which defines the shape's outline.
Why must morphing paths have the same number of points? Anime interpolates between corresponding points. Mismatched counts cause interpolation errors.
Can you morph a rect into a circle? Not directly. Convert both SVG elements to path elements with the same number of commands.
How do you morph through multiple shapes? Pass an array of value objects to the d property or use a timeline.
What is the role of path commands in morphing? Commands (M, L, C, Q) define how points connect. Matching commands between start and end ensures smooth transitions.
Challenge
Create an icon that morphs through three states: a play triangle, a pause double-bar, and a stop square. Use a timeline with loop. Each state should hold for 1 second before morphing.
FAQ
Mini Project
Build a morphing icon set. A navigation icon morphs between hamburger menu, arrow back, close X, and search magnifying glass. Click triggers the next morph state.
const states = [
{ name: 'menu', path: 'M10,20 L90,20 M10,40 L90,40 M10,60 L90,60' },
{ name: 'arrow', path: 'M60,10 L20,40 L60,70 M80,40 L20,40' },
{ name: 'close', path: 'M20,20 L80,80 M80,20 L20,80' },
{ name: 'search', path: 'M50,30 A20,20 0 1,1 48,32 M30,55 L42,45' }
]
let currentState = 0
document.querySelector('#morph-btn').addEventListener('click', () => {
currentState = (currentState + 1) % states.length
anime({
targets: '#morph-icon',
d: states[currentState].path,
duration: 400,
easing: 'easeInOutQuad'
})
})
<svg width="100" height="100" viewBox="0 0 100 80">
<path id="morph-icon" d="M10,20 L90,20 M10,40 L90,40 M10,60 L90,60" stroke="#333" stroke-width="6" stroke-linecap="round" fill="none"/>
</svg>
<button id="morph-btn" class="px-4 py-2 bg-blue-500 text-white rounded mt-4">Next Icon</button>
What's Next
Continue with scroll and performance optimization:
| Tutorial | What You'll Learn |
|---|---|
| Scroll Animations | Trigger animations based on scroll position |
| Performance Optimization | Optimize animations for smooth 60fps |
Related topics: SVG path data format, JavaScript array interpolation.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro