✍️ Overview — The Text category
Animated text isn’t optional in video—it’s the primary vehicle for information. The Text category in the library covers 9 distinct patterns, from revealing letters one at a time to a sine wave and RGB glitch. Knowing which one to use in each context is what separates a shallow video from one with a visual identity.
🎯 When to use text animation
Reveal information progressively:
- →animated-text or typewriter for data that “arrives”
- →slide-text for directional entrances (slide-in)
Draw attention to existing text:
- →pulsing-text for gentle, continuous breathing
- →glitch-text for a retro/hacker style
✓ When text animates well
- ✓Pacing aligned with narration or background music.
- ✓Duration proportional to the length of the text.
- ✓Animation style consistent with the video’s tone.
✗ When it hurts
- ✗Animation faster than reading—the text disappears before it can be read.
- ✗Glitch or bounce in a serious corporate context.
- ✗Multiple different animations in the same scene.
🔤 animated-text — letter-by-letter stagger
The template animated-text.tsx splits the text into an array of characters and applies a Sequence with from scaled by index. Each letter comes in with a slight delay after the previous one, creating the effect of “fast typing” without using setTimeout or state.
const frame = useCurrentFrame(); const chars = text.split(""); return ( <div style={{ display: "flex" }}> {chars.map((char, i) => { const opacity = interpolate( frame, [i * 2, i * 2 + 8], [0, 1], { extrapolateRight: "clamp" } ); return <span key={i} style={{ opacity }}>{char}</span>; })} </div> );
💡 Why i * 2 instead of a fixed value?
O i * 2 is the delay: each letter starts 2 frames after the previous one. Change it to i * 4 and the reveal is slower; i * 1 makes it almost simultaneous. The + 8 sets the duration of each individual fade — the time it takes for opacity to go from 0 to 1.
Execution timeline (text "OLÁ"):
Frame 0 — "O" starts to appear
The “O” opacity goes from 0→1 over frames 0-8. “L” and “Á” are still invisible (opacity=0).
Frame 2 — "L" begins its fade
"O" still animating; "L" starts interpolation from 0→1 on frames 2-10.
Frame 8 — full text visible
All characters at opacity=1. Animation complete.
🏀 bounce-text — spring with overshoot
O bounce-text.tsx uses spring() instead of interpolate(). The visual difference is huge: instead of moving up linearly, the text “bounces”—overshoots its destination and comes back, like an object with mass and damping.
const { fps } = useVideoConfig(); const frame = useCurrentFrame(); const scale = spring({ fps, frame, config: { damping: 8, // baixo = mais quique stiffness: 120, // alto = mais rápido mass: 1, }, }); return <div style={{ transform: `scale(${scale})` }}>{text}</div>;
✓ Spring: when to use it
- ✓Hero titles that need visual impact.
- ✓CTAs and buttons that "call out" to the viewer.
- ✓Emojis and expressive icons.
✗ Interpolate: when to use it
- →Fades—spring doesn’t control opacity precisely.
- →Exact horizontal movement (precise slide).
- →Any timing that can't overshoot.
📊 Spring parameter table
| Parameter | Low value | High value |
|---|---|---|
| damping | elastic, oscillates too much | snaps quickly, no bounce |
| stiffness | slow, lazy | fast, aggressive |
| mass | light, fast | heavy, high inertia |
💻 glitch-text — RGB split without a library
The glitch effect is achieved with three overlapping copies of the same text, each colored in one channel (red, green, blue) and shifted horizontally by a different amount. All with random() seeded and interpolate multi-keyframe for the pulses.
// deslocamento pulsante para canal vermelho const glitchX = interpolate( frame % 12, // pulso periódico [0, 2, 4, 6, 12], [0, -4, 3, -2, 0], { extrapolateRight: "clamp" } ); return ( <div style={{ position: "relative" }}> {/* cópia vermelha */} <span style={{ color:"red", position:"absolute", transform:`translateX(${glitchX}px)`, mixBlendMode: "screen" }}>{text}</span> {/* cópia ciano e texto original */} </div> );
💡 mix-blend-mode: screen
With mixBlendMode: "screen", where red and cyan overlap to produce white—creating the characteristic visual artifact of CRT glitch. Without the blend mode, the colors simply cover each other.
⚠️ Don’t use Math.random() here
The glitch displacement needs to be deterministic—use random("glitch-r") from Remotion for fixed per-channel amplitudes. Math.random() will make the glitch flash differently on each render, breaking the video in parallel rendering.
🌊 floating-bubble-text — sine wave
Instead of interpolate or spring, the floating-bubble-text.tsx uses directly Math.sin() with the frame as an argument. Each character oscillates with a phase difference relative to the previous one, creating a wave that travels continuously across the text — with no beginning or end.
const frame = useCurrentFrame(); {text.split("").map((char, i) => { const y = Math.sin( frame / 12 // velocidade da onda + i * 0.5 // fase por índice ) * 8; // amplitude em px return ( <span key={i} style={{ display:"inline-block", transform: `translateY(${y}px)` }}> {char} </span> ); })}
📊 Adjusting the behavior
frame / 12 — speed: higher number = sloweri * 0.5 — phase offset: lower = more synchronized* 8 — amplitude: vertical displacement in pixels⌨️ typewriter-subtitle — blinking cursor
O typewriter-subtitle.tsx emulates real typing: progressively reveals more characters of the text using text.slice(0, visibleChars), where visibleChars comes directly from the frame. The cursor blinks with multi-keyframe interpolation.
const frame = useCurrentFrame(); const charsPerFrame = 0.3; // velocidade de digitação const visibleChars = Math.floor(frame * charsPerFrame); const displayText = text.slice(0, visibleChars); // cursor pisca a cada ~15 frames const cursorOpacity = interpolate( frame % 20, [0, 10, 20], [1, 0, 1] );
💡 Adjusting the speed
charsPerFrame = 0.3 types ~9 chars/sec at 30fps. To type faster: increase to 0.5. For slow, terminal-style typing: 0.15. The formula Math.floor(frame * rate) is the universal pattern for “how many elements to show so far.”
📚 Complete Library — Text Category
All 9 templates in the category, with the file, a one-line description, and the main hook used.
📌 Module summary
Next module:
2.2 — Charts & Data: animated SVG with interpolate, dashoffset, arcs, and numeric counters.