agentshot: capturas de pantalla y videos demo
La herramienta está en /path/to/agentshot. Ejecútala como:
node /path/to/agentshot/bin/agentshot.mjs <comando> ...
A continuación, agentshot significa ese comando. Cada comando imprime una línea JSON ("ok": true|false). Los renders largos también imprimen progreso en stderr.
Ejecuta agentshot help para ver la lista de comandos.
Flujo de trabajo
- Primero lee las reglas del producto:
agentshot style <producto>imprimestyle.json(aspecto predeterminado) yguidelines.md(lo que le gusta al usuario). Síguelas. Si el producto es nuevo, ejecutaagentshot style <producto> --init. - Captura (elige una):
- Aplicación web o Expo → escribe un escenario JSON con
"url", ejecutaagentshot capture scenario.json. - Aplicación iOS en Mac → un escenario con
"simulator"(la aplicación nativa real en el Simulador de iOS, consulta "iOS Simulator"); una imagen fija rápida →agentshot sim snap --name <captura> --clean-status-bar. - Programa de escritorio → un escenario con
"window": conduces el ratón/teclado real mientras graba (consulta "Desktop app"). Solo una imagen fija →agentshot snap --window "<título>" --name <captura>. El usuario realiza las acciones →agentshot record start/stop. - El usuario ya tiene un archivo (captura de pantalla de iPhone / grabación de pantalla) →
agentshot import <archivo> --name <captura>.
- Aplicación web o Expo → escribe un escenario JSON con
- Inspecciona:
agentshot inspect <captura>enumera tomas, cuadros de elementos (puntos en pantalla), clics, duración y, para videos,moves(trayectoria del puntero),changes(cambios de página: grandes saltos visuales),quiet(nada se mueve: cortar o acelerar) y eltimelinedel escenario. Planifica cortes y zooms a partir de estos números, luego confirma conagentshot frames <captura> --from a --to b(una hoja de contactos con marcas de tiempo; lee el PNG que imprime). Mira el PNG de la toma con la herramienta Read antes de estilizar. - Escribe una receta JSON y
agentshot render recipe.json --note "<lo que cambió>". - Verifica el resultado tú mismo: Lee el PNG; para MP4,
agentshot frames <producto>/<activo>(video completo) yagentshot frames <producto>/<activo> --from 3 --to 4 --every 0.033 --crop x,y,w,h(fotograma a fotograma alrededor de un corte o clic). Corrige y vuelve a renderizar (se añade una nueva versión). Cuando el usuario quiera revisar o ajustar una receta por sí mismo, ejecutaagentshot preview recipe.jsonen segundo plano: abre una página local con la escena y un control deslizante, y se actualiza en vivo cuando se edita la receta (o elstyle.jsondel producto). Imprime una línea JSON con laurly sigue sirviendo. - Informa la ruta de salida (
results[].output).--copy-to <dir>también la copia al proyecto del usuario. - Aprende: cuando el usuario corrige o elogia algo, añade una línea con fecha al
guidelines.mddel producto (y actualiza los valores predeterminados destyle.jsonsi es un aspecto predeterminado). Léelo la próxima vez.
Mantén los escenarios y recetas en el proyecto del usuario (por ejemplo, docs/shots/) para que puedan reejecutarse después de cambios en la UI.
Escenario (capturar una aplicación web)
Los comentarios en los ejemplos JSON a continuación son solo explicaciones; los archivos reales deben ser JSON simple.
{
"name": "ellie-today-drag", // nombre de captura, único; prefija con el producto
"url": "http://localhost:8081", // o una ruta de archivo
"device": "iphone", // iphone | iphone-max | ipad | desktop | laptop
"safeArea": true, // Expo/RN web: Chrome informa los insets del área segura de iPhone, la aplicación se distribuye
// como en un dispositivo ("pad" = forzar relleno para aplicaciones que ignoran los insets)
"css": "[class*='navigationMenuRoot'] { display: none }", // ocultar chrome solo web (las pestañas de Expo Router se renderizan como un menú superior en web)
"waitFor": "today-list", // esperar este elemento antes de empezar
"track": { "fila": "text=Planear un cumpleaños" }, // cuadros de elementos con nombre adicionales para registrar
"steps": [
{ "shot": "main" }, // imagen fija a resolución completa (para capturas de pantalla)
{ "wait": 0.6 },
{ "tap": "add-button" }, // hacer clic/tocar un objetivo (se mueve allí primero)
{ "type": "Comprar leche", "into": "title-input" },
{ "press": "Enter" },
{ "drag": "task-cumpleaños", "to": "slot-11am", "duration": 1.4 },
{ "scroll": 400, "duration": 0.8 },
{ "move": [200, 300], "duration": 0.6 },
{ "goto": "/settings" },
{ "waitFor": "settings-title" },
{ "shot": "after" }
]
}
Objetivos: un nombre simple coincide con data-shot="..." o data-testid="..." (el testID de React Native se convierte en data-testid en web, por lo tanto añade testIDs a los elementos que quieras señalar), o cualquier selector de Playwright (text=Guardar, role=button[name="Guardar"], #id, .class), o [x, y] en px CSS.
Todos los elementos con data-shot/data-testid se registran con sus cuadros, más las entradas de track.
Temporización: por defecto ("timing": "frame") el reloj de la página se pausa y avanza exactamente un fotograma a la vez (60 fps) con una captura de pantalla a resolución completa por fotograma, por lo que las animaciones de la aplicación son suaves a cualquier resolución; la captura toma algunas veces más que el escenario. Usa "timing": "real" solo si la aplicación se rompe con un reloj controlado (un paso entonces expira). agentshot capture informa los tiempos de clic (clicks) para planificar cuts/zoom, y errores/advertencias de consola (console). Las superposiciones de desarrollo (toast de Expo LogBox, indicador de Next.js) están ocultas; "devOverlays": true las mantiene.
Prefiere un segmento continuo de cuts en lugar de varios cortes duros: los saltos entre segmentos se ven bruscos.
Encontrar objetivos en una aplicación sin testIDs: abre la página con Playwright y lista botones/entradas (role, aria-label, texto), luego usa text=..., role=button[name=/^Mi hija/] o [aria-label='Tu oración'], y nombra los cuadros que quieras elevar/lupa mediante track.
Escribir en un campo cubierto por un pie de página adhesivo aún funciona (el campo recibe el foco).
Expo: primero inicia la compilación web (npx expo start --web, generalmente http://localhost:8081). Los módulos solo nativos pueden no funcionar en web; si una pantalla se rompe, pide al usuario una captura de pantalla/grabación de iPhone e importala.
Aplicación de escritorio (escenario con "window")
agentshot windows lista ventanas (título, proceso, tamaño). La ventana se empareja por título, luego por nombre de proceso, se restaura si está minimizada y se trae al frente. Las coordenadas son píxeles de la ventana: mira primero una imagen fija (agentshot snap --window "X" --name x-probe, lee el PNG) y nombra los cuadros que uses en track.
{
"name": "notes-tour",
"window": "Notas", // parte del título o nombre del proceso
"track": { "nav-recent": [20, 200, 190, 40], "nav-search": [20, 96, 190, 40], "contenido": [232, 40, 1030, 650], "perfil": [16, 718, 150, 62] },
"cursor": [1000, 330], // donde comienza el puntero
"steps": [
{ "shot": "home" }, // fija = el fotograma grabado en este momento
{ "wait": 1 },
{ "click": "nav-recent", "duration": 0.9 }, // deslizarse allí (suavizado, ligero arco), hacer clic de inmediato
{ "waitStill": 0.6, "region": "contenido" }, // esperar a que la pantalla cambie, luego que se estabilice
{ "shot": "recent" },
{ "wheel": 4, "at": [760, 460] }, // desplazar 4 muescas hacia abajo (negativo = arriba)
{ "click": "nav-search" }, { "press": "ctrl+a" },
{ "type": "Plan semanal", "cps": 12 }, // cualquier texto, incluidos scripts no latinos
{ "press": "Enter" }, // teclas: enter esc tab space backspace delete arrows home end f1..f12, ctrl/alt/shift/win+x
{ "drag": [100, 300], "to": [400, 300], "duration": 1.2 },
{ "click": [640, 400], "button": "right" }, { "click": [640, 400], "double": true },
{ "note": "compás 2" } // marcador en la línea de tiempo
]
}
-
El resultado tiene
timeline(inicio/fin de cada paso en segundos de video,at= momento del clic) yshots(fijas extraídas del video). Las recetas usan nombres detrackcomo objetivos ("blur"en"perfil"etc.). -
waitStillprimero espera (hastachangeTimeout, 3 s) hasta que la región difiera de cómo estaba (change, diferencia media de píxeles, predeterminado 6;"change": falsepara solo dejar que se estabilice), luego hasta que nada cambió durante los segundos dados (threshold0.6). Usa unaregionsin partes animadas (reproductores, fondos vivos). -
Haz clic justo después de llegar: un cursor reposando en un control ~0.5 s hace que los tooltips de Windows aparezcan en el video.
-
Campos que retienen texto antiguo:
press ctrl+aantes detype. -
El controlador se inicia antes de la grabación (necesita unos segundos) y mueve el cursor real: no uses la máquina mientras tanto. Las capturas de escritorio son 1x, por lo que una lupa se ve suave; prefiere
lift. -
Imágenes fijas en cualquier momento de una grabación:
agentshot snap <captura> --at 12.4 --shot nombre. -
Los cambios pequeños (que se cierra un popup) pueden no alcanzar
changeen toda la ventana: daregionalrededor de ellos. -
Atajos:
modes Ctrl en Windows y Cmd en macOS ("press": "mod+a"), por lo que un escenario funciona en ambos.
Grabación manual (el usuario hace las acciones; el cursor se registra y lo dibuja el renderizador):
agentshot record --name app-filter --window "Figma" --duration 12 # graba 12 s, luego se detiene
agentshot record start --name app-filter --window "Figma" # o iniciar ...
agentshot record stop # ... y detener después
macOS
Mismos comandos y escenarios que en Windows; recorder/mac.swift se compila en el primer uso (necesita las herramientas de línea de comandos de Xcode y macOS 14+). Ejecuta agentshot doctor primero: la aplicación que ejecuta el agente (Terminal, iTerm, Claude, VS Code) necesita Grabación de pantalla y Accesibilidad en Preferencias del Sistema > Privacidad y Seguridad (agentshot doctor --request abre los avisos; reinicia esa aplicación después de concederlos). Sin Grabación de pantalla los títulos de las ventanas son solo nombres de aplicación y la grabación falla; sin Accesibilidad el controlador no puede hacer clic ni escribir.
- Las coordenadas (
track, pasos, objetivos de receta) son puntos; las imágenes fijas y el video están a la escala de píxeles de la pantalla (2 en Retina,inspectmuestrascale), por lo que las elevaciones y zooms permanecen nítidos. - ScreenCaptureKit graba la ventana en sí: puede estar parcialmente cubierta, pero no debe estar minimizada.
node scripts/selftest-mac.mjsverifica todo en TextEdit (y el simulador si uno está iniciado) e imprime lo que falló. Comprobación de sincronización:agentshot record ... --show-cursorquema el cursor real en el video; compáralo con el puntero registrado (agentshot framesvsinspect) como cualquier grabación.
iOS Simulator (macOS)
La aplicación nativa en lugar de su compilación web: fuentes reales, módulos nativos, animaciones de iOS. Inicia un simulador (open -a Simulator), ejecuta la aplicación en él (npx expo run:ios o una compilación de desarrollo), luego:
agentshot sim devices # simuladores iniciados
agentshot sim snap --name app-home --clean-status-bar # imagen fija sin pérdida, 9:41 / batería completa
agentshot sim record start --name app-flow # alguien más conduce ...
agentshot sim record stop
Un escenario lo conduce con idb (brew install facebook/fb/idb-companion, pipx install fb-idb); las coordenadas son puntos del dispositivo (lee un sim snap y divide sus píxeles por scale):
{
"name": "app-onboarding",
"simulator": "booted", // o un UDID o parte del nombre del dispositivo
"statusBar": "clean", // 9:41 durante la captura, borrado después
"appearance": "light", // o "dark"
"openUrl": "exp://127.0.0.1:8081/--/today", // enlace profundo antes de grabar (o "launch": "<bundle id>")
"track": { "add": [330, 760, 48, 48], "title": [24, 120, 340, 44] },
"steps": [
{ "shot": "today" },
{ "tap": "add" },
{ "waitStill": 0.5 },
{ "type": "Comprar leche" }, // en el campo enfocado
{ "press": "enter" }, // enter esc backspace tab space arrows home lock
{ "swipe": [200, 600], "to": [200, 250], "duration": 0.4 },
{ "openUrl": "exp://127.0.0.1:8081/--/settings" },
{ "waitStill": 0.6 },
{ "shot": "settings" }
]
}
Las imágenes fijas son capturas de pantalla del simulador sin pérdida; los toques y deslizamientos se convierten en el puntero táctil y clics, por lo que las recetas usan "pointer": "touch" y "device": "iphone-black" como en las capturas del navegador. Sin idb solo funcionan los pasos wait/waitStill/agentshot/openUrl/launch.
Receta (estilo y renderizado)
{
"name": "today-drag", // nombre del activo en la biblioteca
"product": "ellie", // carpeta de la biblioteca; se aplican los valores predeterminados de style.json
"capture": "ellie-today-drag",
"shot": "main", // establece para un PNG fijo; omítelo para un video MP4
"size": "16:9", // 16:9 16:10 4:3 3:2 1:1 4:5 9:16, o ancho/alto
"background": "lavender", // lavender peach sage sky rose mint neutral midnight ink white,
// cualquier color/gradiente CSS, o una imagen en public/ (backgrounds/x.jpg)
"backgroundBlur": 0.02, // para fondos de foto, proporción del lado corto
"device": "iphone-black", // iphone-black iphone-natural iphone-white browser window none
"url": "app.ellie.so/today", // texto de la barra del navegador; "title": título de la ventana para "window"
"padding": 0.08, "tilt": 12, // margen del dispositivo; inclinación 3D en grados
"position": [0.69, 0.5], // centro del dispositivo en el lienzo, deja espacio para un título a su lado
"accent": "#6d5ce8", // color de pasos, contornos, etiquetas, ondas de clic
"font": "Gilda Display", "labelFont": "Inter", // títulos / etiquetas de elevación: Inter Manrope Poppins Nunito Fraunces Lora
// "Playfair Display" "DM Serif Display" "Gilda Display" "Cormorant Garamond" Caveat
"lift": { "target": "task-row", "label": "Arrástralo a tu día", "start": 3.9, "pad": 10, "dim": 0.1 },
"loupe": { "target": "label-chip", "anchor": [0.2, 0.5], "zoom": 2.3, "size": 0.12, "offset": [-0.15, 0.12] },
"annotations": [
{ "type": "step", "target": "row-principal", "label": "Paso 1", "color": "#ffffff", "background": true, "radius": true },
{ "type": "arrow", "from": [0.32, 0.29], "to": [0.38, 0.48], "color": "#ffffff", "width": 6, "style": "solid" },
{ "type": "note", "x": 0.55, "y": 0.7, "label": "¿Nuevo en Ellie?", "width": 150, "align": "left", "color": "#ffffff", "background": true },
{ "type": "cursor", "x": 0.34, "y": 0.33, "shape": "dot", "color": "#ffffff" }
],
"blur": { "target": "perfil", "radius": 6, "exclude": "avatar" },
"cuts": [
{ "from": 0, "to": 1.2, "speed": 1 },
{ "from": 4.5, "to": 5.8, "speed": 3 },
{ "from": 7, "to": 9, "zoom": 1.4, "anchor": [0.3, 0.5] },
{ "from": 9, "to": 11, "crop": [130, 230, 330, 550] }
],
"info": [
{ "title": "Ellie – Asistente de citas", "subtitle": "Arrastra tareas a tu horario", "icon": "public/logos/ellie.jpg" },
{ "title": "Lleva un registro de tus planes", "subtitle": "Solo se necesita un clic" }
],
"timeline": { "show": true, "height": 22, "color": "#6d5ce8", "labels": false, "markers": ["compás 2"], "trim": [0, 10] },
"pointer": "click", // "click" (círculo pequeño) "touch" (círculo semitransparente) "none"
"resolution": 144, // 72 144 288 300 ppi
"credits": "© 2025 Ellie Inc."
}
Grupos de recetas: en lugar de un único objeto {}, un array separa las escenas, cada una con su propio capture/shot/cuts, renderizadas en secuencia en un MP4. intro/outro añade una tarjeta de título/final. Ejemplo:
[
{ "intro": { "title": "Ellie", "subtitle": "Agenda inteligente", "duration": 2 } },
{ "name": "crear-tarea", ... },
{ "name": "arrastrar", "capture": "ellie-today-drag", ... },
{ "outro": { "title": "Prueba Ellie", "subtitle": "grellie.com", "duration": 3, "action": "cta" } }
]
Cada grupo debe tener un name único (establecido o por defecto) y una salida results[].output. La música de fondo: "audio": "public/audio/chill.mp3" (o "none"). intro/outro también puede ser un video corto ("video": "public/intros/globe.mp4").
Línea de tiempo: las escenas que no sean intro/outro deben tener una propiedad timeline si quieres la barra de progreso; pueden compartir estilo.
Cortes automáticos: si se omite cuts, toda la escena se renderiza completa (speed: 1). "trim": [0, 10] recorta el video a los primeros 10 segundos.
Superposiciones de video: "overlay": { "file": "file.mp4", "position": "bottom-left", "scale": 0.12, "opacity": 0.6, "radius": true, "shadow": true } añade un video PiP (el usuario grabando, una reacción). El archivo se reproduce en bucle o hasta que dure la escena.
Renderizado
agentshot render recipe.json --note "nuevo flujo de arrastre" compila el video/PNG en la biblioteca del producto:
products/
ellie/
today-drag/
1.png # primera versión
render-1.json # la receta usada
note-1.txt # "nuevo flujo de arrastre"
2.png
render-2.json
note-2.txt
products/ellie/style.json contiene los valores predeterminados de los productos (fondo, dispositivo, inclinación, relleno, posición, acento, familia de fuentes, resolución) y guidelines.md para notas narrativas. Los activos versionados permiten comparar versiones: siempre renderiza en una nueva versión pero informa la última. El usuario puede cambiar style.json (o proporcionar uno específico en la receta con "style": "...").
Para renderizar directamente a la ubicación de la UI de producción: --copy-to ../assets/shots/.
applyStyle (cambiar el aspecto de una imagen existente)
Toma un PNG, aplica el fondo, el marco del dispositivo y los créditos, imprime el PNG renderizado en stdout (única línea JSON). Los parámetros se pasan como banderas: agentshot applyStyle <archivo> --background "lavender" --device "iphone-black" --url "ellie.so". No se necesita ningún escenario.
Integración con Claude
Cuando se te pida que tomes una captura de pantalla:
- Identifica qué capturar (página web, aplicación Expo, ventana de escritorio, Simulador de iOS). Si es una aplicación web, ¿está en ejecución el servidor web? (Pregunta al usuario; si no, pídeles que comiencen
npx expo startonpm run dev). - Escribe un escenario JSON. Asegúrate de que la URL coincida con el servidor en ejecución. Usa
shots/dentro del proyecto del usuario. Solicita la URL si no está clara y las dimensiones aproximadas del dispositivo (o smartphone/tableta/escritorio). - Ejecuta
agentshot capture scenario.json. Comprueba la salida. - Ejecuta
agentshot inspect <captura>para ver tomas/bloques de escenario, duración y, para videos,moves,changes,quietytimeline. - Escribe una receta JSON y
agentshot render recipe.json. Comprueba la salida. - Lee el PNG renderizado (o fotogramas de una sección del MP4) para verificar que se vea bien. Pregunta al usuario cómo se ve, luego ajusta y vuelve a renderizar si es necesario.
- Reporta la biblioteca actualizada al usuario (
products/<producto>/<activo>/<n-último>.(png|mp4)), manteniendo los activos versionados.
Nota: Desktop app y Simulador deben ejecutarse en un monitor que el agente pueda leer (macOS / Windows con herramientas de accesibilidad). En Simulador de iOS, el agente puede no ver el contenido de la aplicación sin idb; usa sim snap para imágenes fijas.`