Communitygithub.com

igm61799-cloud/voiceover-to-animation

Convierte un archivo de audio de narración en un video animado 2D completamente codificado (MP4), sin usar modelos de generación de video ni metraje de stock. Cada fotograma se dibuja con código (Canvas 2D), sincronizado con las palabras exactas de la narración y renderizado con Chromium sin cabeza + ffmpeg.

¿Qué es voiceover-to-animation?

Esta habilidad permite transformar cualquier archivo de audio de voz en off, narración, lektor o clip de pódcast en un video animado 2D profesional (MP4) sin depender de modelos de generación de video ni metraje de stock. Está diseñada para agentes de IA como Claude Code, Cursor o Codex, y sigue un pipeline determinista: cada escena es una función pura del tiempo, lo que permite renderizado en paralelo, sincronización perfecta de audio y generación de imágenes fijas para revisión. El flujo de trabajo incluye transcripción del audio para obtener marcas de tiempo de cada palabra, una fase de storyboard contra el texto narrado, codificación de escenas en JavaScript con Canvas 2D y renderizado final con Playwright (Chromium) y ffmpeg. La habilidad enfatiza la coherencia visual (paleta, tratamiento de bordes, estilo de personajes) y proporciona herramientas para revisar fotogramas, renderizar hojas de contacto y verificar la calidad antes de entregar el video. Está documentada con guías de storyboard, API del motor y ejemplos completos de películas animadas.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/igm61799-cloud/voiceover-to-animation/tree/HEAD

Preguntar en tu IA favorita

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

Documentación

Narración -> Corto animado 2D codificado

Estás haciendo un cortometraje, no una presentación de diapositivas. La narración está fija; tu trabajo es inventar lo que el espectador ve en cada momento, dibujarlo en código y entregar un MP4 cuyos cortes y golpes visuales coincidan con las palabras correctas.

Todo el pipeline es determinista: cada escena es una función pura del tiempo, por lo que cualquier fotograma se puede renderizar de forma independiente. Esa única propiedad te da todo lo demás: imágenes fijas instantáneas para revisión, renderizado en paralelo, sincronización perfecta de audio.

Lo que necesitas en la máquina

Verifica esto antes de comenzar; son las únicas partes móviles.

python -c "import faster_whisper, playwright, PIL; print('ok')"
ffmpeg -version

Piezas faltantes: pip install faster-whisper playwright pillow, luego python -m playwright install chromium. ffmpeg debe estar en PATH. Si algo no se puede instalar, dile al usuario qué falta en lugar de cambiar a un enfoque más débil.

El flujo de trabajo

Mantén la vista del usuario simple: te dieron audio y quieren una película. Trabaja a través de estos pasos en orden y mantén una lista de tareas visible.

1. Escucha primero: marcas de tiempo de palabras

python <skill>/scripts/transcribe.py voiceover.mp3 work

Esto imprime oraciones con horas de inicio/fin y cada palabra como palabra@inicio, y guarda work/words.json. Todo lo posterior se planifica según estos números. Anota la duración total.

2. Configura el proyecto junto al audio

Copia <skill>/assets/template/ en la carpeta de trabajo para que se vea así:

voiceover.mp3
render.py
src/index.html  src/engine.js  src/scenes.js  src/main.js

Lee src/engine.js una vez (es corto) y hojea references/engine-api.md para saber lo que ya tienes: easing, aleatoriedad con semilla, una cámara, dibujo de trayectorias parciales y motivos de estilo grabado (nubes, lluvia, relámpagos, humo, horizontes).

3. Decide la dirección artística, luego storyboard contra las palabras

Elige UN lenguaje visual y mantenlo para toda la película: una paleta pequeña (cinco o seis colores), un tratamiento para bordes y textura, una forma de dibujar personas. La plantilla incluye un aspecto de linograbado/impresión (papel hueso, tintas náuticas, bermellón, dorado, bordes temblorosos cortados a mano). Úsalo, o rediseñalo cambiando la paleta en scenes.js y los interruptores de POST, pero no mezcles estilos entre escenas. La variedad proviene de qué color domina cada escena (una escena nocturna, una escena de papel, una escena roja), no de cambiar las reglas.

Luego escribe el storyboard antes de escribir código: una tabla de tomas con horas absolutas de inicio/fin, las palabras que cubre cada toma, lo que está en pantalla y la palabra exacta en la que aterriza cada golpe. Lee references/storyboarding.md para saber cómo convertir la narración en imágenes; es la parte que decide si la película es buena.

La versión corta:

  • Una idea por frase. Una oración con tres cláusulas suele ser tres tomas o tres golpes dentro de una toma.
  • Muestra la cosa, no la subtitules. El texto en pantalla que repite la narración hace que el espectador lea en lugar de mirar. Por defecto, sin texto; los nombres, datos reales y una etiqueta corta y neutral en un gráfico son las excepciones. Si el usuario ha indicado preferencias de texto, esas ganan.
  • Dale a la película una columna vertebral: un personaje o motivo recurrente, y un guiño al final a algo del principio.
  • Cambia la escala y la cámara a propósito: plano general, primer plano, diagrama, mapa, sección transversal. Dos tomas consecutivas no deben tener la misma composición.
  • Si la narración termina en un remate, añade 1-2 s de cola silenciosa después de la última palabra para que la imagen final pueda aterrizar. render.py rellena el audio.

4. Construye una escena de principio a fin antes de escribir el resto

Escribe la primera toma en src/scenes.js, regístrala en SHOTS y mírala:

python render.py stills 0.3,1.5,2.9 first

Luego abre work/first.png con la herramienta de lectura. Haz esto antes de codificar las otras escenas: prueba el pipeline y, más importante, te permite juzgar el estilo mientras aún es barato cambiarlo.

5. Escribe las escenas restantes, de a pocas

Reglas que mantienen el sistema funcionando (cada una existe porque romperla causa un fallo específico):

  • Funciones puras del tiempo. Una toma es function name(g, t, u) donde t son segundos absolutos y u son segundos desde que comenzó la toma. Sin variables que se acumulen entre fotogramas, sin Math.random(), sin Date. Usa hash(n), noise1(x), rng(seed). Los fotogramas se renderizan fuera de orden por varios navegadores a la vez; cualquier cosa con estado se manifiesta como parpadeo o fragmentos que no coinciden.
  • Anima con tiempos absolutos. Escribe E.out(seg(t, 12.62, 13.1)), usando números directamente de la lista de palabras. Cuando el montaje cambia, los golpes permanecen en sus palabras.
  • Todo se mueve un poco. Un fotograma sostenido se lee como un error. Dale a cada toma un desplazamiento lento de cámara (un zoom de 1 + u * .01 es suficiente) y algo de movimiento secundario (lluvia, humo, un objeto que se balancea).
  • Aplica easing a todo. E.out para cosas que llegan, E.inOut para movimientos de cámara, E.back para apariciones, E.bounce para aterrizajes. El movimiento lineal parece mecánico.
  • Dibuja el mundo más grande que el encuadre cada vez que la cámara se aleje o se sacuda; rellena fondos y suelo mucho más allá de 0..1920 para que nunca se exponga ningún borde.
  • Los impactos reciben tres cosas: un flash de 2-3 fotogramas a pantalla completa, un shake que se desvanece, y algo que reacciona (un soplo, un retroceso, un cambio de color).
  • Divide el código de la escena en archivos (s1.js, s2.js, ...) una vez que un archivo pase unos cientos de líneas, y agrégalos a index.html antes de scenes.js.

Escribe dos o tres tomas, renderiza una hoja de contacto de ellas, mira, corrige, continúa. No escribas toda la película a ciegas.

6. Revisa con imágenes fijas: estos son tus ojos

No puedes ver el video, así que la hoja de contacto es la revisión. Para cada toma, muestrea al menos el inicio, la mitad de la acción principal y el final, además del fotograma exacto de cada golpe:

python render.py stills 12.2,13.3,14.3,15.4,16.5 act2     # hasta ~16 marcas de tiempo por hoja
python render.py sheet 4                                   # toda la película, un fotograma cada 4 s

Lee el PNG y verifica, toma por toma: ¿El sujeto es lo suficientemente grande como para verlo de un vistazo? ¿Algo está recortado, superpuesto o flotando? ¿La cosa importante tiene contraste contra lo que está detrás? ¿Se ve diseñado, o la mitad del encuadre está vacía? Luego corrige y vuelve a renderizar las mismas marcas de tiempo. references/pitfalls.md enumera los errores que son fáciles de cometer y difíciles de notar.

Los errores de página son impresos por render.py como líneas PAGE ERROR:: un fotograma negro o medio dibujado generalmente significa una excepción en esa toma.

7. Renderiza y verifica

python render.py full --workers 8

Ejecútalo en segundo plano; una película de 70 s son aproximadamente 2100 fotogramas y toma unos minutos. Escribe output.mp4 (1920x1080, H.264 + AAC, audio rellenado a la longitud completa). Luego verifica el archivo en sí, no solo las imágenes fijas:

ffprobe -v error -show_entries format=duration:stream=codec_name,width,height -of default=nw=1 output.mp4
python render.py sheet 6

Confirma la duración, que hay una secuencia de audio y que la hoja de resumen no tiene fotogramas vacíos. Di claramente en tu informe que verificaste imágenes fijas y propiedades del archivo, pero que no lo has visto en movimiento; el usuario debe verlo una vez.

8. Entrega

Dale al usuario la ruta a output.mp4, la hoja de resumen y una línea sobre cómo volver a renderizar después de ediciones. src/index.html abierto en un navegador es un reproductor en vivo con el audio, que es la forma más rápida de que verifiquen la sincronización.

Sonido

Entrega solo la voz en off a menos que el usuario haya solicitado música o efectos de sonido. Si lo hizo, agrégalos como entradas adicionales de ffmpeg en la mezcla final, sincronizados desde la misma lista de golpes que usaste para los visuales.

Archivos de referencia

  • references/storyboarding.md: convertir narración en tomas; colocación de golpes; metáforas visuales; qué hace que una escena se sienta diseñada. Léelo antes del paso 3.
  • references/engine-api.md: cada ayuda en engine.js con un uso de una línea. Léelo antes del paso 5.
  • references/pitfalls.md: modos de fallo encontrados de la manera difícil, con correcciones. Léelo antes del paso 6.
  • references/example-bells/: una película completa de 71 segundos (16 tomas, ~900 líneas de código de escena) con su storyboard. Lee storyboard.md para ver el nivel de planificación esperado; abre los archivos src/s*.js cuando quieras ver cómo se construyó un efecto específico (una cámara que sigue a un personaje trepando, una explosión, un mapa, una pluma que dibuja una línea, un ojo que se entrecierra).

Skills relacionados