El video es código: composición con tiempo y render determinista
En el motion por código, el video es una página que sabe dibujar cualquier instante. Un navegador sin pantalla pide el fotograma 0, el 1, el 2, y FFmpeg junta todo en un MP4. Si la misma entrada da siempre los mismos fotogramas, puedes rehacer, corregir y versionar el video como código. En esta lección lo compruebas en tu máquina.
1Las cuatro piezas: composición, reloj, navegador sin pantalla y codificador
2Comparar dos renders fotograma a fotograma con un comando
3Por qué Math.random y Date.now rompen el video
4Sorteo con semilla: variedad sin perder la repetición
Objetivo: comprobar en tu máquina que la misma composición da los mismos fotogramas y encontrar lo que lo rompe.
01 · Del código al MP4
Haz clic en cada pieza. HyperFrames (HTML) y Remotion (React) siguen el mismo diseño.
misma entrada → mismos fotogramas
Entre máquinas distintas, la GPU y las fuentes pueden cambiar algunos píxeles; para repetir en otra máquina, el render de la 0.8.176 tiene --docker ("deterministic render") y --no-browser-gpu.
Determinístico = correr dos veces en el mismo entorno y obtener los mismos fotogramas. Es lo que permite corregir un detalle sin rehacer todo lo demás.
02 · Lo que rompe la repetición
Tres fuentes de azar que el lint de HyperFrames detecta.
1. Sorteo
Cada render sortea de nuevo: los mismos 12 puntos nacen en lugares distintos.
El reemplazo es un sorteo con semilla (mulberry32): la misma semilla da los mismos números, siempre.
Reemplazoconst sorteio = mulberry32(42); luego sorteio() en lugar de Math.random().
2. Reloj de la máquina
La hora actual cambia en cada render y en cada fotograma.
Todo lo que anima debe venir del tiempo que entrega el motor, nunca del reloj de la computadora.
3. Red en el momento
Buscar datos en internet durante el render puede traer otra respuesta o fallar a la mitad.
Búscalos antes, guárdalos en un archivo de la carpeta y léelos desde ahí (la lección 7 hace esto con los subtítulos).
03 · El ensayo: dos renders, comparados fotograma a fotograma
Dos composiciones casi iguales: una usa Math.random, la otra un sorteo con semilla. Cada una se renderiza dos veces y se compara por el hash de cada fotograma.
Son 90 fotogramas (3 s a 30 fps). Con Math.random solo coincide el primero; con la semilla, los 90. El primer render descarga hyperframes@0.8.176 y el navegador, por eso tarda más.
Comparar el MP4 con md5sum puede dar distinto aunque los fotogramas sean iguales (metadatos del archivo). El comparar-quadros.sh decodifica y compara la imagen de cada fotograma con ffmpeg -f framemd5.
04 · El lint encuentra el azar antes del render
El mismo par de composiciones pasado por el lint de HyperFrames. Señala la línea y sugiere la semilla.
Terminal · lint de las dos composiciones
K=~/projetos/formacao-cinema-ia-motion-v72/kit
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
for ex in a1-sorteio a1-semente; do
cd "$K/exemplos/$ex"
npx -y hyperframes@0.8.176 lint; echo "saída: $?"
done
Ejemplo del repositorio
◆ Linting a1-sorteio/index.html
✗ [~/projetos/formacao-cinema-ia-motion-v72/kit/exemplos/a1-sorteio/index.html:24:24] non_deterministic_code: Script contains `Math.random()` which produces non-deterministic output. Renders may differ between frames or runs.
Fix: Use a seeded PRNG (e.g. a simple mulberry32) so renders are deterministic across frames.
◇ 1 error(s), 0 warning(s)
saída: 1
◆ Linting a1-semente/index.html
◇ 0 errors, 0 warnings
saída: 0
El lint sale con código 1 cuando encuentra un error: puedes usarlo como compuerta antes de cualquier render.
05 · Práctica
Ensayo, lint y tu semilla.
E1 · Ver el azar y la semilla
10 min
Clona el curso en ~/projetos y ejecuta el bloque "dos renders de cada uno y la comparación".
Listo cuando: a1-sorteio termina en DIFEREM: 89 de 90 quadros y saída: 1; a1-semente en IGUAIS: 90/90 quadros y saída: 0. (En tu computadora el número de fotogramas distintos puede variar; lo que no puede pasar es que la semilla dé distinto.)
E2 · El lint como compuerta
5 min
Ejecuta el bloque del lint.
Listo cuando: a1-sorteio muestra non_deterministic_code y saída: 1; a1-semente muestra 0 errors, 0 warnings y saída: 0.
E3 · Otra semilla, misma garantía
10 min
En /tmp/ensaio-motion/a1/a1-semente, cambia mulberry32(42) por mulberry32(7), renderiza dos veces (render-3.mp4 y render-4.mp4, con el mismo comando del bloque) y compara: 3 con 4, después 1 con 3.
Listo cuando:bash ~/projetos/formacao-cinema-ia-motion-v72/kit/comparar-quadros.sh render-3.mp4 render-4.mp4 → IGUAIS: 90/90 quadros; lo mismo con render-1.mp4 render-3.mp4 → empieza con DIFEREM:.
06 · Prueba de la clase
La explicación aparece después de tu respuesta.
Pregunta 1 de 4
¿Quién decide qué instante dibuja la composición?
Correcto
El motor pide el instante (2,5 s, fotograma 75) y la composición dibuja ese instante. Por eso la velocidad no cambia el resultado: en el mismo entorno, una máquina lenta tarda más, pero da los mismos fotogramas.
No es esa
El motor pide el instante (2,5 s, fotograma 75) y la composición dibuja ese instante. Por eso la velocidad no cambia el resultado: en el mismo entorno, una máquina lenta tarda más, pero da los mismos fotogramas.Repasar: Del código al MP4
Pregunta 2 de 4
Dos renders de la misma composición dieron 89 de 90 fotogramas distintos. ¿Qué buscar primero?
Correcto
El azar dentro de la composición es la causa más común, y el lint señala Math.random con la línea. Los dos renders usaron el mismo hyperframes@0.8.176 y el mismo FFmpeg: lo que cambió fue la entrada.
No es esa
El azar dentro de la composición es la causa más común, y el lint señala Math.random con la línea. Los dos renders usaron el mismo hyperframes@0.8.176 y el mismo FFmpeg: lo que cambió fue la entrada.Repasar: Lo que rompe la repetición
Pregunta 3 de 4
¿Para qué sirve el sorteo con semilla?
Correcto
La semilla fija la secuencia de números: los puntos siguen esparcidos, pero siempre en los mismos lugares. Cambiar la semilla cambia el dibujo a propósito, y de nuevo de forma repetible.
¿Por qué comparar fotograma a fotograma y no el MP4 completo?
Correcto
Lo que importa es la imagen. framemd5 decodifica cada fotograma y compara los píxeles; el hash del archivo completo también cambia con metadatos que no aparecen en la pantalla.