🎞️ Vista general — patrones de composición temporal
La categoría "Animación de contenido" agrupa plantillas que van más allá de animar un solo elemento — ellas orquestan múltiples elementos en el tiempo. El patrón central es el stagger mediante Sequence con from escalado, pero la categoría también abarca 3D CSS, simulación física y loops perpetuos.
🎯 Los 4 patrones de esta categoría
animated-list, notification-pop, progress-steps — varios elementos con from escalado.
card-flip, rotating-carousel — perspective + rotateY para dar profundidad.
countdown-timer — el número mostrado se calcula directamente del frame, sin useState.
particle-explosion, sound-wave — posición/altura calculada con aritmética por frame.
📋 animated-list — stagger de elementos
O animated-list.tsx es la plantilla de referencia para stagger de varios elementos. Cada elemento de una lista aparece con un retraso proporcional a su índice, creando esa sensación de «los elementos van llegando», omnipresente en los videos explicativos y las diapositivas animadas.
const DELAY_PER_ITEM = 10; // frames entre cada item {items.map((item, i) => ( <Sequence key={i} from={i * DELAY_PER_ITEM}> <ListItem item={item} /> </Sequence> ))} // Dentro de ListItem: frame é LOCAL (começa em 0) const frame = useCurrentFrame(); // 0, 1, 2... const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" }); const y = interpolate(frame, [0, 15], [20, 0], { extrapolateRight: "clamp" });
📊 El poder del frame LOCAL dentro de Sequence
Cuando usas <Sequence from={i * 10}>, el componente hijo recibe useCurrentFrame() comenzando en 0 cuando inicia la secuencia. Esto significa que cada ListItem puede tener la misma lógica de animación — no necesitas restar el offset manualmente. Remotion se encarga del desplazamiento.
✓ Correcto: Sequence + frame local
<Sequence from={i * 10}> <Item /> // frame começa em 0 </Sequence>
Cada Item tiene la misma lógica: limpio y reutilizable.
✗ Incorrecto: restar el offset manualmente
const localFrame = frame - i * 10; if (localFrame < 0) return null;
Verboso, propenso a errores de borde (frame negativo).
🃏 card-flip — CSS 3D en Remotion
O card-flip.tsx demuestra cómo implementar CSS 3D dentro de Remotion: dos caras de una tarjeta posicionadas con backfaceVisibility: "hidden", el contenedor con perspective, y la rotación interpolada de 0° a 180°.
const frame = useCurrentFrame(); const rotation = interpolate( frame, [15, 45], [0, 180], { extrapolateRight: "clamp" } ); return ( {/* Contêiner: define a perspectiva */} <div style={{ perspective: 800, transformStyle: "preserve-3d" }}> {/* Frente */} <div style={{ backfaceVisibility: "hidden", transform: `rotateY(${rotation}deg)`, position: "absolute", inset: 0 }}>Face A</div> {/* Verso — começa já virado 180° */} <div style={{ backfaceVisibility: "hidden", transform: `rotateY(${rotation - 180}deg)`, position: "absolute", inset: 0 }}>Face B</div> </div> );
💡 ¿Por qué backfaceVisibility: "hidden"?
Sin esta propiedad, verías ambas caras al mismo tiempo: el frente aparecería reflejado detrás y viceversa. Con hidden, cada cara solo es visible cuando está "de frente" al observador. Es el secreto de cualquier flip card.
⏳ countdown-timer — estado derivado del frame
O countdown-timer.tsx ilustra un concepto central de Remotion: el valor mostrado siempre es una función directa del frame, sin useState ni efectos. El número mostrado se calcula a partir del frame actual y de los parámetros de duración/fps.
const frame = useCurrentFrame(); const { fps, durationInFrames } = useVideoConfig(); // segundos restantes — derivados do frame const secondsLeft = Math.ceil( (durationInFrames - frame) / fps ); // "GO" quando chega a 0 const label = secondsLeft > 0 ? String(secondsLeft) : "GO!"; // spring de entrada para cada mudança de número const frameInSegment = frame % fps; // 0→fps a cada segundo const scale = spring({ fps, frame: frameInSegment, config: { damping: 10, stiffness: 150 } });
Secuencia de eventos en el countdown (30fps, 5s):
Frame 0 — muestra «5»
(150 - 0) / 30 = 5 → Math.ceil(5) = 5. Spring entra con scale-pop.
Frame 30 — cambia a «4»
(150 - 30) / 30 = 4 → el número cambia, spring se reinicia (frame % fps = 0).
Frame 150 — muestra «GO!»
secondsLeft ≤ 0 → label = "GO!". Sin estado, sin setInterval.
💥 particle-explosion — física 2D determinista
O particle-explosion.tsx simula una explosión de partículas con trayectoria física: posición inicial en el centro, velocidad con ángulo aleatorio (sembrado) y gravedad simple. Todo se calcula frame a frame — sin estado acumulado.
const PARTICLE_COUNT = 40; {Array.from({ length: PARTICLE_COUNT }, (_, i) => { // velocidade e ângulo DETERMINÍSTICOS const angle = random(`angle-${i}`) * 2 * Math.PI; const speed = random(`speed-${i}`) * 8 + 2; const vx = Math.cos(angle) * speed; const vy = Math.sin(angle) * speed; // posição frame-a-frame com gravidade const x = cx + vx * frame; const y = cy + vy * frame + 0.15 * frame * frame; // g const opacity = interpolate(frame, [20, 45], [1, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" }); })}
⚠️ Sin random() con seed = video corrupto
Si usas Math.random() aquí, cada frame calculado produce una trayectoria diferente — en el renderizado en paralelo de Remotion, las partículas «saltan» a posiciones aleatorias. El video final parece estar dañado. random("seed") garantiza que el frame 42 siempre tenga las mismas partículas en el mismo lugar.
🎵 sound-wave & text-highlight — loops y enfoque
Dos templates que muestran patrones complementarios: sound-wave.tsx crea un visualizador de audio (barras que oscilan con Math.sin) y text-highlight.tsx destaca una palabra a la vez en sincronía con el frame, como en el karaoke o la lectura guiada.
sound-wave
{bars.map((_, i) => {
const h = Math.sin(
frame / 8 // velocidade
+ i * 0.4 // fase
) * 0.5 + 0.5; // 0 a 1
return <rect height={h * maxH}/>;
})}
text-highlight
const words = text.split(" "); const framesPerWord = fps / 2; const activeIndex = Math.floor( frame / framesPerWord ); {words.map((w, i) => ( <span style={{ color: i === activeIndex ? "#60a5fa" : "white" }}>{w}</span> ))}
💡 text-highlight: sincronizar con audio
El mismo patrón de Math.floor(frame / framesPerWord) se puede adaptar para sincronizar palabras con marcas de tiempo de la transcripción. En los módulos avanzados de T3, verás cómo combinar esta plantilla con @remotion/captions para karaoke automático.
📚 Biblioteca completa — Animación de contenido
📌 Resumen del módulo
Próximo módulo:
2.4 — Imagen y medios: galerías, sliders, comparadores y marcos para fotos en video.