E1 · Primer MP4 en React
10 minEjecuta el bloque "instalar, renderizar y verificar".
Listo cuando: npm: 0, render: 0 y OK: 5,0 s · 1920×1080 · 30 fps · sem áudio con saída: 0.
Clase 5 · 15 min
Remotion hace lo mismo que HyperFrames con otro lenguaje: cada fotograma es un componente React que recibe el número del fotograma. interpolate mapea fotogramas en valores y spring le da física a la entrada. En esta clase renderizas la misma idea de la clase 2 en React, lees la licencia y decides cuándo vale más cada motor.
Empezar la clase
Objetivo: renderizar una composición Remotion con interpolate y spring y decidir entre Remotion y HyperFrames.
Haz clic en cada pieza. Compárala con el diagrama de la clase 1: es el mismo dibujo en React.
HyperFrames: tiempo en segundos y GSAP. Remotion: tiempo en fotogramas y React.
Título con spring, filete y subtítulo con interpolate. El package.json fija remotion 4.0.537 (npm, 19/10/2026).
import {AbsoluteFill, Composition, Easing, interpolate, registerRoot, spring, useCurrentFrame, useVideoConfig} from 'remotion';
// Todo es función del fotograma actual: el mismo fotograma dibuja siempre la misma imagen.
const Abertura: React.FC = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// spring: entra con física (0 → 1), empezando en el fotograma 10
const entra = spring({frame: frame - 10, fps, config: {damping: 200}});
// interpolate: mapea fotogramas a valores; clamp sujeta el valor en los extremos
const apoio = interpolate(frame, [30, 50], [0, 1], {extrapolateLeft: 'clamp', extrapolateRight: 'clamp'});
const barra = interpolate(frame, [20, 60], [0, 640], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
return (
<AbsoluteFill style={{background: '#0c0c10', justifyContent: 'center', paddingLeft: 200, fontFamily: 'system-ui, sans-serif'}}>
<h1 style={{color: '#f4f4f5', fontSize: 120, lineHeight: 1.1, margin: 0, opacity: entra, transform: `translateY(${(1 - entra) * 60}px)`}}>
Vídeo é React
</h1>
<div style={{width: barra, height: 6, background: '#e9b949', margin: '36px 0'}} />
<p style={{color: '#a1a1aa', fontSize: 48, margin: 0, opacity: apoio}}>Um componente, um quadro, um MP4.</p>
</AbsoluteFill>
);
};
const Raiz: React.FC = () => (
<Composition id="Abertura" component={Abertura} durationInFrames={150} fps={30} width={1920} height={1080} />
);
registerRoot(Raiz);{
"name": "abertura-remotion",
"private": true,
"description": "Ensayo del curso Motion por código con agente (INEMA.CLUB): una composición Remotion mínima.",
"scripts": {
"render": "remotion render src/index.tsx Abertura out/abertura.mp4"
},
"dependencies": {
"@remotion/cli": "4.0.537",
"react": "19.3.1",
"react-dom": "19.3.1",
"remotion": "4.0.537"
}
}K=~/projetos/formacao-cinema-ia-motion-v72/kit
E=${TMPDIR:-/tmp}/ensaio-motion/a5; rm -rf "$E"; mkdir -p "$E/remotion"
cp -r "$K"/remotion/{package.json,package-lock.json,src} "$E/remotion/"; cd "$E/remotion"
npm ci --no-audit --no-fund > npm.log 2>&1; echo "npm: $?"
npx remotion render src/index.tsx Abertura out/abertura.mp4 --concurrency=2 > render.log 2>&1
echo "render: $?"
python3 "$K/conferir.py" out/abertura.mp4 5 1920x1080; echo "saída: $?"npm: 0 render: 0 OK: 5,0 s · 1920×1080 · 30 fps · sem áudio saída: 0
El npm ci instala 245 MB en node_modules (medido en esta máquina). El primer render puede descargar el navegador que usa Remotion.
Pedir el render con el id en minúscula.
cd ${TMPDIR:-/tmp}/ensaio-motion/a5/remotion
npx remotion render src/index.tsx abertura out/errado.mp4 2>&1 | grep -m1 -o "Could not find composition.*"
echo "render: ${PIPESTATUS[0]}"npx skills add remotion-dev/skills
Could not find composition with ID abertura. Available compositions: Abertura render: 1
El id distingue mayúsculas de minúsculas. El mensaje lista los ids que existen: copia de ahí.
Qué leer antes de usarlo en un proyecto de empresa.
El LICENSE.md de Remotion libera el uso gratuito para personas físicas, organizaciones sin fines de lucro y empresas de hasta 3 personas; por encima de eso, la empresa necesita la licencia de pago.
HyperFrames es Apache-2.0: uso libre, incluso comercial.
La página de migración de Remotion 5.0 menciona un cambio de licencia (los contratistas pasarían a contar en el equipo). El 19/10/2026 la 5.0 no había salido y la regla no estaba confirmada: vuelve a leer el LICENSE.md cuando actualices.
Equipo que ya escribe React, componentes reutilizados de una app, datos pasados por props, video generado dentro de un producto en React.
Pieza que un agente escribe desde cero, sin build; check con layout y contraste integrados; snapshot de fotogramas; TTS y transcripción locales en el mismo CLI (clase 7).
El ensayo, el error y un cambio tuyo.
Ejecuta el bloque "instalar, renderizar y verificar".
Listo cuando: npm: 0, render: 0 y OK: 5,0 s · 1920×1080 · 30 fps · sem áudio con saída: 0.
Ejecuta el bloque del id equivocado.
Listo cuando: Could not find composition with ID abertura. Available compositions: Abertura y render: 1.
En /tmp/ensaio-motion/a5/remotion/src/index.tsx, cambia durationInFrames a 180 y el easing de la barra a Easing.out(Easing.exp). Renderiza de nuevo con el mismo comando del bloque.
Listo cuando: python3 ~/projetos/formacao-cinema-ia-motion-v72/kit/conferir.py out/abertura.mp4 6 1920x1080; echo "saída: $?" → OK: 6,0 s · 1920×1080 · 30 fps · sem áudio y saída: 0.
La explicación aparece después de tu respuesta.
Pregunta 1 de 4
¿durationInFrames={150} a fps={30} equivale a cuántos segundos?
Pregunta 2 de 4
¿Para qué sirve extrapolateRight: 'clamp' en interpolate?
Pregunta 3 de 4
Una empresa de 12 personas quiere usar Remotion 4 en videos de clientes. ¿Qué hacer antes?
Pregunta 4 de 4
¿Cuándo suele valer más Remotion que HyperFrames?
Elige una alternativa. La explicación aparece después de tu intento.