Text Splitting
ThesplitText() function breaks text into animatable parts:
import { splitText, animate, stagger } from 'animejs';
// Split into characters
const split = splitText('h1', {
chars: true
});
// Animate each character
animate(split.chars, {
y: [-20, 0],
opacity: [0, 1],
duration: 800,
delay: stagger(50)
});
Split Options
Control how text is split:import { splitText } from 'animejs';
// Split into lines, words, and chars
const split = splitText('p', {
lines: true,
words: true,
chars: true
});
// Access split elements
console.log(split.lines); // Array of line elements
console.log(split.words); // Array of word elements
console.log(split.chars); // Array of character elements
Custom HTML Wrapping
Wrap split elements with custom HTML:const split = splitText('h2', {
chars: {
class: 'char',
wrap: 'clip', // Wraps in overflow hidden container
}
});
// Custom template
const split = splitText('h2', {
words: `<span class="word-{i}">{value}</span>`
});
Character Cloning
Create layered text effects:import { splitText, animate, stagger, createTimeline } from 'animejs';
const split = splitText('h2', {
chars: {
class: 'char',
clone: 'left', // Clone character to the left
wrap: 'clip'
}
});
// Animate original and clone
const tl = createTimeline({
defaults: {
ease: 'inOutQuad',
duration: 400
}
});
tl.add('.char > span', {
x: '100%' // Slide cloned characters
}, stagger(5, { use: 'data-char' }));
Wavy Text Effect
Create wave animations across text:import { splitText, animate, createTimeline, stagger } from 'animejs';
const params = {
split: splitText('h2', { chars: true }),
strength: 0
};
const waveAnim = createTimeline()
.add(params.split.chars, {
y: ['-50%', '50%'],
duration: 500,
loop: true,
alternate: true,
ease: 'inOut(2)',
modifier: v => v * params.strength // Control effect strength
}, stagger(50))
.seek(1000);
// On hover
element.addEventListener('pointerenter', () => {
animate(params, {
strength: 1,
onBegin: () => waveAnim.play()
});
});
element.addEventListener('pointerleave', () => {
animate(params, {
strength: 0,
onComplete: () => waveAnim.pause()
});
});
Raining Letters
Letters fall into place:import { splitText, createTimeline, createSpring, stagger } from 'animejs';
const split = splitText('h2', {
chars: {
class: 'char',
clone: 'top', // Clone above
wrap: 'clip'
}
});
const ease = createSpring({
stiffness: 90,
damping: 11
});
createTi meline()
.add('.char > span', {
y: '100%', // Drop down
composition: 'blend',
ease
}, stagger(10, {
use: 'data-char',
from: 'random'
}));
Subtle Highlight Effect
import { splitText, createTimeline, stagger, utils } from 'animejs';
const { chars } = splitText('h2', { chars: true });
// Set initial opacity
utils.set(chars, { opacity: 0.25 });
// Highlight on hover
element.addEventListener('pointerenter', () => {
createTimeline()
.add(chars, {
opacity: 1,
textShadow: '0 0 30px rgba(255,255,255,.9)',
ease: 'out(3)',
duration: 350,
composition: 'blend'
}, stagger(12));
});
element.addEventListener('pointerleave', () => {
createTimeline()
.add(chars, {
opacity: 0.25,
textShadow: '0 0 0px rgba(255,255,255,0)',
ease: 'out(3)',
duration: 350,
composition: 'blend'
}, stagger(12));
});
3D Word Flip
Create 3D rotating word effects:import { splitText, createTimeline, stagger, animate } from 'animejs';
splitText('h2', {
words: `<span class="word-3d word-{i}">
<em class="face face-top">{value}</em>
<em class="face-front">{value}</em>
<em class="face-bottom">{value}</em>
<em class="face-back">{value}</em>
</span>`
});
const wordStagger = stagger(50, { use: 'data-word', start: 0 });
const rotateAnim = createTimeline({
autoplay: false,
defaults: {
ease: 'inOut(2)',
duration: 750
}
})
.add('.word-3d', { rotateX: -180 }, wordStagger)
.add('.word-3d .face-top', { opacity: [0, 0, 0] }, wordStagger)
.add('.word-3d .face-front', { opacity: [1, 0, 0] }, wordStagger)
.add('.word-3d .face-bottom', { opacity: [0, 1, 0] }, wordStagger)
.add('.word-3d .face-back', { opacity: [0, 0, 1] }, wordStagger);
// Trigger animation
element.addEventListener('pointerenter', () => {
animate(rotateAnim, { progress: 1 });
});
Exploding Characters
import { splitText, createTimeline, utils, stagger } from 'animejs';
const { chars } = splitText('h2', { chars: true });
element.addEventListener('pointerenter', () => {
createTimeline()
.add(chars, {
x: {
to: () => utils.random(-3, 3) + 'rem',
duration: () => utils.random(150, 500)
},
y: () => utils.random(-5, 5) + 'rem',
rotate: () => utils.random(-180, 180),
duration: () => utils.random(200, 750),
ease: 'outCirc',
composition: 'blend'
}, stagger(5, { from: 'random' }));
});
element.addEventListener('pointerleave', () => {
createTimeline()
.add(chars, {
x: { to: 0, delay: 75 },
y: 0,
rotate: { to: 0, delay: 150 },
duration: () => utils.random(200, 400),
ease: 'inOut(2)',
composition: 'blend'
}, stagger(10, { from: 'random' }));
});
Revert Split Text
Restore original text structure:import { splitText } from 'animejs';
const split = splitText('p', {
lines: true,
words: true
});
// Later, restore original text
button.addEventListener('click', () => {
split.revert();
});
Split Text Effects
Add custom effects during or after splitting:import { splitText, createTimeline, stagger } from 'animejs';
const split = splitText('p', {
lines: true
});
split.addEffect(split => {
// Return a timeline to sync with the split
return createTimeline({
defaults: {
alternate: true,
loop: true,
loopDelay: 75,
duration: 1500,
ease: 'inOutQuad'
}
})
.add(split.lines, {
color: { from: '#61C3FF' },
y: -10,
scale: 1.1
}, stagger(100, { start: 0 }))
.add(split.words, {
scale: [0.98, 1.04]
}, stagger(100, { use: 'data-line', start: 0 }))
.init();
});
Debug Mode
Visualize split boundaries:const split = splitText('p', {
lines: true,
words: true,
chars: true
});
// Toggle debug visualization
button.addEventListener('click', () => {
split.debug = !split.debug;
split.refresh();
});
Stagger by Line
Stagger animations based on line position:import { splitText, animate, stagger } from 'animejs';
const split = splitText('p', {
lines: true,
words: true
});
// Stagger words by their line
animate(split.words, {
y: [20, 0],
opacity: [0, 1],
duration: 600,
delay: stagger(100, {
use: 'data-line' // Use line index for stagger
})
});
Performance Considerations
Text splitting creates many DOM elements. For long text:
- Limit splitting to visible text
- Use
will-change: transformsparingly - Consider using
composition: 'replace'for better performance - Clean up with
split.revert()when done
Next Steps
Timelines
Sequence text animations
Scroll Animations
Trigger text effects on scroll