Grabar una demo
Graba un recorrido que parece hecho por una persona usando la aplicación: trayectorias curvas del cursor, pulsaciones de teclas por tecla, pausas deliberadas, en lugar de una máquina teletransportándose por la interfaz de usuario.
Las reglas a continuación se aplican a cada grabación, en todas las superficies. Están aquí y no en las referencias de plataforma porque cada una se incumplió una vez y costó una toma, y porque una regla guardada junto a un solo mecanismo es una regla que la siguiente persona no lee.
Elegir la superficie
- La aplicación web - reference/web.md. Chromium sin cabeza bajo Playwright con un cursor DOM dibujado en la página. Nada llega a la pantalla del operador, así que prefiere esto siempre que el cambio sea visible en un navegador.
- La aplicación de escritorio - reference/desktop.md. Necesario cuando la demo requiere el shell real de Electron: menús nativos, diálogos de archivo, bandeja, múltiples ventanas o cualquier cosa fuera del renderizador. Linux tiene un ejecutor empaquetado; macOS graba una sola ventana por ID y aún no tiene ejecutor.
Si el cambio es visible en ambas, graba la aplicación web.
Entradas
Establécelas antes de la primera toma. Léelas del proyecto donde puedas (su README, scripts en package.json, el proceso principal de Electron); pregunta al usuario lo que no puedas encontrar en lugar de adivinar.
- Web: la URL de la aplicación en ejecución, pasada al grabador como
PR_RECORDER_BASE_URL(p. ej.http://localhost:3000). La aplicación ya debe estar ejecutándose desde el checkout que tiene el cambio, incluyendo ediciones no confirmadas - un checkout fresco de la misma rama no las tendrá, y Git se niega a hacer checkout de una rama dos veces. También debe estar en el estado que la demo necesite. Si el flujo requiere un usuario autenticado o datos sembrados, es responsabilidad de la configuración del proyecto, no del grabador - pero confírmalo antes de que comience la captura, o la toma que obtengas será de una pantalla de inicio de sesión. - Escritorio:
DEMO_APP_DIR- el directorio en el que se ejecuta el comando de lanzamiento de la aplicación.DEMO_WINDOW_TITLE- el título exacto de la ventana principal, utilizado para encontrar tanto la ventana X11 como la página del renderizador.DEMO_LAUNCH_CMD- opcional. Un comando de shell que inicia la aplicación con depuración remota en{port}. El valor predeterminado,pnpm dev --remoteDebuggingPort {port} --noSandbox, funciona con electron-vite.
Dónde vive la habilidad
<dir-habilidad> en estos documentos significa el directorio desde el que se cargó este SKILL.md. En Claude Code es ${CLAUDE_SKILL_DIR}, que funciona tanto para instalaciones de proyecto, personales como de complementos. En otros lugares, usa la ruta desde la que se cargó la habilidad - para Codex, una carpeta .agents/skills/record-demo en el repositorio o ~/.agents/skills/record-demo. Resuélvela una vez y usa la ruta absoluta; los scripts nunca asumen dónde está instalada la habilidad.
Ensayar antes de la toma que cuenta
Ejecuta todo el flujo de principio a fin antes de grabar la que enviarás. Una demo se descubre, no se escribe: los nombres de los controles no son los que esperas, un botón hace algo diferente a lo que dice, y una superficie tarda más en estabilizarse de lo que suponías. Descubrirlo en cámara significa que el espectador te ve descubrirlo.
El ensayo es barato y la regrabación es barata. Enviar una toma con un giro equivocado, o pedir al revisor que ignore los ocho segundos centrales, no lo es.
Sondear los nombres reales de los controles primero
Nunca escribas un script contra un control sin haber confirmado que existe y que hace lo que su nombre sugiere. Carga la aplicación una vez, vuelca los nombres accesibles y toma una captura de pantalla:
const nombres = await page
.getByRole("button")
.evaluateAll((els) =>
els.map((e) => (e.getAttribute("aria-label") || e.textContent || "").trim()).filter(Boolean),
);
console.log(JSON.stringify(nombres));
await page.screenshot({ path: "/tmp/sonda.png" });
Luego lee la captura de pantalla. El volcado te dice que existe un nombre; solo la imagen te dice qué es el control. Cuatro formas en que esto muerde:
- Un nombre que no es el que adivinarías. El nombre accesible de un conmutador era el nombre del elemento seleccionado actualmente, no "Seleccionar proyecto".
- Un nombre que no es lo que parece. Un botón
Archivosen una barra lateral era un alternador de sección, por lo que al hacer clic se colapsaba la sección en lugar de navegar a ningún lado. Eso se envió en una toma. - Un nombre que es parte de otro nombre.
getByLabel("Primer mensaje")también coincidió con una opción cercana cuya etiqueta contenía "primer mensaje", por lo que la escritura nunca llegó al campo y nada falló. Pasaexact: trueo coincide también por rol además del nombre. - Algo que parece texto pero no lo es. El encabezado de un selector leído de una captura de pantalla era el marcador de posición de un campo de entrada, por lo que
getByTextnunca pudo coincidir con él. Confirma que un localizador se resuelve antes de escribir un script contra él.
Cuando varios elementos comparten un nombre - un elemento aparece en la barra lateral, el encabezado de la página y la ruta de navegación - delimita con .first().
Conducirlo como lo haría una persona
Encuentra los controles por rol visible o texto (getByRole, getByText, getByLabel, getByPlaceholder). Nunca selectores CSS, nunca atributos solo para pruebas, y nunca agregues un gancho a la aplicación para que una grabación pueda encontrar algo. Los scripts de demostración son desechables y por PR; mantenlos fuera del repositorio.
Nunca modifiques la aplicación, la habilidad o el código de producción para una demo. Si la demo necesita que la aplicación sea diferente, la demo está mal.
Nunca esperar en el reloj
waitForTimeout(9000) para "dejar que el editor cargue" es la causa principal de demos que se pueden ver pero son aburridas. Siempre paga el peor caso, y cada uno de esos segundos está en el archivo. Espera en lo que realmente estás esperando - el primer control con el que interactuarás - para que la demo continúe en el momento en que la aplicación esté lista y falle ruidosamente, nombrando el localizador, en lugar de conducir una página medio construida.
Las pausas fijas son solo para el ritmo: una pausa después de una acción para que el espectador pueda asimilar lo que cambió. Segundos, no decenas de segundos, y nunca como sustituto de una espera.
Un archivo escrito no es una prueba
Los grabadores vacían un archivo parcial cuando el script lanza una excepción, y algunas herramientas de captura escriben al salir lo que haya sucedido. Por lo tanto, que el archivo exista no significa nada por sí solo. Antes de creer en una toma:
- Comprueba el estado de salida y stderr, y lee el error si lo hay - generalmente nombra el localizador que no coincidió con nada.
- Comprueba si hay una captura obsoleta que ya tenga la ruta de salida. Una captura que quedó ejecutándose de un intento anterior aún posee el nombre de archivo y producirá silenciosamente una grabación de lo incorrecto.
- Comprueba los fotogramas. Extrae una hoja de contactos, el fotograma final y cualquier transición de la que no estés seguro, y míralos.
Verificar la demo, no el script
Una salida limpia dice que el script se ejecutó, no que la función funcionó. Confirma ambas:
- Visual - el cambio está en pantalla en los fotogramas, en el estado que la solicitud pidió.
- Funcional - el estado persistido realmente cambió, leído de la base de datos o de la API en lugar de inferido de la interfaz de usuario.
Cuando la afirmación es sobre el diseño - dos paneles lado a lado, un panel acoplado a un borde - afírmalo a partir de los cuadros delimitadores. Que los elementos existan no dice nada sobre dónde están.
Mantén el estado final durante unos tres segundos para que el espectador llegue a él, luego verifica el códec, las dimensiones y la duración del archivo de salida con ffprobe antes de entregarlo.
Conservar la evidencia
Conserva los registros de fallos, las tomas parciales y las capturas de pantalla hasta que una toma haya tenido éxito. Elimina el estado desechable solo después de tener algo que enviarías. Un intermedio descartado a menudo es el único registro de por qué la toma salió mal.
No molestar la máquina en la que estás grabando
Una grabación local se ejecuta en la computadora real de una persona mientras la usa.
- Dale a la aplicación su propio perfil desechable y nunca toques el perfil real del operador.
- Siembra lo que la demo necesite antes del primer lanzamiento, o las pantallas de primera ejecución aparecerán delante de ellos.
- Controla cada proceso que inicies, y detenlo cuando hayas terminado - especialmente las capturas, que siguen ejecutándose después de que el script regrese.
- Inicia procesos de larga duración como tareas en segundo plano de las que tengas un control, no con un
&al final dentro de un envoltorio en primer plano: cuando el envoltorio sale, se lleva el servidor con él. - Detén un proceso de la manera que espera ser detenido. Un servidor de desarrollo eliminado con SIGKILL omitió su trampa de limpieza y dejó un archivo de entorno reescrito y un archivo de puerto obsoleto detrás. Envía señal al proceso que iniciaste y déjalo limpiar. Nunca mates por patrón (
pkill -f next): en una máquina compartida, eso elimina también los servidores de otras personas. - Comprueba con qué backend habla la aplicación bajo demo. Un lanzador de desarrollo por defecto apuntaba a una API de producción a menos que se le indicara lo contrario, por lo que los clics de una demo habrían escrito datos reales. Apúntalo a un backend local o de desarrollo antes de la primera toma.
- Verifica cualquier recurso externo del que dependa la demo - una CLI que debe haber iniciado sesión, un servicio que debe estar activo - antes de tomar la pantalla o iniciar la captura, para que una dependencia faltante falle en un segundo en lugar de a mitad de la toma. Nunca realices una acción con efectos secundarios, como enviar un mensaje, solo para demostrar que una herramienta se lanzó.
- Si una toma necesita su pantalla, su gestor de ventanas o su entrada, dilo y pregunta, en lugar de tomarlo.
Obtener el archivo en un PR
gh sube el video por sí mismo, desde v2.99.0:
gh pr comment <numero> --body-file ./nota.md --attach ./demo.mp4
--attach también funciona en gh pr create, gh pr edit y los equivalentes de gh issue. Es repetible, hasta 50 archivos por comando, y sube al CDN de user-attachments para que GitHub renderice el video en línea.
Cuatro cosas que vale la pena saber:
- El texto alternativo es solo para imágenes.
'./captura.png#El estado de error'establece texto alternativo en una imagen; la misma sintaxis en un video es rechazada concannot set alt text on video. Adjunta videos con una ruta simple. - Un cuerpo que ya referencia la ruta local se reescribe. Escribe
donde lo quieras yghintercambia la URL subida; de lo contrario, el adjunto se agrega al final. gh pr edit --attachsin la bandera de body mantiene el body existente y le agrega contenido, por lo que se puede agregar una demo a la descripción de un PR después del hecho.- Comprueba la versión antes de confiar en ella. En
ghanterior a 2.99.0 no hay--attach, y el CDN no es accesible de ninguna otra forma a través de la API - así que recurre a darle a la persona la ruta del archivo para que lo arrastre al PR por sí misma.