CommunityProgramación y desarrollogithub.com

VirtualPirate/create-product-demo-video-skill

Skill de Claude Code: graba un video demo de producto a partir de un flujo real de usuario en tu propia app web, transcrito desde la IU real y grabado a mp4/gif con Playwright y ffmpeg.

¿Qué es create-product-demo-video-skill?

Este skill permite a Claude Code generar automáticamente un video demo de producto basado en una descripción de flujo de usuario, interactuando con la interfaz real de la aplicación web objetivo. El skill se asegura de que cada pantalla del video sea una transcripción fiel de la IU real, no una impresión o maqueta inventada, lo cual es fundamental para evitar mostrar un producto que no existe. Funciona en cualquier proyecto JavaScript/TypeScript con un router (como React Router) y utiliza Playwright para la captura de pantalla y ffmpeg para la composición del video final en formato mp4 o gif. El skill soporta la inclusión opcional de música de fondo, subtítulos configurables (estilos pill, lower-third, rail y coach), y un proceso de verificación mediante extracción de fotogramas para garantizar la calidad visual. La salida se organiza en carpetas numeradas `demo/vN/` para evitar sobrescrituras.

Compatible con✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/VirtualPirate/create-product-demo-video-skill/tree/main/skills/create-product-demo-video

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

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

Documentación

Construye un video demo del flujo que el usuario describió. El resultado se guarda en una carpeta nueva demo/vN/.

La única regla que importa: cada pantalla es una transcripción de la IU real, no una impresión de ella. Un demo que invente diseño, texto o componentes es peor que ningún demo: enseña a los espectadores un producto que no existe. Lee el código fuente de cada pantalla antes de escribir cualquier marcado.

Entradas

/create-product-demo-video <lo que debería pasar> — una descripción del flujo. Si es vaga ("mostrar el producto"), elige el flujo completo más específico que termine en un valor visible, di cuál elegiste en una línea, y construyelo. No te detengas a hacer preguntas.

Pasos

  1. Mapea el flujo a rutas. Convierte la solicitud en una lista ordenada de rutas reales por las que pasaría el usuario. Encuentra primero el router — un directorio routes/, un árbol app/, un bloque <Routes>, un manifiesto de rutas — y lista solo las rutas que existan. Si el flujo necesita una entidad que debe crearse antes de que pueda existir una pantalla posterior (un proyecto antes de un informe por proyecto), incluye esa pantalla o elige un alcance que no la necesite — no omitas un paso requerido silenciosamente.

  2. Lee el código fuente de cada pantalla. Para cada ruta: el archivo de ruta, los componentes que renderiza, los componentes de diseño compartidos de la app (shell, encabezado de página, estado vacío), y sus primitivas del sistema de diseño (components/ui/ o donde sea que estén). Lee también todo lo que genera cadenas que el demo muestra — ayudantes de vista previa, nombres derivados, servicios de renderizado/plantillas del backend. Copia las cadenas textualmente; no parafrasees el texto del producto.

  3. Andamiaje. mkdir -p demo/vN (siguiente N no usado — nunca sobrescribas un vN existente), luego copia assets/skeleton.html → demo/vN/index.html y assets/record.mjs → demo/vN/record.mjs. assets/ está junto a este SKILL.md, donde sea que el skill esté instalado — un directorio de caché de plugins, ~/.claude/skills/, o .claude/skills/ del proyecto. Resuélvelo desde el propio directorio del skill, nunca desde el repositorio que se está demostrando. El esqueleto trae un shell placeholder, una escala de tokens y el motor de reproducción. Para un demo con música, copia también la pista elegida de assets/music/ → demo/vN/music.mp3 — ver Música. Copiarla dentro (en lugar de referenciar la carpeta del skill) es lo que permite que vN/ sea regrabable más tarde, la misma razón por la que record.mjs se copia por versión.

  4. Adapta el esqueleto a este producto. Todo lo marcado con REPLACE: es un placeholder que debe intercambiarse antes de escribir cualquier escena, porque cada pantalla lo hereda:

    En index.htmlReemplázalo con
    PRODUCTEl nombre de la app, el host que muestra su barra de direcciones y su logo svg real
    NAVLa barra lateral transcrita de la navegación real — mismas secciones, mismo orden, mismas etiquetas
    TOPBARLa barra superior real; elimina controles que la app no tenga
    tokens :rootEl bloque :root de la hoja de estilo de la app, para que color/radio/tipo coincidan
    ICONSDatos de rutas del conjunto de iconos que la app realmente usa
    Elimina los bloques CSS opcionales (pantalla de terceros, paneles de entrega) que el flujo no use.
  5. Escribe las escenas. Una <section class="scene" data-scene="N"> por pantalla, en orden. Reutiliza las clases CSS del esqueleto (.pagehead, .card, .btn, .seg, .opt, .chip, .scopeid, .statusbadge, .empty, .input, .pillbar, .toast) — están moldeadas como la salida de un sistema tipo Tailwind/shadcn, así que verifica cada una contra las clases reales del componente y ajusta en lugar de asumir. Añade CSS nuevo solo para un componente que falte en el esqueleto, y derívalo de las clases reales de ese componente.

  6. Escribe play(). Portada → pantallas → cierre. Usa subtítulos para nombrar cada paso, y establece CAPTIONS al principio del script — el estilo, y steps = cuántas llamadas say() hace la ejecución. Las interacciones pasan por los ayudantes del puntero para que el espectador pueda seguir lo que se hace clic.

  7. Graba. node demo/vN/record.mjs → demo/vN/out/product-demo.mp4. Añade --gif para un gif de 900 px. Un archivo demo/vN/music.* se detecta automáticamente; --music <ruta> apunta a uno en otro lugar, --music-db <n> ajusta el nivel, --no-music fuerza silencio.

  8. Verifica mirando. Extrae fotogramas y lee las imágenes — esto no es opcional, así es como se detectan errores de diseño:

    for t in 5 12 20 28 36 44; do ffmpeg -y -loglevel error -ss $t \
      -i demo/vN/out/product-demo.mp4 -frames:v 1 /tmp/f$t.png; done
    

    Verifica: sin iconos sobredimensionados, nada recortado en el pliegue, el puntero aterriza en el elemento que dice hacer clic, el texto no está colapsado en una línea. Corrige y regraba hasta que esté limpio.

    Los fotogramas no pueden mostrarte el audio. En un demo con música, verifica también el flujo y las rampas — volumedetect registra a nivel info, así que -v error tragaría su salida:

    ffprobe -v error -select_streams a:0 -show_entries stream=codec_name,duration \
      -of default=nw=1 demo/vN/out/product-demo.mp4
    for w in "-ss 0 -t 0.25" "-ss 12 -t 0.5" "-sseof -0.25"; do \
      ffmpeg -hide_banner -nostats $w -i demo/vN/out/product-demo.mp4 \
        -af volumedetect -f null - 2>&1 | grep mean_volume; done
    

    Espera un flujo aac dentro de ~0.05 s de la duración del video, max_volume por debajo de 0 dB, y las medias de cabeza y cola muy por debajo de la del medio — eso es el fundido que prueba que funcionó.

  9. Escribe demo/vN/README.md — tabla de escenas con rutas, el mapeo de archivos fuente, duración, el estilo CAPTIONS y la pista de música con la que se grabó la versión, y lo que el flujo omite deliberadamente. Actualiza demo/README.md para listar la nueva versión.

Reporta la ruta, la duración y el tamaño, luego abre el mp4 para que el usuario pueda verlo — open en macOS, xdg-open en Linux, start en Windows.

API del motor

Disponible dentro de play():

LlamadaEfecto
scene(n)Transición cruzada a la escena n, actualiza la barra de direcciones desde URLS
tap(sel, ms)Mueve el puntero al elemento y haz clic (ondulación + presión)
moveTo(sel, ms) / click(sel)Las dos mitades, cuando necesitas cambios de estado entre ellas
hideCursor() / place(x, y, 0)Reinicia el puntero al entrar a una escena
say(text, opts?) / hush()Subtítulo dentro/fuera. { at: sel } ancla un subtítulo coach; { step: n } fuerza el índice
type(el, text, ms)Escritura carácter por carácter en un <span>
wait(ms)Espera
reveal(el)Llamado automáticamente por moveTo — desplazamiento suave de .main para que los objetivos fuera del pliegue sean visibles

Establece window.__demoDone = true al final (el esqueleto ya lo hace) — el grabador espera en ello.

Diseño de subtítulos

const CAPTIONS = { style: 'pill', steps: 6 } se sitúa con URLS al principio del motor. Los cuatro estilos vienen incluidos en el esqueleto; say() es la misma llamada independientemente de cuál se elija. Elige por video:

styleQué esElígelo cuando
pill (predeterminado)Cápsula de tinta, centro inferiorCualquier cosa corta y orientada a marketing. Menos oclusión, ~10 palabras por subtítulo
lower-thirdBloque anclado a la izquierda con índice de paso + barra de progresoFlujos más largos donde el espectador debe sentir la secuencia; más legible en un gif
railBanda de 68 px debajo de la ventana, puntos de capítuloDocumentación y clips de soporte donde nada puede ser cubierto. Cuesta altura de la app — ver abajo
coachLlamada anclada al elemento en juego, resto atenuadoTutoriales guiados. Cada subtítulo necesita { at: sel }; los que no tienen vuelven a pill

steps impulsa el índice, la barra de progreso y los puntos del rail — cuenta las llamadas say() y establécela, o la ejecución termina leyendo 05 / 06. ¿No estás seguro del estilo? Abre index.html en un navegador y cambia CAPTIONS.style — la página se reproduce con R, por lo que los cuatro pueden compararse sin grabar.

Música

Opcional, y desactivada a menos que haya una pista. La base se multiplexa en el momento de codificación — Playwright no captura ningún audio, por lo que nada de ello toca la página de demostración o el motor.

node demo/vN/record.mjs                      # usa demo/vN/music.* si existe, silencio si no
node demo/vN/record.mjs --music ~/beds/x.mp3  # la ruta explícita gana sobre el archivo hermano
node demo/vN/record.mjs --music-db -4        # base más silenciosa
node demo/vN/record.mjs --no-music           # silencio incluso con una pista hermana
  • Las pistas incluidas viven en assets/music/, una fila por archivo en su LICENSES.md. Ninguna pista se incluye sin una línea CC0/CC-BY verificable — un mp3 sin licencia es un problema para todos los que instalen esto, no solo para ti. ¿No estás seguro? Mantenlo fuera del repositorio y pasa --music <ruta>.
  • El nivel está normalizado, no ajustado. Cada pista se lleva a −18 LUFS con un techo de pico real de −1.5 dB, por lo que las bases intercambiadas entre versiones coinciden entre sí sin ajuste manual. --music-db desplaza ese objetivo; no añade ganancia encima.
  • Los fundidos son automáticos — 1.5 s de entrada, 2.5 s de salida, la salida sincronizada con la duración real del video.
  • Elige una pista más larga que el video. Cualquier cosa más corta se repite y la costura es audible; el grabador advierte cuando tiene que hacerlo. 60 s+ cubre un demo normal de 40–60 s.
  • Sin voces, sin caídas bruscas. El espectador está leyendo subtítulos y texto de la IU al mismo tiempo.
  • El audio solo va en el mp4. El webm es la captura silenciosa sin procesar, y un gif no tiene pista de audio en absoluto — un cambio solo de música es invisible en la salida --gif.

Convenciones

  • El escenario es un navegador simulado fijo de 1280×800; 44 px de eso son el cromo del navegador, dejando 1280×756 para la app. El esqueleto incluye una base de 48

Skills relacionados