Videos de demostración
Recorridos con guion grabados desde la aplicación real en ejecución. El espectador ve el producto haciendo trabajo real; las partes lentas (respuestas del modelo, trabajos) se aceleran, y cada momento tiene una breve leyenda que indica qué observar. Se utiliza el mismo formato cada vez para que los segmentos se puedan unir en un solo video.
El formato de la casa
Mantén estos valores exactos, para que los nuevos segmentos coincidan con los anteriores:
- Video: 1440×900, 30fps, H.264 (
libx264 -preset slow -crf 18),yuv420p,+faststart, sin audio. - Tarjetas de título y final: pantalla blanca completa, centrado: una línea opcional pequeña de marca en gris mayúscula
(establece
brandenkit.start; ninguna por defecto), título en negrita de 46px, subtítulo gris de 20px. Dura aproximadamente 2.8s, luego se desvanece. Los segmentos abren con una tarjeta de título; el último termina con una tarjeta de conclusión de una línea (por ejemplo, "Idea → evaluación → prueba en vivo → implementación" / "Sin implementación de la aplicación en el medio"). - Leyendas: píldora oscura (
rgba(17,17,17,.88)), Lato seminegrita blanco de 17px, centro inferior. Una idea por leyenda, aproximadamente 60 caracteres o menos, mayúscula inicial, sin punto final, tiempo presente, escrito desde la perspectiva del espectador ("Los resultados se abren como un artefacto junto al chat"). Cambia la leyenda cuando cambie el momento; mantén cada una durante aproximadamente 2.5–4s. - Clics: una onda púrpura (
rgba(122,71,255,…)) aparece en el objetivo justo antes de cada clic. - Escritura: visible, tecla por tecla (aproximadamente 25ms por tecla; 14ms para texto largo).
- Esperas: cualquier cosa lenta se ejecuta dentro de
ff(), que se reproduce en aproximadamente 2s. Todo lo demás es en tiempo real. - Escenas de arquitectura: una página blanca fija de 1440×900 de escenas (título → antes → problema
resaltado → después → conteo de métricas → lista de funciones), Lato, tinta
#111, acento púrpura#6f43d6; etiquetas "antes" en gris, etiquetas "después" en púrpura.assets/architecture-example.htmles la referencia: reutiliza su CSS y estructura y cambia el contenido.
Dónde viven los videos: el repositorio de demos
Cada video tiene una carpeta en el repositorio de demos del equipo (por defecto ~/src/demos, o
$DEMOS_REPO), que contiene sus scripts de grabación y un manifiesto demo.json. Los repositorios de producto
permanecen libres de código de demostración. Las grabaciones nunca se confirman; el campo output del manifiesto indica dónde
va el MP4.
~/src/demos/
package.json playwright-core + ffmpeg-static (npm install una vez)
<video>/
demo.json manifiesto
architecture.html segmento de "escenas" (opcional)
record-<part>.js segmentos de "recorrido", escritos en demo-kit
.build/ MP4s y fotogramas por segmento (gitignorado)
Manifiesto (demo.json):
{
"name": "<nombre-del-video>",
"title": "Una línea: qué muestra el video",
"description": "Para quién es y el punto que demuestra",
"owner": "correo",
"repos": ["repositorios donde viven las funciones grabadas, con ramas"],
"needs": [{ "what": "servicio", "check": "URL que responde 2xx/3xx cuando está activo", "start": "cómo iniciarlo" }],
"reset": "cómo obtener una toma limpia, y qué deja la grabación",
"segments": [
{ "name": "architecture", "kind": "scenes", "page": "architecture.html", "timeline": "0:3000,1:4500" },
{ "name": "walkthrough", "kind": "walkthrough", "script": "record-walkthrough.js" },
{ "name": "intro", "kind": "video", "file": "~/ruta/a/existing.mp4" }
],
"output": "~/Downloads/<nombre>.mp4"
}
La carpeta examples/sift/ de este skill es una carpeta de referencia: un video de dos segmentos (una página de escenas y un
recorrido real) de una pequeña aplicación de ejemplo que se incluye en la misma carpeta.
Si el repositorio de demos aún no está clonado, créalo (git init, el package.json anterior, y un
.gitignore que cubra node_modules/, .build/, *.mp4, *.jpg, *.png, *-frames/ y
*-timeline.json) e informa al usuario que aún no tiene remoto.
Herramientas (en scripts/, relativo a este skill)
| Script | Qué hace |
|---|---|
find-demos.js | node find-demos.js [raíz…] [--json]: lista cada video en el repositorio de demos, con segmentos, repos, salida, y cuándo se grabó y confirmó por última vez. |
record.js | node record.js <directorio-video> [--only <segmento>]: verifica needs, graba y codifica cada segmento en .build/, los une en output (el video anterior se conserva como *.previous.mp4). Ejecútalo desde la raíz del repositorio de demos. |
demo-kit.js | Biblioteca para scripts de recorrido: kit.start() proporciona page, title/untitle, caption, tap, type, ff, scroll/scrollTop, ripple, navigate, startCast, finish. Los fotogramas se transmiten al disco. |
encode.js | node encode.js <directorio-fotogramas> <timeline.json> <out.mp4>: construye el MP4, comprimiendo ventanas de ff(). |
record-scenes.js | node record-scenes.js <pagina.html> <out.mp4> "0:3000,1:4500,…": graba una página de escenas que define window.step(n). |
concat.js | node concat.js <out.mp4> <a.mp4> <b.mp4> …: une segmentos, recodificando al formato de la casa. |
review.js | node review.js <video.mp4> <directorio-salida> [fotogramas] [at=s,s,…]: hojas de contacto 2×2 de fotogramas para revisar. |
assets/example-walkthrough.js es un ejemplo completo trabajado en el kit (y
examples/sift/record-walkthrough.js es uno real). Léeelo antes de escribir un nuevo recorrido; muestra la estructura, incluyendo cambiar de aplicación a mitad del video,
trabajos acelerados y una tarjeta final.
Flujo de trabajo
0. Encuentra lo que ya existe
Ejecuta find-demos.js primero. Si el usuario quiere volver a grabar o extender un video que ya
tiene una carpeta, trabaja en esa carpeta: vuelve a grabar con record.js <carpeta> (o
--only <segmento> después de un cambio de UI), o añade un segmento a su manifiesto. No inicies una
segunda carpeta para el mismo video. Crea una nueva carpeta solo para un video verdaderamente nuevo, nombrada
según él (kebab-case).
1. Guion gráfico primero
Antes de cualquier código, escribe el guion gráfico como una lista numerada de secciones, cada una con sus momentos: quién aparece en pantalla y el título. Decide de antemano:
- Qué debe ser real, y qué se puede simular. Prefiere lo real (llamadas reales al modelo, búsquedas reales). Si los datos deben simularse (por ejemplo, semanas de tráfico en vivo), indícalo en pantalla, tanto en un título como en la propia aplicación si puede etiquetarlo. Los espectadores toman una demostración al pie de la letra, por lo que un resultado simulado presentado como real es engañoso.
- Qué no se debe hacer clic. Cualquier cosa que escriba en entornos compartidos (guardar tableros, enviar correo electrónico, compras). Muestra el botón; no lo presiones.
- Duración: aproximadamente 60–90s por segmento. Un video unido de 3 minutos está bien; cada segmento debe hacer un punto.
Si el objetivo del usuario está claro a partir de la conversación, adelante, comparte el guión gráfico en tu actualización mientras trabajas. Pregunta solo cuando el punto del video no esté claro.
2. Configura la carpeta del video
Crea <repositorio demos>/<video>/ con un demo.json (rellena needs con una URL de check para
cada servicio que toque el video, y escribe reset). Ejecuta npm install en la raíz del repositorio de demos
si falta node_modules. El kit y los scripts resuelven playwright-core y
ffmpeg-static desde el directorio de trabajo, así que ejecuta todo desde la raíz del repositorio. Chrome
debe estar instalado (channel: 'chrome'; no es necesario descargar el navegador de Playwright).
3. Verificación previa de la aplicación
- Confirma que todos los servicios que toca el video estén activos (curl cada URL), y que HTTPS local funcione (el kit ignora los certificados autofirmados).
- Restablece el estado para que la toma comience limpia (DB nueva, localStorage borrado), y haz que el script falle inmediatamente si el estado está sucio. Una toma que falla 3 minutos después cuesta llamadas reales al modelo y tiempo.
- Mide los endpoints lentos que sondea el video. Una consulta de resultados de 4 segundos se muestra como un esqueleto de carga en cámara; arregla la consulta o espera a que termine.
- Captura una imagen de cada estado clave con un pequeño script de Playwright y mírala: diseño, ajuste, imágenes rotas, qué está arriba del pliegue a 1440×900. Esto es más barato que grabar.
4. Escribe el script de grabación
Copia la estructura de assets/example-walkthrough.js:
const kit = require(process.env.DEMO_KIT || `${process.env.HOME}/.claude/skills/demo-video/scripts/demo-kit`);
const demo = await kit.start(); // record.js proporciona las rutas de fotogramas y timeline
await demo.page.goto(URL, { waitUntil: 'networkidle' });
await demo.title('Nombre de la función', 'Qué permite hacer a las personas');
await demo.startCast(); // iniciar después de que el título cubra la página
await demo.sleep(2800); await demo.untitle(); await demo.sleep(900);
await demo.caption('…'); await demo.tap(locator); await demo.type(locator, 'texto');
await demo.ff(() => page.waitForFunction(() => /* respuesta terminada */ true, null, { timeout: 180000 }));
await demo.finish();
- Usa selectores estables (
aria-label, ids,data-*) y verifícalos contra el DOM real. - Espera condiciones de finalización reales dentro de
ff(), no esperas fijas, con tiempos de espera generosos. - Cuando una leyenda habla de algo, desplázalo en pantalla primero (
demo.scroll(px, 'main')para aplicaciones cuyo contenido se desplaza dentro de un elemento). demo.navigate(url)cambia de página o aplicación; reinicia la screencast en la nueva página.- Para un segmento de arquitectura, construye la página de escenas a partir del ejemplo y grábala con
record-scenes.js. También dale navegación por teclas de flecha y espacio (el ejemplo la tiene), para que la misma página funcione al presentar en vivo.
5. Grabar
Desde la raíz del repositorio de demos, ejecuta el video completo (o un segmento) en primer plano con un tiempo de espera largo, registrando la salida:
set -o pipefail; node ~/.claude/skills/demo-video/scripts/record.js <video> [--only <segmento>] 2>&1 | tee <video>/.build/record.log
No lo canalices a tail: oculta el código de salida del grabador, y una toma fallida parece un
exito. Si debes ponerlo en segundo plano, espera el PID real (while kill -0 $PID; do sleep 5; done)
en lugar de confiar en una notificación de "completado", que puede llegar antes de que finalice el proceso.
6. Revisar
record.js ya codificó y unió todo; imprime el comando de revisión:
node ~/.claude/skills/demo-video/scripts/review.js <output.mp4> <video>/.build/review 16
Para ver un segmento, revisa <video>/.build/<segmento>.mp4.
Lee cada hoja de contacto antes de dar el video por terminado. Verifica que:
- cada leyenda coincida con lo que está en pantalla en ese momento;
- lo que menciona una leyenda sea visible, no debajo del pliegue;
- no haya imágenes rotas ni texto alternativo, esqueletos atascados, toasts de error, encabezados ajustados o recortados, ni interfaz de depuración;
- las esperas aceleradas parezcan un rápido desenfoque de progreso, no un fotograma congelado;
- las tarjetas de título y final estén ahí.
Arregla el script o la aplicación (por ejemplo, un marcador de posición para imágenes que no cargan, una consulta más rápida), restablece el estado y vuelve a grabar. Espera dos o tres tomas.
7. Entregar
- Revisa los puntos de unión:
review.js <output> <dir> 0 at=<t-1>,<t+1>en cada límite de segmento. record.jsconserva la versión anterior como*.previous.mp4. Nunca sobrescribas videos que no sean eloutputde esta carpeta: para añadir al video de otra persona, agrégalo como un segmentovideode una nueva carpeta.- Informa al usuario que la carpeta del video está lista para confirmar en el repositorio de demos. Solo confirma si lo solicita.
- Reporta al usuario: las rutas de archivo y duraciones, qué muestra cada segmento, qué fue real y qué fue simulado, y cualquier estado que la grabación haya dejado (servicios en ejecución, registros que creó, cualquier cosa que aún esté activada) con cómo deshacerlo.
Errores encontrados antes
- Memoria: una screencast de CDP envía hasta 60 fotogramas por segundo mientras algo se anima.
Almacenar fotogramas en búfer en memoria para una toma de varios minutos mata el grabador sin salida.
El kit transmite fotogramas al disco y los reduce durante
ff(); mantén eso así. - Reloj: las ventanas de
ff()y las marcas de tiempo de los fotogramas usan segundos de reloj de pared, así que mide toda la espera (incluyendo el sondeo) dentro de una sola llamadaff(). - Trabajo bloqueante (por ejemplo,
execFileSyncpara un script de datos) dentro deff()está bien: los fotogramas se reanudan después y la ventana se comprime de todos modos. - Puertos: verifica que un puerto esté libre antes de iniciar un servicio para la demo; no mates procesos que no iniciaste.
- Estado residual: una demo que termina implementando o habilitando algo lo deja activo. Desactívalo después o informa al usuario.