¿Qué hace demo-reel?
Tú produces el vídeo completo: la persona te da el producto y lo que hay que mostrar, y recibe un MP4 que puede publicar. Todo en pantalla es el producto real, grabado en vivo; el pulido (marco de ventana, movimientos de cámara, subtítulos, tarjeta de título y final) se añade después desde la grabación.
El pipeline, y el archivo que genera cada paso:
| Paso | Comando | Genera |
|---|---|---|
| 1. Storyboard | tú, con la persona | 3–5 funcionalidades, un subtítulo cada una |
| 2. Escenario | escribe scenario.mjs | los pasos que daría un usuario |
| 3. Toma | bin/reel take scenario.mjs takes/take1 | take1.mov (imagen + sonido de la app), take1.json (eventos, posiciones de elementos) |
| 4. Edición | escribe edit.json | escenas, tomas, subtítulos, marca |
| 5. Fotogramas fijos | bin/reel check edit.json, bin/reel layers edit.json, luego bin/reel stills edit.json 1,4,9 | problemas detectados temprano; fotogramas de previsualización |
| 6. Subtítulos | bin/reel subtitles edit.json, luego leer y corregir build/subtitles.srt | lo que se dice, como subtítulos |
| 7. Renderizar | bin/reel render edit.json renders/x.mp4 --format all | el vídeo en cada formato, con su .srt |
| 8. Verificar | bin/reel sheet renders/x.mp4 1,4,9,… | hoja de contacto, duración, sonoridad |
examples/sawt/ es un ejemplo completo resuelto (una extensión de Chrome que lee artículos en voz alta). Abre
su scenario.mjs y edit.json antes de escribir los tuyos. docs/edit-format.md es la referencia del archivo
de edición; docs/lessons.md enumera lo que falló la primera vez, así que léelo antes de grabar.
0. Configuración (una vez)
Ejecuta bin/reel doctor primero: verifica todas las herramientas y permisos y dice qué corregir.
bin/reel setup construye el grabador (Swift, ScreenCaptureKit), instala playwright-core y Chrome
para pruebas. También se necesita: ffmpeg, uv, Google Chrome (para renderizar las capas superpuestas). La terminal
que te ejecuta necesita permiso de Grabación de Pantalla y Audio del Sistema (Configuración del Sistema → Privacidad y
Seguridad); si el grabador informa que no tiene permiso, pídele a la persona que lo conceda y reinicie la
terminal.
1. Storyboard
Acuerda, en pocas líneas, antes de grabar nada:
- las funcionalidades, en orden, cada una con un subtítulo: un breve encabezado ("Zoom de palabras") y un título de
como máximo dos líneas cortas, con el beneficio en
<b>("Sigue la lectura. Cada palabracrece mientras se habla."); - qué contenido real mostrar: una página pública, una cuenta de ejemplo, datos semilla. Elige contenido que haga lucir mejor la funcionalidad y verifica que funcione (para Sawt: un artículo cuyas palabras difíciles tengan tarjetas, en un sitio donde las tarjetas tengan espacio junto a la columna);
- la marca: color de acento, variante clara, tonos de fondo, logotipo; texto de tarjeta de título y final.
Formato predeterminado: 1080×1350 (4:5), 25–35 s — llena la mayor parte de un feed de teléfono, y la mayoría ve
sin sonido, así que los subtítulos deben contar la historia por sí solos. Pregunta dónde se publicará: 1:1, 9:16 y
16:9 se obtienen de la misma edición (--format), así que ofrécelos. Revisa los fotogramas fijos de cada formato que renderices:
una toma que encuadre bien en 4:5 puede cortar un encabezado en 1:1; ajústalo por formato ("1:1": {"dy": 20}).
Cuando el producto hable (o la toma tenga narración), crea subtítulos: reel subtitles, luego lee
el .srt y corrige nombres y jerga antes de renderizar — la transcripción es buena, no perfecta.
Pon las palabras difíciles en subtitles.words para guiarla.
2. Escenario
Un escenario es un módulo ES (consulta drive/take.mjs para la API completa):
export const config = { url: "https://…", width: 1700, height: 1090, extension: "./ext" };
export async function setup(api) { /* ajustes, inicio de sesión; api.rect("title", "h1") para objetivos de cámara */ }
export async function run(api) { /* la demo; api.mark("paso") en cada momento en que vayas a cortar */ }
export async function after(api) { /* fotogramas fijos para mostrar como escenas de imagen, p.ej. un popup a 3x */ }
- Marca cada momento en que vayas a cortar o mover la cámara (
api.mark("oración", {n})). La edición se ancla a estas marcas, así que una toma que vaya más rápida o lenta seguirá cortando en el lugar correcto. - Graba objetivos de cámara con
api.rect(nombre, selector | fn, arg)en píxeles del viewport. Los elementos dentro de un shadow root cerrado no se pueden medir: calcula dónde estarán (consulta las tarjetas de Sawt). - Los productos basados en clics necesitan un puntero visible. La automatización no mueve un cursor real, así que
las formas aparecen y los botones se presionan solos. Llama a
api.pointer.show()ensetup, luego dirige conapi.pointer.click(selector | [x, y]),.drag(from, to),.move(x, y),.type(texto)y.key(k): una flecha en la página sigue, los clics se ondulan, los movimientos son suaves y la escritura tiene ritmo humano. Controla los clics por selector (untitleoaria-labelsuele ser estable) para que sus posiciones provengan de la página. - Contenido en canvas (dibujos, gráficos, mapas) no tiene elemento que medir: graba el cuadro en el que dibujaste
con
api.rect(nombre, {x, y, ancho, alto})en px CSS. - Extensiones de Chrome: ejecuta acciones a través del propio código de la extensión con
api.inWorker(fn). Una extensión que dependa deactiveTabnecesita una copia de grabación con acceso al host, porque la automatización no puede presionar los atajos del navegador (consultaexamples/sawt/prepare.sh). No cambies nada que vea un espectador. - Popups y otras IU pequeñas: captúralos en
after()con deviceScaleFactor 3 mediante CDP (consulta el ejemplo), y muéstralos como una escena de imagen. Captura ambos estados de un toggle en el mismo momento haciendo clic en el control real, no recargando la página.
Ejecútalo, luego mira la toma antes de editar: ffmpeg -ss 6 -i takes/take1.mov -frames:v 1 x.png
y lee el PNG. Verifica que la página esté estilizada, que la funcionalidad se haya disparado, que nada la cubra. Vuelve a grabar
libremente: una toma cuesta un minuto.
3. Edición
Escribe edit.json (referencia: docs/edit-format.md). Reglas para que parezca hecho, no grabado:
- Corta en las pausas.
bin/reel speech take1.movlista dónde hay sonido; las piezas de la toma comienzan justo antes de un paso y terminan antes de que comience el siguiente. Anclalas a las marcas:"oración#5-0.15". - El contenido lado a lado no cabe en ventanas altas. Una barra de herramientas a la izquierda y un diagrama a la
derecha pueden necesitar más ancho del que muestra una ventana 4:5;
reel checkadvierte, por formato, cuánto perderá una toma ajustada. Ajusta menos cosas o desplaza la toma para ese formato. - Tomas desde rectángulos.
{"fit": ["title", {"rect": "card1", "dh": 330}], "pad": 60}. Un plano general amplio, luego acerca a lo que habla el subtítulo. Mantén el texto al menos ~20 px de alto en la salida; un plano general puede ser más pequeño por un momento, nunca por mucho tiempo. - Un subtítulo por escena, presente durante toda la escena; cambia los subtítulos solo con un movimiento de cámara.
- Deja respirar los movimientos: 1.0–1.5 s por movimiento de cámara, mantén al menos 1.5 s después de que se detenga.
- Tarjeta de título 2–2.5 s, tarjeta final 3–3.5 s. Escenas de imagen (un popup, un panel de ajustes) 3–4 s.
Velocidad
Un renderizado de 30 segundos en 4:5 tarda unos 3 minutos en un portátil de 6 núcleos: los fotogramas se renderizan
en fragmentos paralelos (4 por defecto; --jobs N), se unen sin recodificar y las capas sin cambios se reutilizan.
Mientras la edición aún se mueve, usa reel render … --draft (15 fps, codificador rápido, aproximadamente la mitad
del tiempo) y reel stills; renderiza la versión real una vez que los fotogramas fijos se vean bien.
4. Verificar, siempre
bin/reel layersybin/reel stillsal principio, en medio y al final de cada escena y en cada movimiento de cámara. Lee cada PNG. Busca: texto o IU cortados en los bordes del fotograma, un encabezado medio visible en la parte superior, un subtítulo sobre algo importante, un fotograma que sea una página vacía.- Renderiza, luego
bin/reel sheeten todo el vídeo y léelo. - La duración debe ser la planeada; la sonoridad alrededor de −16 LUFS cuando el producto hace sonido.
- Sincronización: el momento en que aparece un paso en pantalla y su sonido comienza debe coincidir con la toma.
Luego pon el MP4 delante de la persona, con la miniatura (build/layers/title.png), y di
claramente qué es real y qué se cambió para la grabación.
Música
Por defecto, el sistema elige una banda sonora que se adapte al vídeo (docs/music.md): perfila el vídeo
(duración, habla, ritmo, palabras de los subtítulos), clasifica candidatos instrumentales con licencia — la carpeta
music/ de la persona, luego la biblioteca CC0 incluida (library/), luego en línea solo si nada local
encaja — por tempo medido, energía y estabilidad, y conserva la mejor. Ejecuta reel music auto edit.json --audition renders/x.mp4
para ver la clasificación y obtener una vista previa de las mejores pistas. Tú no puedes oír, así que pasa las vistas previas a la
persona antes de dar el vídeo por terminado. Cuando las mejores pistas sean solo enlace (el sitio bloquea las descargas
con script), dale los enlaces a la persona; ella descarga una y ejecuta reel music add <archivo> --candidate N.
Si la persona trae su propia pista, registra su licencia con reel music add y ponla en la edición.
Siempre dale el .credits.txt junto al renderizado, y di cuándo su licencia necesita un crédito publicado.
Límites
- La grabación es solo macOS (ScreenCaptureKit). La composición y las capas funcionan en cualquier lugar.
- Solo productos de navegador hasta ahora; una aplicación de escritorio necesita su propio controlador (scripting de accesibilidad), pero
el grabador (
--app <id del bundle>) y todo lo posterior ya funcionan para cualquier aplicación. - Generar música (
reel music generate) necesita un modelo local conectado; se sugiere ACE-Step, pero aún no se ha probado con demo-reel.