Motion por código con agente|INEMA.CLUB-PRO

Clase 5 · 15 min

Remotion: frame, interpolate, spring y cuándo elegir React

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
Monitor de edición con una curva de animación suave dibujada como gráfico y una línea de tiempo de fotogramas debajo.

En esta clase vas a

  1. 1Composition: id, fps, duración en fotogramas y tamaño
  2. 2interpolate con clamp y easing; spring con amortiguación
  3. 3La licencia de Remotion en oct/2026
  4. 4HyperFrames o Remotion: el criterio de elección

Objetivo: renderizar una composición Remotion con interpolate y spring y decidir entre Remotion y HyperFrames.

01Remotion por dentro

Haz clic en cada pieza. Compárala con el diagrama de la clase 1: es el mismo dibujo en React.

Haz clic en cada bloque del diagrama para ver qué hace.

HyperFrames: tiempo en segundos y GSAP. Remotion: tiempo en fotogramas y React.

02La composición en React

Título con spring, filete y subtítulo con interpolate. El package.json fija remotion 4.0.537 (npm, 19/10/2026).

Archivo · kit/remotion/src/index.tsx
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);
Archivo · kit/remotion/package.json
{
  "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"
  }
}
Terminal · instalar, renderizar y verificar
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: $?"
Ejemplo del repositorio
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.

03El error más común, aislado

Pedir el render con el id en minúscula.

Terminal · render con el id equivocado
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]}"
Opcional · skills oficiales de Remotion para el agente
npx skills add remotion-dev/skills
Ejemplo del repositorio
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í.

04Licencia y elección

Qué leer antes de usarlo en un proyecto de empresa.

1. Licencia hoy

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.

05Práctica

El ensayo, el error y un cambio tuyo.

E1 · Primer MP4 en React

10 min

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.

E2 · Leer el error

5 min

Ejecuta el bloque del id equivocado.

Listo cuando: Could not find composition with ID abertura. Available compositions: Abertura y render: 1.

E3 · Seis segundos y otra curva

15 min

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.

06Prueba de la clase

La explicación aparece después de tu respuesta.

Pregunta 1 de 4

¿durationInFrames={150} a fps={30} equivale a cuántos segundos?

07En tres frases

FotogramaEn Remotion todo es función del número de fotograma: interpolate y spring dibujan la curva.
LicenciaGratis hasta 3 personas en la 4.0.x; lee el LICENSE.md en cada actualización.
ElecciónReact cuando hay React que reutilizar; HTML cuando el agente escribe desde cero.

Para ir más allá

Clase anteriorPróxima clase