Remotion Motion Graphics — Video 2D Basado en Fotogramas
Remotion renderiza React a video. Cada fotograma es una función pura del índice de fotograma, por lo que la salida es determinista, difeable y revisable. Es la mejor opción por defecto para video basado en texto y datos, y el mejor "compositor" para ensamblar pases de Blender o Manim con tipografía, subtítulos y transiciones.
Lee references/REMOTION-PLAYBOOK.md para convenciones y references/REMOTION-RECIPES.md para componentes listos para copiar. Consulta la documentación oficial y el CLI instalado para la API actual: https://www.remotion.dev/docs/
1. Configuración
node --version # Se requiere 18+, se prefiere 20/22 LTS
npx create-video@latest my-video # elige la plantilla en blanco
cd my-video
npx skills add remotion-dev/skills # habilidades oficiales del agente Remotion (recomendado)
npm run dev # Remotion Studio en http://localhost:3000
Renderizar:
npx remotion render <entry> <CompositionId> out/video.mp4 --codec=h264
npx remotion render <entry> <CompositionId> out/preview.mp4 --scale=0.5
npx remotion render <entry> <CompositionId> out/frames --sequence --image-format=png
Las banderas exactas varían según la versión; confirma con npx remotion render --help.
Licencias: Remotion es de código accesible, no es código abierto OSI. Gratuito para individuos y pequeñas organizaciones elegibles según sus términos actuales; los usos más grandes o comerciales/automatizados pueden requerir una licencia paga. Consulta https://www.remotion.dev/docs/license/pricing para el caso real del usuario antes de prometer una entrega. No lo describas como "MIT" o "gratuito para cualquier empresa".
2. Estructura del proyecto
Adáptate al iniciador en lugar de luchar contra él:
src/
Root.tsx # registra las composiciones
compositions/
MainVideo.tsx # secuencia las escenas juntas
scenes/
Intro.tsx Feature.tsx Outro.tsx
components/
AnimatedTitle.tsx Background.tsx Grid.tsx Caption.tsx Transition.tsx
animations/
easing.ts timing.ts reveal.ts
data/
content.ts # texto y números, separados del diseño
styles/
tokens.ts # paleta, escala tipográfica, espaciado
public/
audio/ fonts/ images/ video/
Reglas:
- Una escena por archivo;
MainVideosolo las secuencia. - El texto y los datos viven en
data/, nunca en línea en cinco escenas. - Los tokens de diseño en
styles/tokens.ts; sin valores hexadecimales mágicos dispersos. - Primitivas reutilizables en
components/, nunca duplicadas por escena. staticFile("...")para todo lo que esté enpublic/.
3. Determinismo (la regla estricta)
Todo el estado visual se deriva del fotograma actual:
import { useCurrentFrame, useVideoConfig, interpolate, spring } from "remotion";
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
Prohibido como controladores de animación: Date.now(), setTimeout, setInterval, requestAnimationFrame, keyframes de CSS, Math.random() sin semilla, datos asíncronos que cambian entre renderizados.
Aleatoriedad con semilla cuando se desea variación:
export const rand = (seed: number) => {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
};
Los activos asíncronos deben resolverse antes de que se renderice el fotograma. Usa delayRender/continueRender correctamente, siempre continuando en un catch, o precarga los activos fuera del fotograma (recomendado).
4. Temporización
durationInFrameses explícito. A 30 FPS, 10 s = 300 fotogramas, índices 0–299.- Convierte una vez:
const s = (n: number) => Math.round(n * fps). - Los límites de las escenas provienen de una línea de tiempo acumulativa, nunca de redondeo por escena.
- Usa
<Sequence from={start} durationInFrames={len}>; asegúrate de que nada se extienda más allá de la composición. - Haz que las superposiciones sean intencionales; un espacio de un fotograma es un destello visible.
- Usa
calculateMetadatacuando la duración o las dimensiones provengan de props.
5. Arte de la animación
| Movimiento | Primitiva |
|---|---|
| Entrada/Asentamiento | spring o interpolate con Easing.out(Easing.cubic) |
| Salida | Easing.in(Easing.cubic) |
| Movimiento simétrico | Easing.inOut(Easing.cubic) |
| Mecánico/Continuo | Easing.linear |
| Número/Color/Rotación | interpolate con extrapolación fijada |
| Escalonado | desplaza from por elemento (30–80 ms) |
const enter = spring({ frame, fps, config: { damping: 18, stiffness: 120, mass: 0.8 } });
const opacity = interpolate(frame, [0, 12], [0, 1], {
extrapolateLeft: "clamp", extrapolateRight: "clamp",
});
No apliques spring a todo. No animes cada propiedad. Prefiere transformaciones y opacidad (amigables con la GPU) sobre las propiedades de diseño. Asegura al menos ~0.8–1.2 s de permanencia para un titular corto, más para texto del cuerpo.
6. Tipografía y diseño
- Establece una escala tipográfica (ej. 96/64/40/28/20 px a 1080p) y úsala en todas partes.
- Carga fuentes desde
public/fontscon@remotion/fontso el patrón documentado del iniciador, y espera a que estén listas antes de renderizar. Evita depender de las fuentes del sistema. - Verifica la longitud de línea (≈45–75 caracteres), la altura de línea (1.1–1.4 para tipo de exhibición) y el tracking.
- Mantén márgenes seguros del 5–8%; verifica las superposiciones de la interfaz de usuario de la plataforma para formatos verticales/de redes sociales.
- Para persa/árabe: corrige
dir="rtl", fuente con capacidad de forma, verifica números/URLs mixtos e inspecciona el fotograma renderizado — Chrome sin cabeza forma el texto de manera diferente a algunas herramientas de diseño. - Verifica el texto final carácter por carácter. Los errores tipográficos en el video son errores de publicación.
7. Composición y transiciones
- Un punto focal por compás; anima el ojo, no toda la pantalla.
- Usa un vocabulario de transiciones: corte, fundido encadenado de 6–10 fotogramas, máscara de wipe, escala a través, desenfoque a través. Reutiliza deliberadamente.
- Prefiere cortar en un tiempo fuerte sobre disolver todo.
- Para videos largos, primero crea una tabla de tiempos (segundos → fotogramas → escena) y codifícala en un archivo.
8. Audio y subtítulos
import { Audio, staticFile } from "remotion";
<Audio src={staticFile("audio/music.mp3")} volume={0.6} />
- Importa solo en una secuencia que comience donde debe comenzar el sonido.
- Funde entrada/salida con
interpolateenvolume; evita clics. - Baja el volumen de la música debajo de la voz en off; mantén el diálogo inteligible.
- Subtítulos: quema con
<Caption>para redes sociales, o exporta.srtpara plataformas. Respeta las áreas seguras y la velocidad de lectura (~15–20 caracteres/seg). - Verifica la mezcla en el archivo codificado, no solo en la vista previa.
9. Rendimiento
- Reduce la concurrencia en máquinas con memoria limitada:
--concurrency=4. - Evita desenfoques gigantes, cadenas de filtros, SVG enormes y miles de nodos DOM; usa Canvas para gráficos densos.
- Almacena en caché los fondos estáticos (
<Freeze>o imagen prerenderizada). - Optimiza imágenes (tamaño correcto, WebP/AVIF cuando sea compatible) y recorta activos de video.
- Renderiza vistas previas a
--scale=0.5y rangos de fotogramas cortos primero.
10. Video por lotes y basado en datos
- Define un esquema de props y valídelo antes de renderizar.
- Mantén los datos en JSON/CSV; mantén el diseño en componentes.
- Ajusta el texto: líneas máximas, tamaño de fuente de respaldo, reglas de truncamiento, pruebas de desbordamiento.
- Renderiza cada variante desde la misma composición con diferentes
--props. - Escribe un manifiesto y verifica la duración y el tamaño no vacío de cada salida.
npx remotion render src/index.ts Main out/acme.mp4 --props='{"brand":"Acme","tagline":"Build faster"}'
11. Híbrido con Blender
- Renderiza la toma de Blender al mismo FPS, resolución y número de fotogramas que la composición de Remotion.
- Asigna el fotograma 1 de Blender al índice de fotograma 0 de Remotion a menos que el proyecto defina un desplazamiento.
- Para transparencia, exporta una secuencia PNG o ProRes 4444 y verifica el alfa sobre un tablero de ajedrez; MP4 no tiene alfa.
- Empareja el pipeline de color: codifica el pase de Blender con las mismas suposiciones de transferencia/transformación de vista que la salida del navegador, luego inspecciona la composición.
- Coloca el pase con
<OffthreadVideo>(no<Video>) dentro de una<Sequence>, y establecestartFrom/desplazamientos de fotograma desde el mapa de fotogramas.
12. Validación antes de la entrega
npx remotion compositions src/index.ts # lista IDs y dimensiones
ffprobe -v error -show_entries format=duration,size \
-show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt,channels \
-of json out/video.mp4
Luego inspecciona los fotogramas 0, cada límite de escena, cada transición, cada fotograma con mucho texto y el fotograma final. Verifica si hay texto recortado, fuentes faltantes, fotogramas negros y desviación de audio. Consulta video-composition para recetas de codificación/normalización y motion-studio/references/QUALITY-CHECKLIST.md para la compuerta completa.
13. Modos de fallo comunes
- Composición no encontrada → el archivo de entrada o el ID es incorrecto; ejecuta
npx remotion compositions. - Renderizado en blanco pero vista previa funcionando → la ruta del activo se resuelve en Studio pero no en modo headless; usa
staticFile, verifica el uso de mayúsculas/minúsculas enpublic/. - Las fuentes retroceden a Times → la fuente no se cargó antes del renderizado; espera a que esté lista.
- Diferentes salidas entre renderizados → tiempo de reloj de pared o aleatoriedad sin semilla.
- OOM o extremadamente lento → baja
--concurrency, reduce el desenfoque/escala, divide el renderizado. - Audio desincronizado →
startFromincorrecto, falta de coincidencia de FPS o fuente de velocidad de fotogramas variable.