Video de recorrido guiado (walkthrough)
Convierte "explica esta funcionalidad" en un MP4 corto: la app real en pantalla, una voz explicándola, subtítulos, un cursor que se mueve como el de una persona y un anillo alrededor de lo que se está hablando. El usuario da las instrucciones y revisa. Tú haces todo lo demás.
El trabajo tiene un punto de revisión que importa más que ningún otro: el usuario aprueba la narrativa antes de que se grabe nada. Cambiar una palabra cuesta segundos en un guion y minutos en un video, y una afirmación incorrecta es mucho más barata de detectar en papel.
Lo que necesitas
- El código fuente de la aplicación y una instancia a la que puedas acceder e iniciar sesión (local o de desarrollo/pruebas). Nunca grabes contra producción: la grabación hace clic en botones reales.
- Playwright en el proyecto de la app (
node_modules/playwrighto@playwright/test). La mayoría de los proyectos con pruebas E2E ya lo tienen. Si no:npm i -D playwright && npx playwright install chromium. ffmpegypython3en el PATH.- Una clave de texto a voz para la voz final (Murf o ElevenLabs). Sin una,
--provider sayusa la voz del sistema macOS, que es suficiente para un borrador. Consultareferences/voices.md.
Verifica primero estos requisitos y di claramente lo que falta. No le pidas al usuario que pegue una clave API en el chat: pídele que la ponga en una variable de entorno o en un archivo ignorado por git y que te diga dónde está.
El flujo de trabajo
1. Toma las instrucciones
Necesitas cuatro cosas. Pregunta solo por lo que la solicitud no diga ya.
- Objetivo y audiencia. "Alinear con el CTO en la nueva página de permisos" produce un video diferente a "enseñar a los nuevos miembros cómo publicar una aplicación". La audiencia determina la duración, el vocabulario y cuánto hay que explicar.
- El flujo. Qué mostrar, en orden. Si el usuario da uno, mejóralo y di qué cambiaste y por qué: un orden mejor, un paso faltante, un paso que no aporta nada. Pidieron un video, no una transcripción de su lista.
- Duración. Por defecto, de 60 a 120 segundos y un solo tema. Si el flujo necesita más, propón dos videos.
- Voz. Proveedor y voz, si tienen preferencia. Si no, usa los valores predeterminados.
2. Recorre el flujo en la aplicación real antes de escribir una palabra
Ejecuta la aplicación, inicia sesión con una cuenta de demostración y realiza cada paso del flujo tú mismo con Playwright o el navegador. Estás comprobando que cada cosa que la narración afirmará sea cierta.
Aquí es donde reside la mayor parte del valor de la skill. A menudo las funcionalidades se describen de memoria o a partir de la especificación, y la aplicación hace algo ligeramente diferente. Si la aplicación no hace lo que el usuario dijo que hace, detente y comunícaselo, con lo que hayas observado. No escribas una narración que lo disimule ni omitas el paso en silencio.
Anota las etiquetas exactas de los botones y menús mientras estés allí. La narración debe usar las palabras que aparecen en la pantalla.
3. Crea datos de demostración
Un recorrido en una cuenta vacía o medio rota parece un informe de error. Crea lo que la historia necesite: una organización, algunos usuarios con diferentes roles, elementos con nombres creíbles. Usa solo nombres inventados (Acme, Northwind, example.com): estos videos se reenvían.
Mantén una lista de todo lo que crees o modifiques. Lo restaurarás en el paso 9.
4. Escribe la narrativa y luego detente para revisión
Escíbela como una tabla y guárdala junto a donde irá el video, como <nn>-<slug>.script.md:
| # | En pantalla | Voz en off | ~seg |
|---|---|---|---|
| 1 | Lista de tareas en reposo. Anillo sobre la lista. | Esta es la lista de tareas del equipo. / Todos en el equipo ven las mismas tareas. | 5 |
| 2 | Cursor a **Agregar tarea**, se abre el formulario. Escribe un nombre, haz clic en **Guardar tarea**. | Para agregar una, selecciona Agregar tarea, / ponle un nombre / y guárdala. | 7 |
La / divide la narración de una escena en líneas de subtítulos. Lee references/narrative.md antes de escribir: cubre ritmo, longitud de línea, tarjetas de antes/después y los errores que hacen que estos videos sean difíciles de seguir.
Muestra la tabla al usuario y espera. Di la duración total esperada. Si cambiaste su flujo, indícalo aquí. Continúa solo cuando lo apruebe; si pide cambios, envía la tabla revisada nuevamente.
5. Genera la voz
Escribe la narración aprobada en scenes.json, una entrada por fila, líneas divididas en las marcas /:
[{ "id": "02", "lines": ["Para agregar una, selecciona Agregar tarea,", "ponle un nombre,", "y guárdala."] }]
python3 scripts/tts.py scenes.json --audio-dir work/audio --provider murf
Esto escribe un clip por escena y durations.json. La voz se genera antes de la grabación a propósito: cada escena se mantiene en pantalla durante el tiempo que dure su clip, por lo que las duraciones de los clips deben existir primero. Volver a ejecutar solo regenera las escenas cuyo texto cambió.
6. Escribe el script de grabación y haz una prueba en seco
Copia example/record.cjs y reescribe sus escenas para este flujo. scripts/walkthrough.cjs te proporciona:
| Helper | Uso |
|---|---|
scene(id, async () => {...}) | Una escena narrada. Muestra sus subtítulos y espera hasta que la voz haya terminado. |
clickAt(locator) | Desliza el cursor hasta el elemento, muestra la pulsación, haz clic. Usa esto, no locator.click(), o las cosas sucederán sin causa visible. |
moveTo(locator) | Apunta a algo sin hacer clic. |
typeInto(locator, text) | Haz clic en un campo y escribe a una velocidad legible. |
ring(locator) / ring(null) | Resalta lo que la voz está explicando; elimínalo cuando la voz pase a otra cosa. |
step('Paso 2 de 4 · Guardar') | La etiqueta en la parte inferior izquierda que le indica al espectador dónde se encuentra. |
card({ title, subtitle }) | Tarjeta de título a pantalla completa, para la escena de cierre. |
card({ before, after }) | Comparación antes/después. card(null) la oculta. |
login: async (page) => {...} | Opción de record(). Inicia sesión fuera de cámara para que el video comience donde comienza la historia. |
Prefiere localizadores por rol y etiqueta (getByRole, getByLabel) sobre CSS: sobreviven a cambios de estilo y son los nombres que usa la narración. Lee los nombres de la pantalla en tiempo de ejecución cuando los datos puedan diferir entre entornos.
Ejecuta primero con dry:
node record.cjs <app-repo> work/rec work/audio/durations.json dry
Una ejecución en seco no graba nada y no espera a la voz, por lo que un selector incorrecto cuesta segundos, no una toma completa. Corrige hasta que cada escena funcione.
7. Graba y ensambla
node record.cjs <app-repo> work/rec work/audio/durations.json
python3 scripts/mux.py --rec work/rec --audio-dir work/audio --output walkthrough-videos/<nn>-<slug>.mp4
El grabador imprime la duración del clip de cada escena junto con el tiempo que tardaron sus acciones. Una escena marcada con segundos de silencio después de la voz tiene demasiadas acciones para lo que se dice: recorta las acciones o dale más texto a la voz.
mux.py escribe el MP4, un .srt correspondiente y <name>.sheet.jpg.
8. Revísalo tú mismo antes que el usuario
Abre la hoja de contactos: un fotograma por escena. Busca un anillo en el elemento equivocado o faltante, un subtítulo que cubra lo que se está explicando, una escena en la pantalla incorrecta, una insignia de herramientas de desarrollo o un mensaje de error en la imagen, datos personales reales. Extrae fotogramas individuales con ffmpeg cuando la hoja sea demasiado pequeña para distinguir.
Luego entrega el video con: su duración, qué cambió respecto a la narrativa aprobada (si algo) y cualquier cosa que no hayas podido verificar.
Cuando el usuario quiera cambios, vuelve primero a la narrativa. Revisa la tabla, muéstrala, obtén la aprobación y luego regenera solo lo que cambió. La mayoría de los comentarios ("demasiado rápido", "perdí el hilo de lo que cambió", "menciona también el filtro") son comentarios sobre el guion, y arreglarlos solo en la grabación produce un video que ya no coincide con su guion.
9. Restaura los cambios
Deshaz lo que la toma modificó, usando la lista del paso 3 y lo que la grabación misma haya hecho clic: configuraciones cambiadas, elementos creados o eliminados, estado de las cuentas de demostración. Luego informa al usuario qué se ha restaurado y qué has dejado deliberadamente (por ejemplo, datos de semilla que quizá quiera para el próximo video). Si algo no se puede deshacer, dímelo.
Archivos
Los entregables van juntos en un lugar que el usuario pueda encontrar, por defecto walkthrough-videos/ en el proyecto:
walkthrough-videos/
03-add-a-task.mp4
03-add-a-task.srt
03-add-a-task.script.md
Mantén los archivos de trabajo (scenes.json, audio, grabación raw, el script de grabación) fuera del repositorio o en una carpeta ignorada por git. Son grandes, y el script de grabación contiene selectores para un momento concreto en la vida de la aplicación. El script y el .srt vale la pena conservarlos: facilitan que la próxima revisión sea una edición pequeña.
Cosas que pueden salir mal
- Los controles nativos no se graban. Un
<select>nativo, un selector de archivos o un diálogo del navegador son dibujados por el navegador fuera de la página. Apunta al control conmoveTo, establece el valor conselectOption/setInputFilesy deja que la narración diga lo que se eligió. - La superposición desaparece después de la navegación. Se recrea en cada carga de página y se restauran el paso actual y los subtítulos. Si una página reemplaza
document.bodypor completo, vuelve a llamar astep()después de que se estabilice. - Una escena comienza antes de que la página esté lista. Espera a que el elemento de la escena esté listo (
await locator.waitFor()) antes de llamar ascene(), no dentro de ella, para que el tiempo de carga no se narre. - Los primeros segundos son una página en blanco.
mux.pyrecorta todo lo anterior a la primera escena. Realiza la navegación y las esperas antes descene('01'). - Inicio de sesión en cámara. Usa la opción
login. Nadie necesita ver un campo de contraseña y las credenciales no deben ser visibles en un video compartido.