Respondes tres preguntas y el agente escribe cada fotograma en HTML, renderiza el MP4 en 16:9 y 9:16 y, si quieres narración, sincroniza cada imagen con la palabra que tu voz está diciendo.

video-codigo es una skill (un paquete de instrucciones y scripts) para Claude Code y Codex, los agentes de código de Anthropic y OpenAI, que crea vídeos sin cámara ni editor: cada fotograma se escribe en código (HTML, Canvas o SVG) y se convierte en MP4. Sirve para quien quiere mostrar un producto, un proyecto o una idea en vídeo: lanzamiento, anuncio, explicativo o clase. Si el vídeo lleva narración, la voz se genera en tu computadora, sin pagar por voz, y cada imagen aparece en el instante en que se pronuncia la palabra. Para usarlo necesitas Node, Python y FFmpeg; para la voz, inemavox con GPU NVIDIA (sin ella, el vídeo sale solo con música).
La skill pregunta lo importante, propone la dirección, prueba un fragmento y solo después renderiza el vídeo entero.
La skill sabe dirigir lanzamientos, anuncios con varios ganchos, vídeos explicativos de productos, series con el mismo aspecto, ventas narradas y clases largas. Ya incluye dos ejemplos listos para copiar: uno explicativo narrado y otro de lanzamiento solo con música.
scripts/voz.py genera la narración con tu voz clonada y mide el tiempo de cada palabra. En el HTML, pal('frase', 'palabra') indica cuándo aparece cada elemento.
El mismo proyecto se recompone para cada formato. Un render para YouTube y otro para Reels, Shorts y TikTok.
Con voz, el reloj del vídeo es la narración. Sin voz, es la música.
¿De qué se trata y para quién? (puede ser una carpeta, un repositorio o un sitio web para leer) · ¿Con voz o solo música? · ¿Qué estilo? — el estándar INEMA o un vídeo de referencia.
Chatterbox pronuncia cada frase con la voz clonada; Whisper escucha, verifica y marca el tiempo de cada palabra. Las frases que salen mal se generan de nuevo.
Un navegador sin ventana abre la página, pide el fotograma de cada instante (window.seek(t)) y FFmpeg lo une todo con el audio. Sin conexión: las fuentes y las imágenes quedan en el proyecto.
El instalador (instalar.sh) instala Playwright y Chromium automáticamente, sin sudo. El resto solo lo comprueba y muestra el comando para instalarlo.
Node 18 o posterior, Python 3 con numpy, scipy y Pillow, FFmpeg en el PATH.
# comprobar node -v && python3 -V && ffmpeg -version | head -1 # bibliotecas de Python (Ubuntu/Debian) sudo apt install python3-numpy python3-scipy python3-pil # otros sistemas python3 -m pip install --user numpy scipy pillow
Un navegador sin ventana, controlado por un script, que toma una imagen de cada fotograma del vídeo. Se instala en ~/.cache.
# instalar.sh (paso 1) ya ejecuta esto
bash ~/projetos/video-codigo/scripts/preparar-entorno.shLa voz usa inemavox instalado en ~/projetos/inemavox: Chatterbox (modelo que habla con una voz copiada de una grabación, la «voz clonada») y Whisper (modelo que escucha el audio y marca el tiempo de cada palabra). También necesita Miniconda (gestor de entornos Python; el instalador oficial se instala en ~/miniconda3) y una grabación limpia de tu voz de 10–20 s en .wav. La primera vez, los modelos descargan varios GB. Si conda o inemavox están en otro lugar, indícalo con CHATTERBOX_PYTHON=/caminho/python3 y INEMAVOX_DIR=/caminho/inemavox. Sin GPU o sin inemavox, crea vídeos solo con música.
# los tres deben existir ls ~/miniconda3/envs/chatterbox/bin/python3 \ ~/projetos/inemavox/chatterbox_tts_worker.py \ ~/projetos/inemavox/venv/bin/python # instalar (probado: Python 3.11, chatterbox-tts 0.1.6) git clone https://github.com/inematds/inemavox ~/projetos/inemavox conda create -n chatterbox python=3.11 -y ~/miniconda3/envs/chatterbox/bin/pip install chatterbox-tts==0.1.6 cd ~/projetos/inemavox && python3 -m venv venv && venv/bin/pip install faster-whisper soundfile numpy
Lo habitual es pedirle al agente (paso 2): escribe el guion y las escenas, y lo ejecuta todo. Los comandos de los pasos siguientes son los que ejecuta y te sirven para repetir una etapa a mano. Para eso, ejecútalos primero en la terminal ($K es la carpeta del kit y $P, la de tu vídeo):
K=~/projetos/video-codigo # donde se clonó el kit P=~/videos/trabalho/2026-11-06-meuapp # una carpeta por vídeo mkdir -p "$P"
Clona el repositorio, conecta la skill a Claude Code y Codex e instala el navegador del render.
git clone https://github.com/inematds/video-codigo ~/projetos/video-codigo bash ~/projetos/video-codigo/instalar.sh # ✓ skill en ~/.claude/skills/video-codigo
Prueba la instalación renderizando el ejemplo listo (no necesita voz ni GPU; tarda alrededor de 1 minuto):
cd ~/projetos/video-codigo/exemplos/lancamento && node ../../scripts/render-video.mjs --project . --output teste.mp4 --audio audio/lancamento/mezcla.wav --overwrite
Di el tema y, si tienes material, dónde está. El agente te hará las tres preguntas que falten. Para narrarlo con tu voz, dile dónde está la grabación .wav.
/video-codigo haz un vídeo de 40 s de mi app, lee la carpeta ~/projetos/meu-app, narrado con la voz de ~/minha-voz.wav, estilo INEMA
Sin narración no necesitas guion ni GPU. Lo más sencillo es pedirle al agente («solo con música, 20 s»): escribirá las escenas. Para partir manualmente del ejemplo de lanzamiento, aprende qué debes cambiar en el <script> de index.html:
• window.videoSpec = {… duration: 21} — la duración del vídeo en segundos; usa la misma que la música.
• SEG — la lista de etapas: a y b son los segundos en que cada etapa entra y sale; rot y sub son el título y la línea inferior.
• S — dónde está y qué tamaño tiene la forma amarilla en cada segundo (t), que es lo que conecta una etapa con otra.
• function conteudo — el dibujo dentro de la forma en cada etapa (módulos, página, play, terminal, conversación). Sustitúyelos por los de tu producto.
cp -r $K/exemplos/lancamento/{index.html,motion.mjs,inema} $P/ python3 $K/scripts/mezcla.py --projeto $P --id meuapp --duracao 21 --musica energica --lufs -14 # misma duración que videoSpec
Después ve al paso 7 (prueba) y al 8 (render, con --audio $P/audio/meuapp/mezcla.wav).
Archivo $P/roteiro.json. Cada frase tiene un id: es ahí donde se sincroniza la imagen. En voz, la ruta a tu grabación. dicionario cambia lo que aparece en pantalla por lo que debe leer la voz.
{"id": "meuapp", "pausa": 0.28, "voz": "/home/voce/minha-voz.wav",
"dicionario": [["16:9", "dezesseis por nove"]],
"blocos": [{"id": "abertura", "frases": [
{"id": "hook", "texto": "Este vídeo no tiene cámara."},
{"id": "codigo", "texto": "Cada fotograma se escribió en código."}]}]}
Se ejecuta en tu computadora. Genera $P/voz/meuapp/voz.wav y $P/voz/meuapp/tiempos.js (el tiempo de cada palabra); las frases con menos de un 80 % de similitud se rehacen automáticamente. Cada frase se escucha con Whisper: si no coincide con el texto (o cambia algún número), se genera de nuevo, hasta --tentativas veces. El informe queda en $P/voz/meuapp/checagem.md, con lo que oyó Whisper — lee las frases marcadas con ⚠.
python3 $K/scripts/voz.py --projeto $P $P/roteiro.json # ej.: meuapp: 41.9 s · 12 frases · 107 palabras
Música original sintetizada (energica, 120 pulsos por minuto; tranquila, 84; o --pista con tu música), 24 dB por debajo de la voz mientras se habla. --lufs -14 deja el volumen final al nivel que usan YouTube e Instagram (así la plataforma no baja ni satura el sonido). Sin voz, pasa --duracao en segundos. La música se ajusta a los cortes de las escenas: cada cambio de escena cae en un tiempo fuerte, en el cambio de acorde, sin saltos de volumen. Al final, el script lo comprueba, verifica que la voz esté al frente y que no haya whoosh, y guarda trilha.json.
python3 $K/scripts/mezcla.py --projeto $P --id meuapp --musica tranquila --lufs -14 # → $P/audio/meuapp/mezcla.wav
Parte del ejemplo narrado: ya incluye el tema, el motor de tiempo y el esqueleto que usa el render (videoSpec = tamaño y duración, seek(t) = dibuja el instante t, renderReady = avisa cuando se cargaron las fuentes y las imágenes). Cambia el texto de las escenas y, en cada pal('frase', 'palabra'), ini('frase') y data-in, los id y las palabras por los de tu guion. Si queda alguno del ejemplo, el render se detiene e indica cuál: Não encontrei «câmera» na frase hook do roteiro.
cp -r $K/exemplos/explicativo-narrado/{index.html,engine.mjs,motion.mjs,declarativo.mjs,inema} $P/ cp $P/voz/meuapp/tiempos.js $P/ # los tiempos de tu voz
// en el <script> de index.html: cada elemento aparece con la palabra pronunciada pop($('.code', c1), t, pal('codigo', 'escrito')); // aparece cuando la voz dice "escrito" pop($('.onda', c1), t, ini('voz')); // aparece al comienzo de la frase "voz"
Extrae fotogramas sueltos en los momentos difíciles, en ambos formatos, y revísalos antes de dedicarle tiempo al vídeo completo. --still indica el segundo del vídeo (debe estar dentro de la duración; en un guion de 5 s, usa 2 o 3).
node $K/scripts/render-video.mjs --project $P --output $P/prova.png --still 2 node $K/scripts/render-video.mjs --project $P --output $P/prova-v.png --still 2 --width 1080 --height 1920
Comprueba también que cada texto permanezca el tiempo suficiente para leerlo (1 s + 0,3 s por palabra, mínimo 1,5 s) y guarda los cortes de las escenas; después, vuelve a procesar la música para que se ajuste a ellos.
node $K/scripts/checar-leitura.mjs --project $P --salvar-cortes $P/audio/meuapp/cortes.json # sale 0 = todo legible; 1 = algún texto desaparece demasiado pronto python3 $K/scripts/mezcla.py --projeto $P --id meuapp --musica tranquila --lufs -14 # la música ahora cae en los cortes
Un MP4 por formato y una hoja de fotogramas para revisar todo el vídeo de una vez.
node $K/scripts/render-video.mjs --project $P --output $P/renders/meuapp-16x9.mp4 --audio $P/audio/meuapp/mezcla.wav node $K/scripts/render-video.mjs --project $P --output $P/renders/meuapp-9x16.mp4 --width 1080 --height 1920 --audio $P/audio/meuapp/mezcla.wav python3 $K/scripts/inspect-video.py $P/renders/meuapp-9x16.mp4 --output-dir $P/reviews
Para una clase, un testimonio o un avatar: la grabación no se corta. A partir de la transcripción con el tiempo de cada palabra, el kit decide frase por frase qué muestra la pantalla: a la persona completa, a la persona en un círculo con el concepto dibujado con trazos, o un gráfico a pantalla completa; y prepara el proyecto listo para renderizar. Revisa $P/plano.md y edita $P/plano.json antes del render.
# transcripción local con el tiempo de cada palabra cd ~/projetos/inemavox && venv/bin/python transcrever_v1.py --in aula.mp4 --outdir $P/transcricao --src pt --words # plan + plantilla + cuadros + audio; --rosto = dónde está el rostro python3 $K/scripts/broll-plano.py --fala aula.mp4 --transcricao $P/transcricao/transcript.json --projeto $P --rosto 0.58,0.45,0.38 # después de editar el plano.json python3 $K/scripts/broll-plano.py --projeto $P --replanejar node $K/scripts/checar-leitura.mjs --project $P node $K/scripts/render-video.mjs --project $P --output $P/renders/aula-broll.mp4 --audio $P/audio/fala.wav
El código, el guion y el audio de cada uno están en exemplos/. No se filmó ningún fotograma. El primer éxito más rápido, sin voz ni GPU: renderiza el ejemplo de lanzamiento.
cd $K/exemplos/lancamento && node ../../scripts/render-video.mjs --project . --output teste.mp4 --audio audio/lancamento/mezcla.wav --overwrite
Hecho = está en el repositorio y se usó en los ejemplos.