¿Qué hace make-video?
Convierte una idea en un MP4 renderizado y verificado usando solo herramientas gratuitas y locales. Un proyecto creado con esta habilidad tiene sus propias reglas en AGENTS.md, así que síguelas (pureza de animación, useScale, sec(), estructura de carpetas).
0. Configurar un proyecto de video (una vez)
Si la carpeta actual no tiene tools/make-story.sh, aún no es un proyecto de video:
-
Verifica la máquina antes que nada:
uname -sm(necesita Darwin arm64),node --version(20+),brew --version,df -h ~(unos 8 GB libres). En otro SO, di qué no funcionará (Chatterbox y el verificador de tomas funcionan en la GPU de Apple) antes de continuar. Si falta Node o Homebrew, dale al usuario el comando de instalación y espera. -
Dile al usuario qué se descargará y espera su aprobación. Nunca inicies las descargas sin ella. Muestra esta tabla (todo gratuito, de las fuentes oficiales):
Descarga Tamaño Usado para Dónde va Paquetes npm (Remotion, etc.) ~500 MB renderización node_modules/ffmpeg, uv, FluidSynth (Homebrew, solo si faltan) ~150 MB herramientas de audio/video Homebrew Paquetes Python (PyTorch, Chatterbox…) ~1.5 GB voz, QA .venv/Soundfont GeneralUser GS ~30 MB música tools/soundfonts/Pesos de Chatterbox ~3 GB la voz Caché de Hugging Face ( ~/.cache/huggingface), compartido por todos los proyectosWhisper small.en ~590 MB subtítulos tools/models/Whisper large-v3-turbo (verificador de tomas opcional) ~1.6 GB regrabar líneas poco claras Caché de Hugging Face Total unos 6 GB y 10-20 minutos. Ofrece la opción más ligera:
SKIP_TAKE_CHECK=1omite el verificador de tomas (4.4 GB en total). Pregunta dónde crear el proyecto (por defecto~/videos). -
Tras su aprobación, copia la carpeta
template/que está junto a este SKILL.md en el proyecto, incluidos los archivos ocultos (cp -R <directorio skill>/template/. <dest>/), luegogit init. -
Ejecuta
tools/setup.shen segundo plano y mantén al usuario informado: di en qué paso está (imprime líneas▶) y, durante la gran descarga, cuánto falta (du -shL ~/.cache/huggingface/hub/models--ResembleAI--chatterbox, objetivo ~3 GB). Es seguro volver a ejecutarlo: los pasos terminados se saltan y las descargas interrumpidas se reanudan. Si una descarga se estanca (el tamaño no crece durante 5 minutos), detenla y ejecuta la configuración de nuevo. Si falla, lee el error, corrige la causa (herramienta faltante, espacio en disco, red) y vuelve a ejecutar; no evites un modelo faltante. -
Demuestra que funciona:
tools/make-story.sh stories/fridge-drama FridgeDramahace el ejemplo de 33 s (tres verduras discuten en una nevera) en unos 4 minutos. Muéstrale al usuarioout/FridgeDrama.mp4, luego pregúntale qué quiere hacer.
Las herramientas encuentran los modelos por sí solas (Chatterbox y el verificador de tomas desde la caché de Hugging Face, los subtítulos desde tools/models/), por lo que no es necesario configurar nada después de la instalación. Un segundo proyecto reutiliza los pesos en caché, por lo que su configuración es mucho más rápida.
1. Definir el brief (pregunta solo si falta)
| Campo | Predeterminado |
|---|---|
| Plataforma / formato | Reel/Short: 1080×1920, 30 fps · YouTube: 1920×1080, 30 fps · Publicación en feed: 1080×1350 |
| Duración | Reel/Short: 15-45 s · YouTube: 3-10 min |
| Tipo | Historia (los personajes hablan, así que usa §3B) o Gráficos en movimiento (texto, datos, diagramas, así que usa §3A) |
| Tema + conclusión única | Lo único que el espectador debe recordar |
| Audio | Voz (Chatterbox), música + SFX (tools/music.py), o solo música |
| Voz | Voz incorporada de Chatterbox, o un clon de la grabación del propio usuario (§3B). Nunca clones a alguien sin su consentimiento. |
2. Escribir el guion antes de cualquier código
Presupuesto de duración: el inglés hablado al ritmo de Chatterbox tiene unas 2.6 palabras/s. Duración objetivo ≈ palabras ÷ 2.6 + Σ pausas + outro. Verifícalo antes de generar. (Fridge Drama: 62 palabras + 6.4 s de pausas + 3 s de outro = 33 s.)
Reglas de ritmo para formato corto vertical:
- El gancho debe estar en pantalla y ser audible desde el fotograma 0. Los primeros 1.5 s deciden la retención, y el fotograma 0 suele ser la miniatura, así que nunca empieces con un fotograma vacío o desvaneciéndose.
- Cada línea ≤ 12 palabras. Los subtítulos muestran ≤ 3 palabras a la vez.
- Algo se mueve cada segundo.
- Zona segura para 1080×1920: nada importante por encima de y=220 ni por debajo de y=1540 (interfaz de la plataforma), y nada a la derecha de x≈940 debajo de y≈1000: los botones de me gusta, comentar y compartir están en el borde derecho (
tools/qa.py --layoutlo detecta). Coloca al presentador abajo a la izquierda. - Termina con un remate o un golpe de efecto, luego una tarjeta de llamada a la acción de 2-3 s.
Plantilla de explicación ("cómo funciona" y reels de consejos para desarrolladores, 45-60 s, 120-160 palabras):
- Gancho (≤ 3 s): un hecho o resultado sorprendente verdadero.
- "Aquí está cómo funciona realmente": una línea que abre la explicación.
- 2-4 puntos, cada uno con un número + una analogía ("un video son solo 30 fotos por segundo, como un folioscopio").
- "Pero aquí está el truco": el giro, el error o el problema común.
- Remate de una línea, luego una llamada a la acción clara (guardar, compartir o seguir).
Luego enumera cada afirmación factual con un enlace a la fuente debajo del guion, marca cualquier cosa que no puedas verificar, y corrígelo o elimínalo antes de la locución. Muestra la fuente en pantalla (pequeña, en la parte inferior de la tarjeta) cuando aparezca un número o una afirmación.
Lista de verificación de calidad para Shorts/Reels:
- Progreso visible. Los videos paso a paso obtienen
<StepCard steps={[{at: 0, title: 'Descárgalo'}, …]} />(src/components/StepCard.tsx): una pastilla "PASO 2/4" y una barra segmentada. - Subtítulos karaoke (estilo opcional).
<Karaoke words={captions} keywords={['gratis']} style={{left: 60, right: 140, top: 1180}} />(src/components/Karaoke.tsx): el fragmento completo de 2 a 5 palabras está en pantalla, las palabras habladas en sólido, las próximas en gris, las palabras clave y las acentuadas en el color de acento, para que los espectadores puedan leer por adelantado en la reproducción automática silenciada.backgroundda un aspecto de tarjeta clara; pasaqapara que la verificación de diseño lo vea. - Chip de serie. Un marcador de episodio en la parte superior izquierda ("PARTE 2") hace que las publicaciones parezcan dignas de maratón.
- Muestra el contraste. Un antes/después o "nosotros vs ellos" funciona mejor como tarjeta de dos columnas que como discurso.
- Los latidos de la historia vencen a las listas. "El intento 1 falló → el intento 2 falló → lo que funcionó" mantiene la atención mejor que una lista de funciones.
- Remate antes de la CTA. Una línea humana, luego la llamada a la acción.
- Solo prometas una recompensa de "comenta PALABRA CLAVE y te enviaré un DM" si hay algo real (una guía, un prompt, un repositorio) esperando detrás.
Escribir para TTS:
- No empieces una línea con "…": Chatterbox improvisa una palabra de relleno.
- No empieces una línea con un número en palabras ("Dos. La cara" salió como "a la cara"). Escribe "Segundo, …".
- Escribe números y nombres extraños como se pronuncian ("cinco punto seis", "X Z"), y pon el texto real en el campo
captionde la línea. - Redondea números grandes ("más de 600"); TTS distorsiona "646" y "87.000".
- Las palabras cortas en los ganchos se difuminan ("Este repo" se escuchó como "Los tres"). Reformula hasta que el verificador de tomas las escuche bien.
- No hagas que varias voces griten la misma palabra corta juntas; la mezcla la emborrona.
- La puntuación dirige la entonación: "?" eleva, "." aterriza, MAYÚSCULAS añaden énfasis.
3A. Video de gráficos en movimiento
- Copia
src/compositions/_Template→src/compositions/<Nombre>, con un componente por tipo de punto (Gancho, Punto, Estadística, Lista, CTA). - Calcula la duración a partir del guion (suma de puntos − transiciones), como lo hace
getSampleIntroDuration. - Regístralo en
src/Root.tsxcondefaultPropsen línea. - Solo música: escribe un JSON de línea de tiempo con
totalMs,outroStartMsyevents, luego ejecutatools/music.py.
3B. Historia narrada (personajes + subtítulos + música)
Crea stories/<slug>/script.json (copia stories/fridge-drama/script.json):
characters:color,exaggeration(0.3 calmado → 0.9 dramático), y opcionalmenterefVoice: un WAV limpio de 10-30 s entools/voices/para clonar. Sin él, se usa la voz incorporada de Chatterbox. Para clonar la voz del usuario: que grabe 60-90 s hablando de forma natural en una habitación silenciosa, luego corta un fragmento limpio de 10-15 s sin música ni eco (ffmpeg -ss <inicio> -t 12 -i nota.m4a -af highpass=f=80,loudnorm=I=-18 -ar 24000 tools/voices/me.wav).lines:speaker,text,pauseAfter(s), opcionalevent+eventAt: 'start'para marcar los latidos de la historia (se abre la puerta, esconderse…) de los que tanto la animación como la música toman referencia.- Dirección de voz opcional por línea:
emotion(calm|neutral|warm|excited|dramatic|whisper),pace(slow|normal|fast),emphasis(palabras dichas en MAYÚSCULAS y resaltadas en los subtítulos),pauseBefore(s).'pace': 'slow'con pausas de 0.4 s hace que cada palabra sea clara.
Luego ejecuta un comando:
tools/make-story.sh stories/<slug> <CompositionId> # voz → subtítulos → música/SFX → lint → render → master → QA
SKIP_VOICE=1 tools/make-story.sh … # iterar solo en lo visual
SAMPLE=15 tools/make-story.sh … # renderizar los primeros 15 s para aprobación, luego parar
| Herramienta | Salida |
|---|---|
tools/voice.py | public/<slug>/lines/*.wav (almacenado en caché por texto + configuración de voz), public/<slug>/voice.wav, stories/<slug>/timeline.json (temporización de líneas, eventos, envolventes bucales por fotograma). Con el verificador de tomas instalado, Whisper escucha cada frase y regraba las poco claras (VOICE_TAKES, por defecto 3). |
tools/captions.mjs | public/<slug>/captions.json (temporización de palabras de Whisper, ortografía del guion), stories/<slug>/captions-report.json (tasa de error de palabras y palabras coincidentes por línea, los "rellenos" que Whisper omitió, matchRate general) |
tools/music.py | public/<slug>/music.wav (MIDI → FluidSynth, ajustado a los cortes), public/<slug>/sfx.wav |
tools/qa.py | stories/<slug>/qa/report.md: PASA / ARREGLA / FALLA |
Construye la composición a partir de timeline.json / captions.json (ver src/compositions/FridgeDrama/data.ts). Controla las bocas con mouthOpen(), la mirada hacia el hablante activo, los eventos a través de timeline.events.*, y la duración desde timeline.durationInFrames.
Cualquier cambio de temporización (texto o pausas) necesita subtítulos de nuevo. Los tiempos de los subtítulos son absolutos, por lo que se desvían de lo contrario. make-story.sh siempre vuelve a ejecutar los subtítulos.
4. Verificar (siempre, antes de decir que está listo)
tools/make-story.sh termina con tools/qa.py, que sale con código distinto de cero en caso de FALLO. Verifica el archivo, el volumen (-14 ±1 LUFS, pico verdadero ≤ -1), la precisión de los subtítulos, los cortes al ritmo (≤ 120 ms), los tramos congelados (≤ 3 s), la variedad visual (la raya más larga del mismo aspecto ≤ 5 s) y los subtítulos que repiten texto en pantalla. LAYOUT=<CompId> también verifica los subtítulos contra las zonas muertas y la cara (la composición necesita una propiedad qa que delinee los subtítulos #FF00FF y la cara #00FFFF). Lee stories/<slug>/qa/report.md y corrige cada FALLO y ARREGLA.
Luego verifica visualmente:
npm run lint.- Cualquier línea en
stories/<slug>/captions-report.jsoncon WER > 0.2 probablemente está farfullada: reformula y regenera (económico, gracias a la caché). Las palabras que Whisper omitió se colocan sobre la parte sonora del espacio solo, las palabras más largas reciben más tiempo, y se enumeran bajofilled: escucha esos lugares. Por debajo del 70% dematchRate, el guion y el audio difieren, así que vuelve a generar la voz antes de continuar. - Renderiza fotogramas clave (gancho, cada hablante, cada evento, outro), únelos en una hoja de contactos, y mírala:
Verifica el tamaño del personaje, la zona segura, las superposiciones que cubren personajes, los restos detrás del outro, la sincronización de subtítulos y el tamaño del texto (chips ≥ 28 px, cuerpo ≥ 54 px a 1080 de ancho).npx remotion still <Id> out/stills/f<N>.png --frame=<N> --scale=0.4 ffmpeg -i a.png -i b.png … -filter_complex hstack=inputs=K out/stills/contact.png - Extrae 4-5 fotogramas del MP4 final y míralos.
- Para cualquier cosa importante, pídele a un subagente nuevo que critique la hoja de contactos sin contexto. Los ojos nuevos encuentran problemas que el constructor pasa por alto.
5. Entregar
Dale al usuario el MP4, un título, un pie de foto, 3-5 hashtags y un fotograma de miniatura. Nunca publiques ni subas nada sin aprobación explícita. Recuérdales que marquen la etiqueta de "contenido alterado o sintético" de YouTube cuando se utilice una voz clonada o una cara generada por IA.
Reglas que ahorran horas
- Un render a la vez. Varios renders de Remotion a la vez sobrecargan la máquina durante horas. El pipeline ya pasa
--timeout=180000 --concurrency=2. - Agrega paquetes de Remotion con
npx remotion add <pkg>, nunca connpm isimple, para que las versiones se mantengan sincronizadas. - Volumen: diálogo −16 LUFS, fondo musical aproximadamente −24, master final −14 (dos pasos, ya en
make-story.sh). Mantén la voz al menos 10 dB por encima de la música. - Studio solo puede guardar ediciones de props cuando
defaultPropses un objeto en línea enRoot.tsx. - Escribe bucles zsh sobre filas como
while read -r a b c; do …; done <<EOF, ya quefor x in 'a b c'se rompe.
Más lecciones, y cómo añadir las tuyas: reference/lessons.md.
Costos medidos (M1 Max, 64 GB)
| Paso | Tiempo |
|---|---|
| Carga del modelo Chatterbox | ~20 s por ejecución (se omite cuando cada línea está en caché) |
| Generación de voz | primera línea ~55 s (calentamiento), luego ~3× tiempo real |
| Verificación de tomas | ~20-30 s por frase que necesita una retoma |
| Subtítulos (Whisper small.en, WebGPU) | ~10 s para 11 líneas |
| Música + SFX | 2-5 s |
| Render 1080×1920, 33 s | ~97 s (~3 s por segundo de video) |
| Pipeline completo | ~2 min con voz en caché; ~4 min desde cero |
make-video es de TheNoumanDev, de zero-dollar-studio. Es el pipeline detrás del canal de YouTube @0x45.dev.