🕐 useCurrentFrame() — el reloj
En una página web usarías requestAnimationFrame o un setInterval y acumularía estado. En Remotion, olvídate de todo eso. Solo preguntas: "¿en qué frame estoy ahora?" — e useCurrentFrame() devuelve un número entero que crece de 0 hasta el final del video.
🎯 La idea central
El frame es la entrada y la imagen es la salida. Si cambia el frame, recalcula todo desde cero. Este hook es el punto de partida de prácticamente todos los templates de la biblioteca.
- •Devuelve un número: 0 al principio, y aumenta de 1 en 1.
- •El componente se vuelve a ejecutar en cada frame durante el renderizado.
- •Nunca "avanzas" el tiempo: Remotion lo hace por ti.
import { useCurrentFrame } from "remotion"; export const MyVideo = () => { const frame = useCurrentFrame(); // 0, 1, 2, 3 … return <div>Frame atual: {frame}</div>; };
💡 Consejo práctico
¿Quieres probarlo? Abre Remotion Studio y arrastra la barra de tiempo. El número que aparece es exactamente lo que useCurrentFrame() devuelve. Ver cómo cambia el número mientras arrastras hace que el concepto sea concreto.
⚙️ fps y durationInFrames — la regla
El frame por sí solo no indica cuánto tiempo pasó. Quien da la escala es el fps (frames por segundo). A 30fps, el frame 30 es "1 segundo". El durationInFrames indica cuántos frames tiene el video en total: ese es tu límite de tiempo.
📊 Conversiones que usarás a cada rato
- segundos × fps = frames — 2s a 30fps = 60 fotogramas
- frames ÷ fps = segundos — 90 fotogramas a 30fps = 3s
- 30fps — patrón web/social, ligero para renderizar
- 60fps — más fluido, duplica el costo de render
✓ Qué HACER
- ✓Definir fps y duración en la
<Composition>. - ✓Derivar tiempos a partir de fps (
fps * 1.5para 1,5s). - ✓Pensar la animación dentro de la ventana de durationInFrames.
✗ Qué NO hacer
- ✗Fijar "frame 45" sin recordar que cambia si cambia el fps.
- ✗Animar más allá de durationInFrames (desaparece en el render final).
- ✗Mezclar 30 y 60fps entre escenas sin convertir.
📐 useVideoConfig() — dimensiones y fps
¿Cómo saber los fps dentro del componente, sin hardcode? ¿Y el ancho, para centrar algo? El useVideoConfig() devuelve todo: width, height, fps e durationInFrames de la composición que se está renderizando.
const { width, height, fps } = useVideoConfig(); const frame = useCurrentFrame(); // "1 segundo" funciona em 30 ou 60fps: const apareceu = frame > fps; // centralizar sem saber o tamanho exato: const cx = width / 2;
💡 Por qué esto importa
El mismo componente puede ejecutarse en 16:9 (1920×1080) y 9:16 (1080×1920) sin cambiar una sola línea, si lees width/height de useVideoConfig() en vez de fijar números. Así es como una plantilla se vuelve reutilizable entre YouTube y Reels.
🎯 El frame como fuente de verdad
Aquí está la regla de oro: la imagen de un frame depende SOLO del número del frame. Nada de useState acumulándose, nada de timers, nada de «cuánto tiempo pasó desde que hice clic». Cada frame es una función pura.
El render solicita frames fuera de orden
Para ir rápido, Remotion renderiza varios frames en paralelo — puede calcular el frame 80 antes que el 20. Solo funciona porque cada uno es independiente.
El estado en tiempo real rompe esto
Uno setInterval asume que el tiempo transcurre continuamente. En el renderizado eso no existe — cada frame es un cálculo aislado. Por eso la animación depende del frame, no de timers.
Todo deriva de una entrada
Posición, opacidad, color, escala: todos son funciones del frame. Si cambia el frame, recalcula. Esa disciplina es lo que mantiene el video consistente.
🔁 Determinismo — mismo frame, misma imagen
Consecuencia directa de la regla anterior: renderizar el frame 42 hoy, mañana o en otra máquina produce exactamente el mismo píxel. Esto se llama determinismo, y tiene un enemigo claro: la aleatoriedad sin semilla.
⚠️ Atención: lo que destruye el determinismo
- ✗
Math.random()— da un valor diferente en cada cálculo, hace que las partículas "parpadeen". - ✗
Date.now()/new Date()— cambia en cada ejecución. - ✗Cualquier dato externo que varíe entre renders.
✅ La solución: random() con semilla
Remotion ofrece random("seed"): dada la misma semilla, siempre devuelve el mismo número. Obtienes «aleatoriedad» visual sin perder reproducibilidad.
import { random } from "remotion"; // mesma seed → mesmo valor, sempre: const x = random("particula-7") * width;
⏱️ Pensar en frames, no en segundos
Último cambio de hábito del módulo: tu unidad de trabajo pasa a ser el frame. "El título aparece en medio segundo" se convierte en "el título aparece en 15 frames". Los segundos solo aparecen en el límite del sistema, cuando una persona escribe un valor.
✓ Mentalidad de frame
- ✓"Aparece del frame 0 al 15" — directo en la API.
- ✓Stagger: el elemento N comienza en el frame N×5.
- ✓Convierte segundos solo al inicio:
0.5 * fps.
✗ Mentalidad de segundo orden
- ✗Calcular "0,5s" en medio de toda la animación cada vez.
- ✗Mezclar segundos y frames en el mismo cálculo.
- ✗Olvidar que cambiar los fps reescala todo en segundos.
💡 Regla práctica
A 30fps: 15 fotogramas = 0,5s, 30 frames = 1s, 45 frames = 1,5s. Aprende estos tres y podrás calcular cualquier timing mentalmente.
📌 Resumen del módulo
Próximo módulo:
1.2 — interpolate(): transformar el número del fotograma en opacidad, posición y escala.