Examples
Each line reveals independently. Ideal for headlines and multi-line copy — pair with overflow to mask letters as they slide.
<TextEngine
mode="once"
overflow
lineIn={{ opacity: 1, y: 0 }}
lineOut={{ opacity: 0, y: 60 }}
lineStagger={80}
lineConfig={{
duration: 1000,
easing: easings.easeOutQuart,
}}
>
Motion is the language
of human intent.
</TextEngine>
Words animate as independent units with staggered delay. Spring tension and friction give it a natural, organic feel.
mode="always"<TextEngine
mode="always"
wordIn={{ opacity: 1, y: 0 }}
wordOut={{ opacity: 0, y: 20 }}
wordStagger={55}
wordConfig={{ tension: 160, friction: 18 }}
>
Every word finds its moment.
</TextEngine>
Per-character stagger with scale and opacity. Tight stagger feels like a typewriter; loose stagger feels cinematic.
mode="always"<TextEngine
mode="always"
letterIn={{ opacity: 1, y: 0, scale: 1 }}
letterOut={{ opacity: 0, y: 30, scale: 0.7 }}
letterStagger={28}
letterConfig={{ tension: 220, friction: 22 }}
>
Character by character.
</TextEngine>
Inline elements like <span> are treated as word wrappers — their styles, classes and props are preserved while each word inside animates normally.
<TextEngine
mode="always"
overflow
wordIn={{ opacity: 1, y: 0 }}
wordOut={{ opacity: 0, y: 24 }}
wordStagger={60}
wordConfig={{
duration: 700,
easing: easings.easeOutCubic,
}}
>
Styled{' '}
<span style={{ fontWeight: 900, color: '#7c6fef' }}>
inline
</span>
{' '}elements animate too.
</TextEngine>
Wrap each letter in an overflow:hidden container so characters emerge from — and retreat into — a masked boundary, giving a refined editorial reveal.
<TextEngine
mode="always"
overflow
wrapLetterIn={{ overflow: 'hidden' }}
letterIn={{ opacity: 1, y: '0%' }}
letterOut={{ opacity: 0, y: '100%' }}
letterStagger={35}
letterConfig={{ tension: 180, friction: 20 }}
>
Clipped inside each letter.
</TextEngine>
Crank up the tension to 500 and drop friction to 6 — each letter overshoots and bounces back. Pure spring physics, no keyframes.
mode="always"<TextEngine
mode="always"
letterIn={{ opacity: 1, y: 0, scale: 1 }}
letterOut={{ opacity: 0, y: -80, scale: 2.2 }}
letterStagger={40}
letterConfig={{ tension: 500, friction: 6 }}
>
Elastic spring physics.
</TextEngine>
Rotate each letter on the X axis while clipping it — creates a slot-machine flip effect. Combine with word stagger for a cascade.
mode="always"<TextEngine
mode="always"
overflow
wrapLetterIn={{ overflow: 'hidden' }}
letterIn={{ opacity: 1, rotateX: 0 }}
letterOut={{ opacity: 0, rotateX: -90 }}
letterStagger={50}
letterConfig={{ tension: 200, friction: 18 }}
>
3D flip. Per letter.
</TextEngine>
Stack y, x, rotate and scale simultaneously on every letter. Each spring resolves independently — the result is beautifully chaotic.
mode="always"<TextEngine
mode="always"
letterIn={{
opacity: 1, y: 0, x: 0,
rotate: 0, scale: 1,
}}
letterOut={{
opacity: 0, y: 60, x: -20,
rotate: -25, scale: 0.4,
}}
letterStagger={45}
letterConfig={{ tension: 260, friction: 14 }}
>
Everything. All at once.
</TextEngine>
Tie animation progress to the scroll position. Words reveal as the element travels through the viewport — no threshold snapping.
mode="progress"<TextEngine
mode="progress"
wordIn={{ opacity: 1, y: 0 }}
wordOut={{ opacity: 0, y: 20 }}
wordConfig={{ duration: 400 }}
start="top bottom"
end="bottom center"
type="interpolate"
interpolationStaggerCoefficient={0.3}
>
Driven by scroll position.
</TextEngine>
type="toggle" fires a one-shot play-in when the element crosses the start threshold and play-out when it crosses end — no continuous tracking needed.
<TextEngine
mode="progress"
wordIn={{ opacity: 1, y: 0, scale: 1 }}
wordOut={{ opacity: 0, y: 20, scale: 0.9 }}
wordStagger={60}
wordConfig={{ tension: 180, friction: 20 }}
start="top bottom"
end="top center"
type="toggle"
>
Snaps in as you scroll past.
</TextEngine>
Combine filter: blur with opacity and y in progress mode. Each letter un-blurs as it scrolls into the focal zone — scroll back and watch it dissolve again.
<TextEngine
mode="progress"
letterIn={{
opacity: 1, y: 0,
filter: 'blur(0px)',
}}
letterOut={{
opacity: 0, y: 40,
filter: 'blur(16px)',
}}
letterStagger={25}
letterConfig={{ duration: 600 }}
start="top bottom"
end="center center"
type="interpolate"
interpolationStaggerCoefficient={0.25}
>
Blur fades with your scroll.
</TextEngine>
Word wrappers fall from above while letters rise from below — they collide into place. wrapWordConfig drives the outer container; letterConfig drives the inner characters independently.
<TextEngine
mode="always"
wrapWordIn={{ y: 0, opacity: 1 }}
wrapWordOut={{ y: -50, opacity: 0 }}
wordConfig={{ tension: 160, friction: 16 }}
letterIn={{ opacity: 1, y: 0 }}
letterOut={{ opacity: 0, y: 24 }}
letterStagger={14}
letterConfig={{ tension: 280, friction: 22 }}
wordStagger={80}
>
They fall. Rise. Collide.
</TextEngine>
Each letter's wrapper spins in 180° while the letter itself counter-rotates −90°. Two transforms working against each other — the result looks mechanical, like interlocking gears.
mode="always"<TextEngine
mode="always"
wrapLetterIn={{ rotate: 0, scale: 1 }}
wrapLetterOut={{ rotate: 180, scale: 0 }}
letterIn={{ opacity: 1, rotate: 0 }}
letterOut={{ opacity: 0, rotate: -90 }}
letterStagger={28}
letterConfig={{ tension: 320, friction: 12 }}
>
Gears within gears.
</TextEngine>
Line wrappers expand outward from a tiny scale (0.15→1) while the text inside simultaneously rises. The combination reads as the lines breathing open rather than simply sliding in.
mode="always"<TextEngine
mode="always"
wrapLineIn={{ scale: 1, opacity: 1 }}
wrapLineOut={{ scale: 0.15, opacity: 0 }}
lineIn={{ y: 0, opacity: 1 }}
lineOut={{ y: 18, opacity: 0 }}
lineStagger={130}
lineConfig={{ tension: 140, friction: 18 }}
>
Lines breathe
into the frame.
</TextEngine>
Each word wrapper skews −20° while the word itself counter-skews +20°. The opposing transforms cancel out at rest — during the animation the words appear to shear in from a diagonal plane.
mode="always"<TextEngine
mode="always"
wrapWordIn={{ skewX: 0 }}
wrapWordOut={{ skewX: -20 }}
wordIn={{ opacity: 1, skewX: 0 }}
wordOut={{ opacity: 0, skewX: 20 }}
wordStagger={65}
wordConfig={{ tension: 200, friction: 16 }}
>
Sliced. Sheared. Served.
</TextEngine>
Three independent animation layers stacked: word wrappers slide in from the left, letter wrappers drop from above with a spring bounce, and each letter spins 270° into place. All three run simultaneously with separate stagger clocks.
mode="always"<TextEngine
mode="always"
wrapWordIn={{ x: 0, opacity: 1 }}
wrapWordOut={{ x: -50, opacity: 0 }}
wrapLetterIn={{ y: 0, scale: 1 }}
wrapLetterOut={{ y: -32, scale: 0 }}
letterIn={{ opacity: 1, rotate: 0 }}
letterOut={{ opacity: 0, rotate: 270 }}
wordStagger={90}
letterStagger={18}
wordConfig={{ tension: 150, friction: 16 }}
letterConfig={{ tension: 380, friction: 10 }}
>
Three layers. Pure chaos.
</TextEngine>
Each letter's wrapper descends from above while the letter rises from below. overflow clips both — they're invisible until they converge, then snap into place like venetian blinds opening.
<TextEngine
mode="always"
overflow
wrapLetterIn={{ y: 0 }}
wrapLetterOut={{ y: -52 }}
letterIn={{ y: 0, opacity: 1 }}
letterOut={{ y: 52, opacity: 0 }}
letterStagger={20}
letterConfig={{ tension: 240, friction: 22 }}
>
Blinds open. Letters rise.
</TextEngine>
The word wrapper slides in from the right, the word itself from the left. With overflow clipping both, each word is invisible until the two halves slide together — like a pair of doors closing.
<TextEngine
mode="always"
overflow
wrapWordIn={{ x: 0 }}
wrapWordOut={{ x: 70 }}
wordIn={{ x: 0, opacity: 1 }}
wordOut={{ x: -70, opacity: 0 }}
wordStagger={55}
wordConfig={{ tension: 180, friction: 18 }}
>
Doors slide open.
</TextEngine>
Line wrappers drop from below while the lines themselves rise from above. overflow keeps each invisible until they meet — the stage curtain drops and the line is revealed behind it.
<TextEngine
mode="always"
overflow
wrapLineIn={{ y: 0 }}
wrapLineOut={{ y: 110 }}
lineIn={{ y: 0, opacity: 1 }}
lineOut={{ y: -110, opacity: 0 }}
lineStagger={120}
lineConfig={{ tension: 140, friction: 16 }}
>
Each line drops its
curtain.
</TextEngine>
The wrapper tilts backward (−22° skewY) while the letter tilts forward (+22°). overflow makes the letter invisible until both skews resolve — each character appears to hinge open like a card flipping face-up.
<TextEngine
mode="always"
overflow
wrapLetterIn={{ skewY: 0 }}
wrapLetterOut={{ skewY: -22 }}
letterIn={{ opacity: 1, skewY: 0 }}
letterOut={{ opacity: 0, skewY: 22 }}
letterStagger={22}
letterConfig={{ tension: 280, friction: 18 }}
>
Cards flip open.
</TextEngine>
Word wrappers rise from below while words themselves fall from above.overflow hides each until they align — like stadium gates lifting to reveal the words waiting above them.
<TextEngine
mode="always"
overflow
wrapWordIn={{ y: 0 }}
wrapWordOut={{ y: 56 }}
wordIn={{ y: 0, opacity: 1 }}
wordOut={{ y: -56, opacity: 0 }}
wordStagger={65}
wordConfig={{ tension: 200, friction: 16 }}
>
Gates lift. Words land.
</TextEngine>