Communitygithub.com

TheNoumanDev/make-video

Convierte una idea en un video social terminado (YouTube Short, Instagram Reel o video largo de YouTube) por $0 usando Remotion y herramientas locales de IA, desde una idea de una línea hasta un MP4 verificado.

¿Qué es make-video?

Esta habilidad es un pipeline de video completamente local y gratuito que transforma una idea simple en un video social completo (YouTube Short, Instagram Reel o video largo de YouTube) sin necesidad de API keys ni créditos. Utiliza herramientas de IA como Chatterbox para síntesis de voz (con soporte para clonación de la voz del usuario), Whisper para subtítulos sincronizados, FluidSynth para música y efectos de sonido generados proceduralmente, y Remotion para la renderización final. Incluye un paso automático de control de calidad (QA) que verifica la precisión de los subtítulos, el volumen, el ritmo y la seguridad de la composición visual. Está optimizado para funcionar en macOS con chip Apple Silicon (M1/M2/M3) y los proyectos se organizan en una carpeta con sus propias reglas detalladas en un archivo AGENTS.md, incluyendo pautas de animación, uso de escala, funciones de tiempo y estructura de carpetas. El costo total en descargas es de aproximadamente 6 GB (modelos de voz, subtítulos, música y herramientas de Python), y el tiempo de renderización en una M1 Max es de unos 2-4 minutos para un video de 33 segundos.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/TheNoumanDev/zero-dollar-studio/tree/main/plugins/make-video/skills/make-video

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿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:

  1. 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.

  2. 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):

    DescargaTamañoUsado paraDónde va
    Paquetes npm (Remotion, etc.)~500 MBrenderizaciónnode_modules/
    ffmpeg, uv, FluidSynth (Homebrew, solo si faltan)~150 MBherramientas de audio/videoHomebrew
    Paquetes Python (PyTorch, Chatterbox…)~1.5 GBvoz, QA.venv/
    Soundfont GeneralUser GS~30 MBmúsicatools/soundfonts/
    Pesos de Chatterbox~3 GBla vozCaché de Hugging Face (~/.cache/huggingface), compartido por todos los proyectos
    Whisper small.en~590 MBsubtítulostools/models/
    Whisper large-v3-turbo (verificador de tomas opcional)~1.6 GBregrabar líneas poco clarasCaché de Hugging Face

    Total unos 6 GB y 10-20 minutos. Ofrece la opción más ligera: SKIP_TAKE_CHECK=1 omite el verificador de tomas (4.4 GB en total). Pregunta dónde crear el proyecto (por defecto ~/videos).

  3. 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>/), luego git init.

  4. Ejecuta tools/setup.sh en 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.

  5. Demuestra que funciona: tools/make-story.sh stories/fridge-drama FridgeDrama hace el ejemplo de 33 s (tres verduras discuten en una nevera) en unos 4 minutos. Muéstrale al usuario out/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)

CampoPredeterminado
Plataforma / formatoReel/Short: 1080×1920, 30 fps · YouTube: 1920×1080, 30 fps · Publicación en feed: 1080×1350
DuraciónReel/Short: 15-45 s · YouTube: 3-10 min
TipoHistoria (los personajes hablan, así que usa §3B) o Gráficos en movimiento (texto, datos, diagramas, así que usa §3A)
Tema + conclusión únicaLo único que el espectador debe recordar
AudioVoz (Chatterbox), música + SFX (tools/music.py), o solo música
VozVoz 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 --layout lo 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):

  1. Gancho (≤ 3 s): un hecho o resultado sorprendente verdadero.
  2. "Aquí está cómo funciona realmente": una línea que abre la explicación.
  3. 2-4 puntos, cada uno con un número + una analogía ("un video son solo 30 fotos por segundo, como un folioscopio").
  4. "Pero aquí está el truco": el giro, el error o el problema común.
  5. 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. background da un aspecto de tarjeta clara; pasa qa para 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 caption de 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

  1. Copia src/compositions/_Template → src/compositions/<Nombre>, con un componente por tipo de punto (Gancho, Punto, Estadística, Lista, CTA).
  2. Calcula la duración a partir del guion (suma de puntos − transiciones), como lo hace getSampleIntroDuration.
  3. Regístralo en src/Root.tsx con defaultProps en línea.
  4. Solo música: escribe un JSON de línea de tiempo con totalMs, outroStartMs y events, luego ejecuta tools/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 opcionalmente refVoice: un WAV limpio de 10-30 s en tools/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), opcional event + 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
HerramientaSalida
tools/voice.pypublic/<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.mjspublic/<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.pypublic/<slug>/music.wav (MIDI → FluidSynth, ajustado a los cortes), public/<slug>/sfx.wav
tools/qa.pystories/<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:

  1. npm run lint.
  2. Cualquier línea en stories/<slug>/captions-report.json con 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 bajo filled: escucha esos lugares. Por debajo del 70% de matchRate, el guion y el audio difieren, así que vuelve a generar la voz antes de continuar.
  3. Renderiza fotogramas clave (gancho, cada hablante, cada evento, outro), únelos en una hoja de contactos, y mírala:
    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
    
    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).
  4. Extrae 4-5 fotogramas del MP4 final y míralos.
  5. 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 con npm i simple, 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 defaultProps es un objeto en línea en Root.tsx.
  • Escribe bucles zsh sobre filas como while read -r a b c; do …; done <<EOF, ya que for 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)

PasoTiempo
Carga del modelo Chatterbox~20 s por ejecución (se omite cuando cada línea está en caché)
Generación de vozprimera 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 + SFX2-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.

Skills relacionados