Gravar uma demonstração
Grava um passo a passo que parece uma pessoa usando o aplicativo — caminhos de cursor curvos, digitação tecla por tecla, pausas deliberadas — em vez de uma máquina teletransportando pela interface.
As regras abaixo se aplicam a toda gravação, em toda superfície. Elas estão aqui em vez de nas referências da plataforma porque cada uma foi quebrada uma vez e custou uma tentativa, e porque uma regra mantida ao lado de apenas um mecanismo é uma regra que a próxima pessoa não lê.
Escolher a superfície
- A aplicação web - reference/web.md. Chromium headless sob Playwright com um cursor DOM desenhado na página. Nada atinge a tela do operador, então prefira isso sempre que a alteração for visível em um navegador.
- A aplicação desktop - reference/desktop.md. Necessário quando a demonstração requer o shell real do Electron: menus nativos, diálogos de arquivo, bandeja, várias janelas ou qualquer coisa fora do renderizador. Linux tem um executor incluído; macOS grava uma única janela por ID e ainda não tem executor.
Se a alteração for visível em ambos, grave a aplicação web.
Entradas
Estabeleça estas antes da primeira tentativa. Leia-as do projeto onde puder (seu README, scripts package.json, o processo principal do Electron); pergunte ao usuário por qualquer coisa que não conseguir encontrar, em vez de adivinhar.
- Web: a URL da aplicação em execução, passada para o gravador como
PR_RECORDER_BASE_URL(ex.:http://localhost:3000). A aplicação já deve estar em execução a partir do checkout que tem a alteração, incluindo edições não commitadas — um checkout limpo do mesmo branch não as terá, e o git se recusa a fazer checkout do mesmo branch duas vezes. Também deve estar no estado que a demonstração precisar. Se o fluxo exigir um usuário logado ou dados pré-configurados, isso é responsabilidade da configuração do projeto, não do gravador — mas confirme antes da captura começar, ou a tentativa que você obtiver será de uma tela de login. - Desktop:
DEMO_APP_DIR- o diretório onde o comando de inicialização da aplicação executa.DEMO_WINDOW_TITLE- o título exato da janela principal, usado para encontrar tanto a janela X11 quanto a página do renderizador.DEMO_LAUNCH_CMD- opcional. Um comando shell que inicia a aplicação com depuração remota na porta{port}. O padrão,pnpm dev --remoteDebuggingPort {port} --noSandbox, é adequado para electron-vite.
Onde a skill reside
<skill-dir> nestes documentos significa o diretório de onde este SKILL.md foi carregado. No Claude Code é ${CLAUDE_SKILL_DIR}, que funciona tanto para instalações de projeto, pessoais quanto de plugins. Em outros lugares, use o caminho de onde a skill foi carregada — para o Codex, uma pasta .agents/skills/record-demo no repositório ou ~/.agents/skills/record-demo. Resolva uma vez e use o caminho absoluto; os scripts nunca assumem onde a skill está instalada.
Ensaiar antes da tentativa que conta
Execute o fluxo completo do início ao fim antes de gravar aquele que você vai enviar. Uma demonstração é descoberta, não escrita: nomes de controles não são o que você espera, um botão faz algo diferente do que diz, e uma superfície leva mais tempo para estabilizar do que você imaginou. Descobrir isso na câmera significa que o espectador vê você descobrindo.
O ensaio é barato e regravar é barato. Enviar uma tentativa com um desvio errado, ou pedir ao revisor para ignorar os oito segundos do meio, não é.
Verificar primeiro os nomes reais dos controles
Nunca programe contra um controle que você não confirmou que existe e faz o que seu nome sugere. Carregue a aplicação uma vez, despeje os nomes acessíveis e tire uma captura de tela:
const names = await page
.getByRole("button")
.evaluateAll((els) =>
els.map((e) => (e.getAttribute("aria-label") || e.textContent || "").trim()).filter(Boolean),
);
console.log(JSON.stringify(names));
await page.screenshot({ path: "/tmp/probe.png" });
Em seguida, leia a captura de tela. O despejo informa que um nome existe; só a imagem informa o que o controle é. Quatro maneiras como isso pega:
- Um nome que não é o que você adivinharia. O nome acessível de um alternador era o nome do item atualmente selecionado, não "Selecionar projeto".
- Um nome que não é o que parece. Um botão
Arquivosem uma barra lateral era um alternador de seção, então clicar nele recolhia a seção em vez de navegar para qualquer lugar. Isso foi enviado em uma tentativa. - Um nome que faz parte de outro nome.
getByLabel("Primeira mensagem")também correspondia a uma opção próxima cujo rótulo continha "primeira mensagem", então a digitação nunca alcançava o campo e nada falhava. Passeexact: true, ou combine também pelo papel. - Algo que parece texto mas não é. O título de um seletor lido em uma captura de tela era o espaço reservado de um campo de entrada, então
getByTextnunca poderia corresponder a ele. Confirme que um localizador resolve antes de programar contra ele.
Quando vários elementos compartilham um nome — um item aparece na barra lateral, no cabeçalho da página e em um breadcrumb — escopo com .first().
Dirigir como uma pessoa faria
Encontre controles pelo papel visível ou texto (getByRole, getByText, getByLabel, getByPlaceholder). Nunca seletores CSS, nunca atributos apenas de teste, e nunca adicione um gancho ao aplicativo para que uma gravação possa encontrar algo. Scripts de demonstração são descartáveis e por PR; mantenha-os fora do repositório.
Nunca modifique o aplicativo, a skill ou o código de produção para uma demonstração. Se a demonstração precisar que o aplicativo seja diferente, a demonstração está errada.
Nunca esperar pelo relógio
waitForTimeout(9000) para "deixar o editor carregar" é a maior causa única de demos assistíveis, mas entediantes. Ele sempre paga o pior caso, e cada um desses segundos está no arquivo. Espere pela coisa que você está realmente esperando — o primeiro controle com o qual você interagirá — para que a demonstração continue no momento em que o aplicativo estiver pronto e falhe ruidosamente, nomeando o localizador, em vez de dirigir uma página meio construída.
Pausas fixas são apenas para ritmo: uma batida após uma ação para que um espectador possa absorver o que mudou. Segundos, não dezenas de segundos, e nunca como substituto de uma espera.
Um arquivo escrito não é prova
Os gravadores descarregam um arquivo parcial quando o script lança uma exceção, e algumas ferramentas de captura gravam na saída o que aconteceu. Então, o arquivo existir não significa nada por si só. Antes de acreditar em uma tentativa:
- Verifique o status de saída e stderr, e leia o erro se houver um — geralmente nomeia o localizador que não correspondeu a nada.
- Verifique se há uma captura obsoleta já ocupando o caminho de saída. Uma captura deixada em execução de uma tentativa anterior ainda possui o nome do arquivo e produzirá silenciosamente uma gravação da coisa errada.
- Verifique os quadros. Extraia uma folha de contatos, o quadro final e qualquer transição da qual você não tenha certeza, e olhe para eles.
Verificar a demonstração, não o script
Uma saída limpa indica que o script foi executado, não que a funcionalidade funcionou. Confirme ambos:
- Visual - a alteração está na tela nos quadros, no estado que a solicitação pediu.
- Funcional - o estado persistido realmente mudou, lido do banco de dados ou da API em vez de inferido da interface.
Quando a alegação é sobre layout — dois painéis lado a lado, um painel encaixado em uma borda — afirme a partir das caixas delimitadoras. Elementos existirem não diz nada sobre onde eles estão.
Mantenha o estado final por cerca de três segundos para que o espectador pouse nele, então verifique o codec, dimensões e duração do arquivo de saída com ffprobe antes de entregá-lo.
Manter as evidências
Mantenha logs de falha, tentativas parciais e capturas de tela até que uma tentativa tenha sido bem-sucedida. Exclua estado descartável apenas depois de ter algo que você enviaria. Um intermediário descartado é frequentemente o único registro de por que a tentativa deu errado.
Não perturbar a máquina na qual você está gravando
Uma gravação local é executada no computador real de uma pessoa enquanto ela o está usando.
- Dê ao aplicativo seu próprio perfil descartável e nunca toque no perfil real do operador.
- Prepare o que a demonstração precisar antes da primeira inicialização, ou telas de primeira execução aparecerão na frente deles.
- Possua todo processo que você iniciar e pare quando terminar — especialmente capturas, que continuam rodando após o script retornar.
- Inicie processos de longa duração como tarefas em segundo plano para as quais você mantém um manipulador, não com um
&no final dentro de um wrapper em primeiro plano: quando o wrapper sair, ele leva o servidor junto. - Pare um processo da maneira que ele espera ser parado. Um servidor de desenvolvimento morto com SIGKILL pulou seu trap de limpeza e deixou um arquivo de ambiente reescrito e um arquivo de porta obsoleto. Sinalize o processo que você iniciou e deixe-o limpar. Nunca mate por padrão (
pkill -f next): em uma máquina compartilhada, isso derruba os servidores de outras pessoas também. - Verifique com qual backend a aplicação sob demonstração se comunica. Um iniciador de desenvolvimento padrão usava uma API de produção a menos que instruído ao contrário, então os cliques de uma demonstração teriam escrito dados reais. Aponte para um backend local ou de desenvolvimento antes da primeira tentativa.
- Verifique previamente qualquer coisa externa da qual a demonstração dependa — um CLI que deve estar logado, um serviço que deve estar ativo — antes de capturar a tela ou iniciar a captura, para que uma dependência ausente falhe em um segundo em vez de no meio da tentativa. Nunca execute uma ação com efeito colateral, como enviar uma mensagem, apenas para provar que uma ferramenta foi iniciada.
- Se uma tentativa precisar da tela do usuário, do gerenciador de janelas ou da entrada, diga e pergunte, em vez de tomar.
Colocar o arquivo em um PR
gh faz upload do vídeo por si só, desde a v2.99.0:
gh pr comment <número> --body-file ./note.md --attach ./demo.mp4
--attach também funciona em gh pr create, gh pr edit e nos equivalentes gh issue. É repetível, até 50 arquivos por comando, e faz upload para o CDN user-attachments para que o GitHub renderize o vídeo inline.
Quatro coisas que vale a pena saber:
- Texto alternativo é apenas para imagens.
'./shot.png#O estado de erro'define texto alternativo em uma imagem; a mesma sintaxe em um vídeo é recusada com "não é possível definir texto alternativo em vídeo". Anexe vídeos com um caminho simples. - Um corpo que já referencia o caminho local é reescrito. Escreva
onde você quiser eghtroca pela URL de upload; caso contrário, o anexo é adicionado ao final. gh pr edit --attachsem a flag de corpo mantém o corpo existente e anexa a ele, para que uma demonstração possa ser adicionada à descrição de um PR posteriormente.- Verifique a versão antes de confiar nela. Em
ghanterior a 2.99.0 não há--attach, e o CDN não é alcançável de outra forma através da API — então recorra a fornecer à pessoa o caminho do arquivo para arrastar para o PR ela mesma.