Habilidad de Generación de Video Programático
Un flujo de trabajo determinista y sin código repetitivo para que agentes de IA diseñen, revisen visualmente, evalúen y rendericen videos animados MP4 a 60fps y 1080p directamente desde un único archivo HTML5 Canvas/SVG, un script de audio procedural en Python y una tubería headless Playwright → FFmpeg.
Rutas. ${CLAUDE_SKILL_DIR} es el directorio que contiene este SKILL.md. En Claude Code se expande automáticamente; en Cursor, Codex, OpenCode u otros agentes, reemplaza ${CLAUDE_SKILL_DIR} con la ruta resuelta a skills/programmatic-video/.
¿Por qué Avance de Fotogramas Determinista?
Nunca uses grabación de pantalla en tiempo real (MediaRecorder, captura por reloj de pared de requestAnimationFrame o transiciones CSS en tiempo real) para producir videos con un agente de IA:
- La captura por reloj de pared pierde fotogramas cuando la carga de la CPU aumenta, causando desviación y tartamudeo de audio/video.
- Las animaciones CSS se ejecutan en tiempo real, imposibilitando buscar en
t = 14.20spara una revisión visual instantánea. - El renderizado ciego desperdicia minutos: renderizar 5,000 fotogramas antes de verificar si un título se desborda de su tarjeta garantiza trabajo perdido.
En su lugar, cada video construido con esta habilidad sigue tres reglas:
- Regla 1 — Función Pura del Índice de Fotograma: Toda la escena se maneja mediante
window.__setFrame(frameIndex, timeSeconds, fps)dondet = frameIndex / fps. Cada posición, opacidad, contador y partícula es una función matemática determinista det(usando un PRNG con semilla comomulberry32, nuncaMath.random()). - Regla 2 — Revisión Multimodal con Hoja de Contactos Antes del Renderizado Completo: Antes de codificar el MP4 completo a 60fps, captura 8–12 marcas de tiempo clave (
render.mjs --timestamps ...), combínalas en una solacontact-sheet.png(contact-sheet.py) e inspecciona esa imagen usando tu herramienta multimodal de Lectura/Visión para corregir texto recortado, superposiciones o bajo contraste. - Regla 3 — Audio Preciso por Muestra + Tubería FFmpeg sin Hinchazón de Disco: Genera una banda sonora WAV estéreo multisegmento + señales de efectos SFX con marcas de tiempo (
synth-audio.py), luego transmite búferes PNG desde Playwright directamente affmpeg -f image2pipe(render.mjs).
Flujo de Trabajo Integral del Agente (6 Pasos)
Paso 1: Storyboard y Presupuesto de Escenas
Diseña una tabla de línea de tiempo concreta antes de escribir código. Agrupa el video en escenas de 4 a 8 segundos con marcas de transición explícitas (T_cut) que tanto scene.html como synth-audio.py compartan:
| Escena | Tiempo (t) | Fotogramas (60fps) | Enfoque Visual | Audio / Señal SFX |
|---|---|---|---|---|
| 01 — Gancho / Alerta | 0.0s – 7.0s | 0 – 420 | Arranque de terminal CRT, logs de máquina de escribir, clic en botón CTA a 2.7s | Pulso grave + señal de clic/desbloqueo de UI a 2.7s, ascenso hasta 3.4s |
| 02 — Métricas Estrella | 7.0s – 15.0s | 420 – 900 | Cuadrícula synthwave en perspectiva 3D + 3 tarjetas de contador con física de resorte | Bajo synthwave completo 124 BPM + arpegiador estéreo cae a 7.0s |
| 03 — Telemetría Profunda | 15.0s – 23.0s | 900 – 1380 | Barras de progreso en pantalla dividida + medidor semicircular animado | Barrido de filtro + impulso de platillo, impacto grave a 15.0s |
| 04 — Llamada de Lista y Final | 23.0s – 30.0s | 1380 – 1800 | Cuadrícula Bento de tarjetas de colaboradores + cartel de "¡TRABAJO TERMINADO!" y confeti | Acorde final + señal de voz/SFX a 25.2s, desvanecimiento maestro 28.5–30.0s |
Paso 2: Crear scene.html con window.__setFrame(f, t, fps)
Escribe un archivo HTML autónomo de 1920x1080 usando <canvas> de HTML5 (y/o <svg> en línea + superposiciones DOM) que exponga:
window.__setFrame = function(frameIndex, timeSeconds, fps = 60) {
if (window.__rafId) {
cancelAnimationFrame(window.__rafId);
window.__rafId = null;
}
const t = typeof timeSeconds === 'number' ? timeSeconds : frameIndex / fps;
renderSceneAtTime(frameIndex, t);
};
- Incluye siempre un PRNG con semilla (
mulberry32(seed)) para estrellas, partículas, confeti o ruido, de modo que el fotogramafsea bit-idéntico entre ejecuciones. - Espera a
document.fonts.ready(manejado automáticamente porrender.mjs). - Consulta references/visual-patterns.md para recetas copiables (cuadrícula 3D en perspectiva, contadores con resorte, terminal CRT, medidores, tarjetas bento, física de confeti).
Paso 3: Ejecutar Capturas Rápidas de Marcas de Tiempo y Generar contact-sheet.png
Nunca ejecutes primero un renderizado completo a 60fps. Muestrea 1–2 marcas de tiempo por escena (además de puntos medios de transición) y genera una sola hoja de contactos:
# 1. Capturar 9 fotogramas clave en ~3 segundos
node "${CLAUDE_SKILL_DIR}/scripts/render.mjs" \
--html ./scene.html \
--timestamps 1.8,3.0,5.2,8.5,12.5,16.5,20.5,24.5,28.0 \
--out-dir ./qa-frames
# 2. Combinarlos en una imagen de cuadrícula etiquetada
python3 "${CLAUDE_SKILL_DIR}/scripts/contact-sheet.py" \
--dir ./qa-frames \
--cols 3 \
--thumb-width 560 \
--title "HOJA DE CONTACTO DE QA VISUAL" \
--out ./contact-sheet.png
Paso 4: Bucle de Autorevisión Multimodal (¡Obligatorio!)
Usa tu herramienta de Lectura/Visión de imágenes en ./contact-sheet.png (y en cualquier ./qa-frames/t-*.png individual que parezca densa). Revisa cada mosaico contra la lista de verificación en references/visual-qa-loop.md:
- ¿Algún texto se desborda o choca con bordes de tarjetas, insignias o barras de progreso?
- ¿Todos los números, etiquetas y encabezados HUD tienen alto contraste y son legibles a 1080p?
- ¿Cada transición de escena aterriza limpiamente sin un fotograma vacío/negro no deseado?
Si detectas algún problema en contact-sheet.png, corrige scene.html y vuelve a ejecutar el Paso 3 antes de continuar.
Paso 5: Sintetizar Banda Sonora Procedural y Mezclar Señales SFX WAV
Genera una banda sonora WAV estéreo de 44.1 kHz cuyos ascensos de transición y señales SFX coincidan con las marcas de tiempo exactas en scene.html:
python3 "${CLAUDE_SKILL_DIR}/scripts/synth-audio.py" \
--duration 30.0 \
--bpm 124 \
--style synthwave \
--transitions 3.4,7.0,15.0,23.0,25.2 \
--cue "25.2:./sfx/jobs-done.wav:+1.5" \
--out ./soundtrack.wav
Para composiciones multisegmento personalizadas o la integración de paquetes de sonido temáticos (como jblxo/claude-code-sound-packs), lee references/audio-synthesis.md.
Paso 6: Renderizar el MP4 Final a 60fps H.264 mediante Tubería FFmpeg
Una vez que la revisión visual y la síntesis de audio hayan sido exitosas, ejecuta render.mjs en modo de tubería completa:
node "${CLAUDE_SKILL_DIR}/scripts/render.mjs" \
--html ./scene.html \
--duration 30 \
--fps 60 \
--audio ./soundtrack.wav \
--crf 18 \
--out ./final-video.mp4
Verifica el contenedor de salida con ffprobe:
ffprobe -v error -show_entries format=duration,size:stream=codec_name,width,height,r_frame_rate -of default=noprint_wrappers=1 ./final-video.mp4
Guías de Referencia (Cargadas Bajo Demanda)
| Tema | Archivo de Referencia |
|---|---|
| Primitivas visuales Canvas/SVG, funciones de easing, PRNG con semilla, cuadrícula synthwave 3D, medidores, tarjetas bento | references/visual-patterns.md |
| Bucle de QA visual con hoja de contactos multimodal, defectos de diseño comunes, estrategia de selección de marcas de tiempo | references/visual-qa-loop.md |
| Síntesis de audio procedural Python/NumPy, progresiones de acordes, ascensos, ducking, mezcla de señales SFX WAV | references/audio-synthesis.md |