Communitygithub.com

ismhmum123/kinetic-promo-video

Vídeos promocionales a partir de una línea de tiempo HTML determinista: tipografía cinética y animación basada en código.

¿Qué es kinetic-promo-video?

Este skill permite generar vídeos promocionales verticales con apariencia profesional (1080x1920, 30 fps, H.264) sin necesidad de editores de vídeo, material de archivo ni aplicaciones de línea de tiempo. El vídeo se crea a partir de una única página HTML que funciona como un reloj maestro pausado: cada fotograma es reproducible a partir de una marca de tiempo, lo que garantiza un resultado determinista y depurable. Es compatible con cualquier asistente de código (Claude Code, Cursor, Codex, etc.) que pueda ejecutar scripts de shell, Python y un navegador Chromium. El flujo de trabajo incluye: análisis del brief del negocio, opcional referencia visual (con teardown automático usando yt-dlp y ffmpeg), redacción de guion y hoja de ritmos, renderizado con Playwright y codificación final. El resultado es un archivo `promo.mp4` junto con el HTML fuente, el script de renderizado, subtítulos (voice.srt) y un README con constantes de re-marca. Está orientado a desarrolladores que necesitan crear vídeos cortos para redes sociales (Shorts, Reels, TikTok) con un control preciso sobre cada fotograma y sin depender de servicios externos.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add ishmum123/kinetic-promo-video

Preguntar en tu IA favorita

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

Documentación

Vídeo Promocional Cinético

Construye un vídeo promocional vertical con apariencia de broadcast a partir de una simple descripción del negocio. El vídeo se crea como una única página HTML controlada por un reloj maestro pausado, luego se renderiza fotograma a fotograma y se codifica. Sin editor, sin material de archivo, sin aplicación de línea de tiempo, y cada fotograma es reproducible a partir de una marca de tiempo.

Entradas

  • $brief — qué es, para quién es, qué lo hace diferente. Obligatorio. Tómalo de la conversación, del README del repositorio o pregunta.
  • $reference — opcional. Una URL de vídeo o archivo local cuyo estilo se debe imitar.
  • $brand — opcional. Nombre, eslogan, URL, colores, logotipo. Si no está presente, usa un marcador de posición claramente indicado (nunca inventes una marca en silencio y la presentes como definitiva).
  • $duration — opcional. Por defecto 30–35 s sin sonido, 45–60 s con narración (la voz determina la duración — ver references/audio.md). Mantén por debajo de 60 s para Shorts/Reels/TikTok.
  • $audio — por defecto: narrado, sin música. Escribe una voz en off y construye la línea de tiempo alrededor de ella a menos que el usuario pida una pieza sin sonido. La música es lo único que permanece desactivado a menos que se solicite explícitamente.

Objetivo

promo.mp4 — 1080×1920, 30 fps, H.264, reproducible y correcto a la primera visualización — además del scene.html que lo generó, un render.py que lo reproduce, un archivo de subtítulos voice.srt para piezas narradas, y un README con la hoja de ritmos y las constantes para cambiar la marca. El éxito no es "que exista un archivo": son fotogramas que has mirado y que se leen limpios, sin texto superpuesto, sin elementos visibles antes de su entrada, y sin silencios muertos.

Pasos

1. Verificar el conjunto de herramientas

which ffmpeg ffprobe yt-dlp python3
python3 -m venv .venv && .venv/bin/pip install -q playwright && .venv/bin/playwright install chromium

ffmpeg y un Chromium para Playwright son requisitos estrictos. yt-dlp solo es necesario para el análisis de referencias. Prefiere usar un venv — el Python del sistema puede estar gestionado externamente.

Criterios de éxito: ffmpeg -version funciona y .venv/bin/python -c "from playwright.sync_api import sync_playwright; sync_playwright().start().chromium.executable_path" imprime una ruta.

2. Establecer el objetivo visual

Dos caminos — elige según si existe $reference.

2a. Referencia proporcionada → analizarla

Lee references/teardown.md y síguelo. En resumen: descárgalo, examínalo, extrae hojas de contacto a 1 fps, lee realmente las imágenes de la hoja, y anota dimensiones, duración, paleta, tratamiento tipográfico, estructura de ritmos y vocabulario de movimiento antes de escribir cualquier código.

Nunca describas una referencia que no hayas examinado fotograma a fotograma. El título o la descripción de una página no te dice nada sobre su diseño de movimiento.

2b. Sin referencia → primero deriva el lenguaje visual del propio tema

No abras aún default-style.md. Dedica dos minutos a responder cuatro preguntas sobre el tema real:

  1. ¿Cuáles son los objetos? Libros, frascos, facturas, rostros, un panel de control. Estos son lo que debería moverse.
  2. ¿En qué luz viven? Lámpara de lectura, sala de exposición, luz de luna, resplandor de pantalla, luz del día a través de una ventana.
  3. ¿Cómo se mueven físicamente? Las cosas con masa se asientan. El papel gira y se arruga. Los líquidos se extienden. Los datos aparecen de golpe.
  4. ¿Cuál es la columna vertebral? El único elemento recurrente que lleva el argumento: una cuenta atrás, un reloj cruzando la noche, un recibo que crece, una ruta que se completa. Idealmente es la propuesta de valor, no un adorno.

Si esas cuatro respuestas te dan una apariencia coherente, constrúyela. Un promocional de cuidado de la piel sobre reparación nocturna obtiene paleta nocturna, tipografía serifa, movimiento lento de asentamiento y un dial que corre de 10 p.m. a 7 a.m. — no anillos brillantes.

Recurre al estilo predeterminado cuando el tema no sugiera genuinamente nada específico (la mayoría del software B2B, servicios abstractos). Entonces lee references/default-style.md y úsalo tal cual: es una especificación completa y validada (azul marino oscuro + resplandor azul, sans-serif geométrico, tipografía cinética con desenfoque, horizonte brillante, outro con anillo). Indica al usuario qué estilo estás usando en una línea y que puede cambiarlo nombrando un vídeo de referencia — luego continúa. No te detengas para obtener aprobación.

Verificación de honestidad antes de construir. Si las temporizaciones de tus ritmos coinciden en ~0.5 s con la plantilla y las tomas características sobreviven — la pila de palabras eco, la floración del anillo, la tarjeta de horizonte más losa, el desenfoque como único movimiento de texto — has reemplazado la plantilla en lugar de diseñar para el tema. Eso está bien cuando elegiste el recurso deliberadamente, y es un defecto cuando no lo hiciste.

Criterios de éxito: una breve especificación escrita — tamaño del lienzo, fps, duración, códigos hexadecimales de la paleta, fuente y los movimientos de animación que usarás — a la que puedas volver mientras construyes. Si derivaste un lenguaje nativo del tema, también nombra la columna vertebral y los movimientos que estás deliberadamente sin usar.

3. Escribir la hoja de ritmos

Lee references/audio.md y escribe la pista de voz primero — está activada por defecto. La voz es dueña de la línea de tiempo: genera las líneas, mídelas y deriva los tiempos de los ritmos a partir de las mediciones en lugar de ajustar el habla a números redondos. Conserva las temporizaciones medidas por línea — se convertirán en voice.srt en la entrega. Solo omite esto cuando el usuario haya solicitado una pieza sin sonido.

Lee references/beats.md para conocer la estructura y las reglas de copia, luego asigna los diferenciadores reales del usuario a los ritmos. El tercio medio es donde se vende el producto: debe contener las razones específicas por las que esto es mejor, no adjetivos. Asume reproducción silenciada — la mayoría de los espectadores de Shorts/Reels nunca escuchan la voz — por lo que cada afirmación en la voz en off también debe aparecer como texto en pantalla, no solo como narración.

Escribe la hoja de ritmos como una tabla (rango de tiempo → ritmo) antes de escribir código. Equivocarse en el ritmo es mucho más costoso de arreglar después de construir las escenas.

Artefactos: tabla de ritmos con rangos de segundos explícitos que sumen $duration.

Criterios de éxito: cada ritmo se remonta a algo real sobre el producto, y los rangos son contiguos sin espacios > 0.3 s.

4. Andamiar a partir de las plantillas

$SKILL a continuación es el propio directorio de este skill — el que contiene este SKILL.md. Resuélvelo desde tu lista de skills en lugar de adivinar una ruta; a menudo está montado como solo lectura, lo cual está bien porque todo se copia fuera.

mkdir -p video && cp "$SKILL/templates/render.py" video/
cp "$SKILL/templates/scene-starter.html" video/scene.html
bash "$SKILL/templates/fetch-fonts.sh" video/fonts     # subconjuntos de Poppins, ~40 KB

scene-starter.html ya contiene el armazón de animación (seek, win, io, pop, swap, draw, RNG con semilla, atmósfera) y siete ritmos de ejemplo que cubren cada patrón que vale la pena copiar. No reescribas el armazón — codifica los errores enumerados en las Reglas. Reemplaza los ritmos de ejemplo; mantén todo lo que está arriba.

Criterios de éxito: python render.py --contact produce contact.png a partir del iniciador sin modificar.

5. Construir las escenas

Una IIFE por ritmo, cada una creando su propia layer() controlada por win(layer, tIn, tOut). Dentro, cada elemento animado recibe exactamente una llamada io() / pop() / swap().

Construye maquetas de UI (paneles, teléfonos, portátiles, tarjetas, chips) como DOM simple + CSS y anímalas — aportan la sensación de "producto real" que el texto puro no puede. Los gráficos son divs y SVG en línea; sin bibliotecas de gráficos, sin imágenes, sin solicitudes externas.

Un corte directo es un movimiento legítimo: dos capas win() que comparten un límite de tiempo exacto, entradas con steps(1,end), dan un corte intencional de un solo fotograma — la herramienta adecuada para un cambio tonal como mundo narrativo → color de marca plano. Todo lo demás se suaviza; el corte funciona porque es el único.

Los logotipos multicolor reales a menudo son ilegibles tanto en escenas oscuras como en fondos de marca planos — coloca el activo en un pequeño plato blanco en lugar de recolorearlo.

Reglas: consulta la sección de Reglas. No son preferencias de estilo — cada una es un fallo específico que este skill ya ha encontrado.

Criterios de éxito: python render.py --contact se renderiza sin errores.

6. Bucle de previsualización — mira cada fotograma

python render.py --contact          # vista general de 24 fotogramas, ~20 s
python render.py --at 6.2 12.0 19.5 # momentos específicos, resolución completa

Lee los PNG resultantes con tu herramienta de lectura de imágenes — como sea que el armazón la llame — e inspecciónalos. Luego corrige y repite. Itera aquí hasta que la hoja esté limpia — un renderizado completo es 10 veces más lento, así que nunca lo uses como tu bucle de retroalimentación.

Las dos vistas responden a diferentes preguntas. La hoja de contacto es para la estructura: temporización, superposiciones, fotogramas muertos, orden de los ritmos. Es de 270×480 por fotograma y sistemáticamente subestima el trabajo oscuro o de bajo contraste — una pieza que se ve embarrada y rota en la hoja a menudo está limpia a tamaño completo. Juzga el contraste, la paleta y la legibilidad solo a partir de los fotogramas --at, y toma al menos uno por ritmo siempre que la paleta sea oscura, más uno por pictograma o ilustración — la reconocibilidad no se puede juzgar al tamaño de los mosaicos (ver Regla 12). No aumentes el brillo para arreglar algo que la hoja exageró.

Qué buscar en cada pasada:

  • dos piezas de texto legibles a la vez en medio de una transición
  • cualquier cosa visible antes de su entrada (el clásico error de fill: 'both' — ver Reglas)
  • elementos de fondo que se lean como formas reconocibles en lugar de atmósfera
  • manchas translúcidas apiladas — las capas alfa superpuestas se componen en arcos de intersección visibles y se leen como discos; usa un elemento con un borde que se disuelva dentro de su propia caja, dimensionado más grande que el fotograma
  • fotogramas muertos — cualquier momento sin nada en pantalla
  • texto o maquetas apretados contra los bordes del fotograma, o demasiado pequeños para una pantalla de teléfono

Punto de control humano: ninguno requerido, pero si el usuario está presente, muéstrale la hoja de contacto antes del renderizado completo — las notas sobre ritmo y copia son más baratas ahora.

Criterios de éxito: has visto una hoja de contacto en la que cada fotograma se lee limpiamente y ninguno de los defectos anteriores está presente.

7. Renderizar y verificar

Primero haz una prueba de humo del codificador. Renderiza un fragmento de ~2 s — mediante un indicador de rango si tu copia de render.py tiene uno, o reduciendo temporalmente las constantes de duración — y examínalo con ffprobe. Los problemas de codificación y multiplexado aparecen en segundos aquí, en lugar de después de un renderizado completo de varios minutos.

python render.py                    # -> promo.mp4, ~1 captura de pantalla por fotograma
# piezas narradas: multiplexar solo después de que el proceso del codificador haya TERMINADO
ffmpeg -y -i promo.mp4 -i vo/voice.wav -c:v copy -c:a aac -b:a 192k promo_av.mp4
ffprobe -v error -show_entries format=duration \
        -show_entries stream=codec_type,codec_name,width,height,nb_frames \
        -of default=noprint_wrappers=1 promo_av.mp4
ffmpeg -y -v error -i promo_av.mp4 -vf "fps=1/1.2,scale=180:320,tile=10x3" -frames:v 1 verify.png

Ejecuta el renderizado completo en segundo plano. Es ~1 captura de pantalla por fotograma — un vídeo de 50 s son ~1500 fotogramas y supera cómodamente un tiempo de espera de comando de 600 s. Espera a que salga el proceso de renderizado, no a que aparezca el mp4: el archivo existe en el disco mucho antes de que esté terminado, y multiplexar temprano da moov atom not found.

Para piezas narradas, escribe voice.srt a partir de las temporizaciones por línea medidas en el paso 3 — los números ya existen; esto es un pase de formato, no trabajo nuevo.

Lee verify.png — verificar la salida codificada, no el navegador, es el objetivo. Luego elimina las hojas de borrador y el directorio de fotogramas.

Criterios de éxito: ffprobe informa la duración esperada, las dimensiones esperadas (1080×1920 a menos que el usuario haya cambiado la relación de aspecto), y nb_frames == fps × duration; para piezas narradas hay un flujo de audio presente, la duración coincide con la pista de voz, y voice.srt existe; verify.png coincide con la hoja de ritmos de principio a fin. Un archivo corto con un final faltante generalmente significa que -shortest encontró una pista de voz desactualizada — ver references/audio.md.

8. Entregar

Escribe un README junto al vídeo con: la hoja de ritmos, las constantes de cambio de marca, los comandos de renderizado y los dos problemas comunes del armazón. Luego informa al usuario:

  • dónde está el archivo y sus especificaciones exactas (tamaño, duración, fps, y si está narrado o sin sonido — además de la voz TTS utilizada, para que pueda regenerarse)
  • la ruta de voice.srt para piezas narradas, y que Shorts/Reels/TikTok lo aceptan como carga junto al vídeo
  • la tabla de ritmos
  • cada marcador de posición y número inventado, indicado explícitamente — nombres de marca, URL y cualquier métrica mostrada en una maqueta. Di claramente que las cifras fabricadas deben reemplazarse antes de publicar si las afirmaciones deben ser defendibles.
  • que no hay un enlace compartible — es un archivo local — a menos que el usuario haya solicitado alojamiento

Ofrece abrirlo: open promo.mp4.

Reglas: nunca confirmar ni publicar sin aprobación explícita. Nunca subir el vídeo a ningún lado como efecto secundario de producirlo.

Criterios de éxito: el usuario sabe la ruta del archivo, qué es un marcador de posición y cómo cambiarlo.

Reglas

Restricciones estrictas. Cada una es un fallo que este pipeline ya ha producido.

  1. Narrado por defecto, nunca música. Escribe una voz en off y deja que sea la dueña de la línea de tiempo a menos que el usuario haya solicitado una pieza sin sonido. La música y el diseño de sonido permanecen desactivados a menos que se soliciten explícitamente — no puedes proporcionar pistas con licencia, y nunca extraigas audio de un sitio de streaming. Asume reproducción silenciada de todos modos: cada afirmación de la voz en off se refleja como texto en pantalla, y las piezas narradas se entregan con un voice.srt. Cuando entregues una pieza sin sonido, di "sin sonido" al informar para que la reproducción silenciosa no se lea como un error.

  2. Una animación por elemento, que cubra entrada → espera → salida. Dos animaciones WAAPI separadas con fill: 'both' se pelean: el clip de salida aplica su primer fotograma clave desde t = 0, fijando el elemento visible durante todo el vídeo. El ayudante io() existe únicamente para evitar esto. Síntoma: todo en una escena aparece a la vez al inicio de la escena en lugar de animarse.

  3. El texto consecutivo debe salir completamente antes de que entre el siguiente. Dos líneas legibles en pantalla en medio de un fundido cruzado se leen como un error de renderizado, no como una transición. Programa la salida de la línea N para que se complete antes de que comience la entrada de la línea N+1.

  4. El determinismo no es negociable. Inicializa el RNG con una semilla. Nunca llames a Date.now(), Math.random(), performance.now(), requestAnimationFrame, o cualquier API que devuelva un valor no determinista. El armazón proporciona un draw basado en temporizador; úsalo. El reloj del sistema y el contador de fotogramas del navegador varían entre ejecuciones y máquinas. Un renderizado determinista significa que el fotograma 474 es idéntico entre ejecuciones, en tu máquina y en la del usuario.

  5. Rendimiento de renderizado de un solo subproceso. El renderizado usa Playwright en modo sin cabeza. Los fotogramas se capturan uno a la vez, así que el código de animación debe ejecutarse en menos de ~15 ms por fotograma a 30 fps (con un margen para la sobrecarga de la captura de pantalla). Evita sombras de caja complejas, degradados de gran tamaño o cualquier cosa que active un diseño completo del navegador en cada fotograma.

  6. Sin fugas de memoria. Cada capa win() debe limpiar sus event listeners y temporizadores. El armazón proporciona un hook de destrucción; úsalo. Una escena que gotea hace que el uso de memoria del navegador crezca linealmente con el recuento de fotogramas, causando eventuales fallos.

  7. El texto debe ser legible en una pantalla de teléfono. El texto mínimo es 24 px en un lienzo de 1080 px de ancho. Para logotipos y marcas, nunca uses menos de 20 px. Prueba siempre con texto de marcador de posición de la longitud máxima esperada. Una línea de 20 caracteres a 24 px ocupa ~480 px — verifica que quepa en el ancho del fotograma. El kerning y el interlineado deben ser adecuados para pantallas pequeñas.

  8. Sin dependencias externas de fuentes. No enlaces a Google Fonts ni a ninguna URL de fuente externa en el HTML. Las fuentes deben estar incluidas (subconjuntos de Poppins ~40 KB) o proporcionadas por el usuario. El armazón de scene-starter.html ya incluye las fuentes de la plantilla.

  9. Fotograma clave inicial visible. Cada elemento animado debe comenzar fuera de la pantalla, invisible, o con opacidad 0. Ningún elemento debe ser visible en el fotograma 0 a menos que sea parte de la primera escena. Esto evita destellos durante la carga y asegura que el primer fotograma capturado sea limpio.

  10. El audio narrado se mide, no se estima. No supongas que una línea de 10 palabras dura 3 s. Las líneas de voz en off deben medirse contra la TTS real, y la línea de tiempo debe ajustarse para que coincida. El paso de medición (paso 3) es obligatorio para piezas narradas. Los subtítulos (voice.srt) deben coincidir exactamente con la pista de audio.

  11. Sin recursos de red durante el renderizado. No se permiten solicitudes fetch, XMLHttpRequest ni carga de imágenes desde URL externas en el HTML de la escena. Los recursos deben ser locales (incrustados en base64 para imágenes pequeñas, o servidos por un servidor local que coincida con la duración del renderizado). Las solicitudes de red se bloquean de forma predeterminada en el script de renderizado.

  12. Las miniaturas de la hoja de contacto no son fiables para detalles. Los fotogramas de 270×480 son demasiado pequeños para juzgar la legibilidad del texto, los detalles de los iconos o las diferencias sutiles de contraste. Para estos juicios, usa siempre el modo --at con resolución completa de 1080×1920. Si una hoja de contacto se ve borrosa pero legible, el fotograma completo suele estar bien. Si la hoja de contacto se ve bien, el fotograma completo también lo estará.

  13. Un recuento de fotogramas por segundo incorrecto en la salida de ffprobe indica una línea de tiempo defectuosa. Si nb_frames no es fps × duración, la línea de tiempo del navegador no está produciendo fotogramas a la velocidad esperada. Las causas comunes son: animaciones demasiado pesadas que retrasan el bucle de renderizado, bloqueos de setTimeout/setInterval que no se sincronizan con el reloj de captura de fotogramas, o un error en el guión de la escena que hace que el bucle de animación se detenga.

  14. La salida final debe pasar por el codificador H.264. Los renderizados de prueba pueden ser PNG, pero la entrega final debe ser un mp4 con codificación H.264. El script de renderizado se encarga de esto mediante ffmpeg. Verifica que el archivo resultante se pueda reproducir en un navegador y en un reproductor de vídeo estándar. Siempre multiplexa el audio por separado después de que el codificador de vídeo haya terminado.

  15. Sin animaciones infinitas ni bucles. No se permiten animaciones CSS infinite ni bucles JavaScript sin una condición de salida clara vinculada a la línea de tiempo. Cada animación debe estar vinculada al reloj maestro y terminar cuando su escena termine. Las animaciones que se ejecutan más allá del final del vídeo causan fugas de memoria y no se renderizan.

  16. Todos los elementos de una escena deben tener una entrada y una salida programadas. No hay elementos estáticos permanentes dentro de una escena win(). Incluso los fondos deben aparecer (fundido de entrada) y desaparecer (fundido de salida) dentro de la ventana de la escena, o de lo contrario persistirán en la línea de tiempo. El fondo de la escena no es el fondo del vídeo.

  17. No se permiten animaciones de fotogramas clave CSS con tiempo de fotograma fijo. Usa la API de temporización basada en el reloj maestro proporcionada por el armazón (seek(), lerp()). Las animaciones CSS con tiempos fijos (ej. animation-duration: 2s) se rompen cuando cambia la velocidad de fotogramas del renderizado o cuando la línea de tiempo se ajusta. Todas las duraciones deben estar en segundos desde el inicio del vídeo, no en segundos desde el inicio de la escena.

Versión del armazón: 2.4.1 — la hoja de contacto, los indicadores de rango, los fondos de escena y la codificación por lotes funcionan.

Skills relacionados