O que agentshot: capturas de tela e vídeos de demonstração faz?
A ferramenta está em /path/to/agentshot. Execute-a como:
node /path/to/agentshot/bin/agentshot.mjs <comando> ...
Abaixo, agentshot significa esse comando. Cada comando imprime uma linha JSON ("ok": true|false). Renderizações longas também imprimem progresso no stderr.
Execute agentshot help para a lista de comandos.
Fluxo de trabalho
- Leia as regras do produto primeiro:
agentshot style <produto>imprimestyle.json(aparência padrão) eguidelines.md(o que o usuário gosta). Siga-as. Se o produto for novo, executeagentshot style <produto> --init. - Capture (escolha um):
- Aplicativo web ou Expo app → escreva um JSON de cenário com
"url", executeagentshot capture scenario.json. - Aplicativo iOS em um Mac → um cenário com
"simulator"(o aplicativo nativo real no iOS Simulator, veja "iOS Simulator"); uma imagem estática rápida →agentshot sim snap --name <capture> --clean-status-bar. - Programa de desktop → um cenário com
"window": você controla o mouse/teclado real enquanto ele grava (veja "Desktop app"). Apenas uma imagem estática →agentshot snap --window "<titulo>" --name <capture>. O usuário realiza as ações →agentshot record start/stop. - O usuário já tem um arquivo (captura de tela do iPhone / gravação de tela) →
agentshot import <arquivo> --name <capture>.
- Aplicativo web ou Expo app → escreva um JSON de cenário com
- Inspecione:
agentshot inspect <capture>lista disparos, caixas de elementos (pontos da tela), cliques, duração e, para vídeos,moves(movimento do cursor),changes(mudanças de página: grandes saltos visuais),quiet(nada se move: corte ou acelere) e otimelinedo cenário. Planeje cortes e zooms a partir desses números, depois confirme comagentshot frames <capture> --from a --to b(uma folha de contato com timestamps; Leia o PNG que imprime). Olhe para o PNG do disparo com a ferramenta Leitura antes de estilizar. - Escreva uma receita JSON e
agentshot render recipe.json --note "<o que mudou>". - Verifique o resultado você mesmo: Leia o PNG; para MP4,
agentshot frames <produto>/<ativo>(vídeo inteiro) eagentshot frames <produto>/<ativo> --from 3 --to 4 --every 0.033 --crop x,y,w,h(quadro a quadro em torno de um corte ou clique). Corrija e renderize novamente (uma nova versão é adicionada). Quando o usuário quiser explorar ou ajustar uma receita por conta própria, executeagentshot preview recipe.jsonem segundo plano: ele abre uma página local com a cena e um controle deslizante e atualiza ao vivo quando a receita (ou ostyle.jsondo produto) é editada. Ele imprime uma linha JSON com aurle continua servindo. - Relate o caminho de saída (
results[].output).--copy-to <dir>também o copia para o projeto do usuário. - Aprenda: quando o usuário corrige ou elogia algo, anexe uma linha datada ao
guidelines.mddo produto (e atualize os padrões destyle.jsonse for uma aparência padrão). Leia-o na próxima vez.
Mantenha cenários e receitas no projeto do usuário (por exemplo, docs/shots/) para que possam ser reexecutados após mudanças na interface do usuário.
Cenário (capturar um aplicativo web)
Os comentários nos exemplos JSON abaixo são apenas explicações; arquivos reais devem ser JSON simples.
{
"name": "ellie-hoje-arrastar", // nome da captura, único; prefixo com o produto
"url": "http://localhost:8081", // ou um caminho de arquivo
"device": "iphone", // iphone | iphone-max | ipad | desktop | laptop
"safeArea": true, // Expo/RN web: Chrome relata insets de área segura do iPhone, o aplicativo se organiza
// como em um dispositivo ("pad" = forçar padding para aplicativos que ignoram insets)
"css": "[class*='navigationMenuRoot'] { display: none }", // ocultar chrome somente web (as abas do Expo Router são renderizadas como um menu superior na web)
"waitFor": "lista-hoje", // esperar por este elemento antes de começar
"track": { "linha": "text=Planejar um aniversário" }, // caixas de elementos nomeados extras para gravar
"steps": [
{ "shot": "principal" }, // imagem estática em resolução total (para capturas de tela)
{ "wait": 0.6 },
{ "tap": "botao-adicionar" }, // clicar/tocar em um alvo (move-se até lá primeiro)
{ "type": "Comprar leite", "into": "input-titulo" },
{ "press": "Enter" },
{ "drag": "tarefa-aniversario", "to": "slot-11h", "duration": 1.4 },
{ "scroll": 400, "duration": 0.8 },
{ "move": [200, 300], "duration": 0.6 },
{ "goto": "/configuracoes" },
{ "waitFor": "titulo-configuracoes" },
{ "shot": "depois" }
]
}
Alvos: um nome simples corresponde a data-shot="..." ou data-testid="..." (testID do React Native torna-se
data-testid na web, então adicione testIDs aos elementos que deseja apontar), ou qualquer seletor do Playwright
(text=Salvar, role=button[name="Salvar"], #id, .class), ou [x, y] em px CSS.
Todos os elementos com data-shot/data-testid são gravados com suas caixas, além das entradas track.
Timing: por padrão ("timing": "frame"), o relógio da página é pausado e avançado exatamente um quadro
por vez (60 qps) com uma captura de tela em resolução total por quadro, para que as animações do aplicativo sejam suaves em
qualquer resolução; a captura leva algumas vezes mais tempo que o cenário. Use "timing": "real" apenas se
o aplicativo quebrar sob um relógio controlado (um passo então expira). agentshot capture relata os tempos de clique
(clicks) para planejar cuts/zoom e erros/avisos do console (console). Sobreposições de desenvolvimento (toast do Expo LogBox,
indicador do Next.js) são ocultadas; "devOverlays": true as mantém.
Prefira um segmento contínuo cuts em vez de vários cortes duros: saltos entre segmentos parecem entrecortados.
Encontrando alvos em um aplicativo sem testIDs: abra a página com Playwright e liste botões/inputs
(role, aria-label, texto), depois use text=..., role=button[name=/^Minha filha/] ou
[aria-label='Sua oração'] e nomeie caixas que deseja elevar/lupa por meio de track.
Digitar em um campo coberto por um rodapé fixo ainda funciona (o campo recebe foco).
Expo: inicie a compilação web primeiro (npx expo start --web, geralmente http://localhost:8081). Módulos somente
nativos podem não funcionar na web; se uma tela quebrar, peça ao usuário uma captura de tela/gravação do iPhone e faça import.
Desktop app (cenário com "window")
agentshot windows lista janelas (título, processo, tamanho). A janela é correspondida pelo título, depois pelo nome do processo,
restaurada se minimizada e trazida para frente. As coordenadas são pixels da janela: veja uma imagem estática primeiro
(agentshot snap --window "X" --name x-probe, Leia o PNG) e nomeie as caixas que você usa em track.
{
"name": "tour-notas",
"window": "Notes", // parte do título ou nome do processo
"track": { "nav-recente": [20, 200, 190, 40], "nav-pesquisa": [20, 96, 190, 40], "conteudo": [232, 40, 1030, 650], "perfil": [16, 718, 150, 62] },
"cursor": [1000, 330], // onde o ponteiro começa
"steps": [
{ "shot": "inicio" }, // estático = o quadro gravado neste momento
{ "wait": 1 },
{ "click": "nav-recente", "duration": 0.9 }, // deslizar até lá (com easing, leve arco), clicar imediatamente
{ "waitStill": 0.6, "region": "conteudo" }, // aguardar a tela mudar, depois estabilizar
{ "shot": "recente" },
{ "wheel": 4, "at": [760, 460] }, // rolar 4 notches para baixo (negativo = para cima)
{ "click": "nav-pesquisa" }, { "press": "ctrl+a" },
{ "type": "Plano semanal", "cps": 12 }, // qualquer texto, incluindo scripts não 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": "batida 2" } // marcador no timeline
]
}
-
O resultado tem
timeline(início/fim de cada passo em segundos de vídeo,at= momento do clique) eshots(imagens estáticas cortadas do vídeo). As receitas usam nomes detrackcomo alvos ("blur"em"perfil"etc.). -
waitStillprimeiro espera (atéchangeTimeout, 3 s) até que a região difira de como estava (change, diferença média de pixel, padrão 6;"change": falsepara apenas deixar estabilizar), depois até que nada tenha mudado pelos segundos fornecidos (threshold0.6). Use umaregionsem partes animadas (players, fundos vivos). -
Clique logo após chegar: um cursor descansando em um controle ~0,5 s faz com que dicas de ferramentas do Windows apareçam no vídeo.
-
Campos que mantêm texto antigo:
press ctrl+aantes detype. -
O driver inicia antes da gravação (precisa de alguns segundos) e move o cursor real: não use o computador durante esse período. As capturas de desktop são 1x, portanto uma lupa parece suave; prefira
lift. -
Imagens estáticas a qualquer momento de uma gravação:
agentshot snap <capture> --at 12.4 --shot name. -
Pequenas alterações (um popup fechando) podem não atingir
changeem toda a janela: forneçaregionem torno delas. -
Atalhos:
modé Ctrl no Windows e Cmd no macOS ("press": "mod+a"), portanto um cenário é executado em ambos.
Gravação manual (o usuário faz as ações; o cursor é registrado e desenhado pelo renderizador):
agentshot record --name app-filtro --window "Figma" --duration 12 # grava 12 s, depois para
agentshot record start --name app-filtro --window "Figma" # ou inicia ...
agentshot record stop # ... e para depois
macOS
Mesmos comandos e cenários que no Windows; o gravador/mac.swift é compilado no primeiro uso (requer as Ferramentas de Linha de Comando do Xcode
macOS 14+). Execute agentshot doctor primeiro: o aplicativo que executa o agente (Terminal, iTerm,
Claude, VS Code) precisa de Gravação de Tela e Acessibilidade em Ajustes do Sistema > Privacidade e Segurança
(agentshot doctor --request abre os prompts; reinicie esse aplicativo após conceder). Sem Gravação de Tela, os títulos das janelas
são apenas nomes de aplicativos e a gravação falha; sem Acessibilidade, o driver não pode clicar ou digitar.
- Coordenadas (
track, passos, alvos da receita) são pontos; imagens estáticas e vídeo estão na escala de pixels da tela (2 no Retina,inspectmostrascale), portanto elevações e zooms permanecem nítidos. - ScreenCaptureKit grava a própria janela: ela pode estar parcialmente coberta, mas não deve estar minimizada.
node scripts/selftest-mac.mjsverifica tudo no TextEdit (e no simulador se um estiver inicializado) e imprime o que falhou. Verificação de sincronia:agentshot record ... --show-cursorqueima o cursor real em; compare-o com o ponteiro registrado (agentshot framesvsinspect) como qualquer gravação.
iOS Simulator (macOS)
O aplicativo nativo em vez de sua compilação web: fontes reais, módulos nativos, animações iOS. Inicialize um simulador
(open -a Simulator), execute o aplicativo nele (npx expo run:ios ou uma compilação de desenvolvimento), então:
agentshot sim devices # simuladores inicializados
agentshot sim snap --name app-inicio --clean-status-bar # imagem estática sem perdas, 9:41 / bateria cheia
agentshot sim record start --name app-fluxo # outra pessoa dirige ...
agentshot sim record stop
Um cenário o dirige com idb (brew install facebook/fb/idb-companion, pipx install fb-idb); as coordenadas
são pontos do dispositivo (Leia um sim snap e divida seus pixels por scale):
{
"name": "app-onboarding",
"simulator": "booted", // ou um UDID ou parte do nome do dispositivo
"statusBar": "clean", // 9:41 durante a captura, limpo depois
"appearance": "light", // ou "dark"
"openUrl": "exp://127.0.0.1:8081/--/hoje", // deep link antes da gravação (ou "launch": "<bundle id>")
"track": { "add": [330, 760, 48, 48], "title": [24, 120, 340, 44] },
"steps": [
{ "shot": "hoje" },
{ "tap": "add" },
{ "waitStill": 0.5 },
{ "type": "Comprar leite" }, // no campo focado
{ "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/--/configuracoes" },
{ "waitStill": 0.6 },
{ "shot": "configuracoes" }
]
}
As imagens estáticas são capturas de tela do simulador sem perdas; toques e deslizes tornam-se o ponteiro de toque e cliques, portanto
as receitas usam "pointer": "touch" e "device": "iphone-black" como nas capturas do navegador. Sem idb, apenas
os passos wait/waitStill/agentshot/openUrl/launch funcionam.
Receita (estilo e renderização)
{
"name": "arrastar-hoje", // nome do ativo na biblioteca
"product": "ellie", // pasta da biblioteca; os padrões de style.json se aplicam
"capture": "ellie-hoje-arrastar",
"shot": "principal", // definido para um PNG estático; omita para um vídeo MP4
"size": "16:9", // 16:9 16:10 4:3 3:2 1:1 4:5 9:16, ou largura/altura
"background": "lavender", // lavender peach sage sky rose mint neutral midnight ink white,
// qualquer cor/gradiente CSS, ou uma imagem em public/ (backgrounds/x.jpg)
"backgroundBlur": 0.02, // para fundos de foto, fração do lado curto
"device": "iphone-black", // iphone-black iphone-natural iphone-white browser window none
"url": "app.ellie.so/hoje", // texto da barra do navegador; "title": título da janela para "window"
"padding": 0.08, "tilt": 12, // margem do dispositivo; inclinação 3D em graus
"position": [0.69, 0.5], // centro do dispositivo na tela, deixa espaço para um título ao lado
"accent": "#6d5ce8", // cor dos passos, contornos, rótulos, ondulações de clique
"font": "Gilda Display", "labelFont": "Inter", // títulos / rótulos de elevação: Inter Manrope Poppins Nunito Fraunces Lora
// "Playfair Display" "DM Serif Display" "Gilda Display" "Cormorant Garamond" Caveat
"lift": { "target": "linha-tarefa", "label": "Arrraste para o seu dia", "start": 3.9, "pad": 10, "dim": 0.1 },
"loupe": { "target": "chip-etiqueta", "anchor": [0.2, 0.5], "zoom": 2.3, "size": 0.12, "offset": [-0.15, 0.12] },
"annotations": [
{ "type": "step", "text": "1", "at": { "target": "botao-adicionar", "direction": "top", "offset": [-30, -10] }, "accent": "#ff6b6b" },
{ "type": "text", "text": "Toque em + para começar", "at": [400, 150], "fontSize": 18, "accent": "#333" },
{ "type": "arrow", "from": [400, 165], "to": [360, 210], "color": "#ff6b6b", "stroke": 2 }
],
"hideCursor": false, // ocultar o cursor nos quadros (padrão: seguir o cenário)
"cuts": [ // para MP4: quais partes do vídeo bruto incluir
{ "from": 0, "to": 10.6, "speed": 1 }, // em segundos (do timeline de inspeção); speed > 1 = acelerado
{ "from": 15.2, "to": 23.0, "speed": 0.7 },
{ "from": 120.5, "to": 127.3, "speed": 1 }
],
"zoom": [ // zooms de vídeo (opcional — corta a área ampliada para
{ "from": 0, "to": 10.6, "region": [20, 40, 190, 340] }, // coordenadas de pixel x,y,w,h)
{ "from": 15.2, "to": 23.0, "target": "botao-adicionar" }
],
"transition": "crossfade 0.3" // entre cortes (crossfade | cut | fade 0.5 | wipe 0.4)
}
Dicas
- Produto novo: execute
agentshot style <produto> --initpara criar os arquivos de diretrizes e estilo. - Pós-processamento: você pode ajustar cores, adicionar legendas e cortar a saída com ferramentas externas como ImageMagick ou ffmpeg.
- Depuração: use
agentshot inspectpara entender o timeline e os elementos; useagentshot framespara visualizar quadros-chave. - Versionamento: a biblioteca mantém várias versões do mesmo ativo. Sempre especifique
--noteao renderizar para rastrear as mudanças.
# Exemplo de fluxo de trabalho completo
# 1. Inicializar o estilo do produto
agentshot style meu-app --init
# 2. Capturar um cenário
cat > captura.json << 'EOF'
{
"name": "captura-tutorial",
"url": "http://localhost:3000",
"device": "iphone",
"waitFor": "conteudo-principal",
"steps": [
{ "shot": "tela-inicial" },
{ "wait": 0.5 },
{ "tap": "botao-proximo" },
{ "waitFor": "tela-seguinte" },
{ "shot": "passo-dois" }
]
}
EOF
agentshot capture captura.json
# 3. Inspecionar e planejar
agentshot inspect captura-tutorial
# 4. Renderizar como imagem estática
cat > receita.json << 'EOF'
{
"name": "tutorial-passo1",
"product": "meu-app",
"capture": "captura-tutorial",
"shot": "tela-inicial",
"size": "1:1",
"background": "sage",
"device": "iphone-black",
"padding": 0.05,
"lift": { "target": "botao-proximo", "label": "Próximo passo", "start": 0, "pad": 5, "dim": 0.15 }
}
EOF
agentshot render receita.json --note "Primeira foto do tutorial"
# 5. Verificar o resultado
agentshot frames meu-app/tutorial-passo1
Solução de problemas
- Erro de permissão no macOS: execute
agentshot doctore conceda Gravação de Tela e Acessibilidade ao seu terminal/IDE. - Falha na captura do iOS Simulator: certifique-se de que o simulador esteja inicializado e que o aplicativo esteja em execução. Use
agentshot sim devicespara listar simuladores disponíveis. - Falha na captura do aplicativo web: verifique se o servidor de desenvolvimento está em execução e acessível no URL especificado.
- Erros de renderização: verifique os logs do console para obter detalhes. Use
agentshot inspectpara garantir que o cenário de captura e os nomes dos ativos estejam corretos. - Cortes/zooms incorretos: ajuste os valores
from/tocom base no timeline deagentshot inspect.