O que B Narrado faz?
Mais gatilhos
apresentação em vídeo do PR, fazer uma gravação demo, narração demo, gravar ambas as stacks, vídeo explicativo, sem filtro drawtext, Playwright recordVideo, shell headless ausente
Um mp4 por conjunto de afirmações: cartão de título, clipe A, clipe B, cartão de evidência, cartão de veredito, cada um narrado.
Construído para macOS em Apple Silicon (say, cache do Playwright em ~/Library/Caches/ms-playwright, chrome-mac-arm64). Em outros sistemas, defina CHROMIUM_EXE e use --eleven para a voz. Precisa de Bun, ffmpeg e Python 3.
Faça isso
S=${SKILL_DIR:-~/.claude/skills/narrated-ab-video}
$S/preflight.sh /tmp/vid # chromium, playwright ffmpeg, ffmpeg, say voice
bun $S/record.ts a.json raw/a-run # um cenário por lado (copie examples/scenario.json)
bun $S/record.ts b.json raw/b-run
bun $S/cards.ts cards.json cards # PNGs de título/evidência/veredito + banner-A/B.png
python3 $S/build.py plan.json # [--voice Samantha] [--rate 182]
abra -a "QuickTime Player" demo.mp4 # abre pausado; nunca o reproduza você mesmo
Exemplos em examples/: scenario.json (passos: wait, select, click, clickIfPresent, type, send, waitStable, expand, fetchText, waitText, probeEnabled, reload; veja o cabeçalho de record.ts), cards.json, plan.json. Caminhos do plano são relativos ao arquivo do plano. Validado de ponta a ponta em um build de 4 segmentos, 40s a partir de dois clipes reais.
Por que foi construído assim (atritos minerados)
- O shell headless fixo do Playwright muitas vezes não está baixado.
record.tsecards.tslançam o build completochromium-*mais recente em cache (ou$CHROMIUM_EXE) em vez de falhar. - recordVideo precisa do próprio ffmpeg do Playwright. A falta impede a geração de webm. O preflight lê a revisão de
browsers.jsone executabunx playwright install ffmpeg. - O ffmpeg do Homebrew pode não ter
drawtext. Os banners são PNGs transparentes docards.ts, sobrepostos no build.py. Sem caça a fontes ou filtros. - As respostas do modelo levam de 10 a 60 segundos de silêncio.
sendmarca "enviado" ewaitStablemarca "respondeu". O build.py reproduz esse intervalo emspeed(padrão 10x) e o resto em 1x. - A narração geralmente é mais longa que o clipe. O build.py segura o último quadro (
tpad stop_mode=clone) até a voz terminar, então uma resposta permanece na tela enquanto é explicada. - Entrada dinâmica (códigos OTP, ids de uma rodada anterior): coloque
{{fn:NOME}}em um passotypee exporteNOME(page, state)dehooks.tsao lado do cenário.state.lastJsoncontém o último JSON POST que corresponde acaptureJsonFrom. - Seletores: botões são correspondidos por role e regex de nome (
"Ferramentas usadas","^Enviar$"). CSS é usado apenas para inputs e selects. Encontre nomes com uma captura de tela rápida antes de scriptar. - Concatenação precisa de codificações idênticas. Cada segmento é recodificado com o mesmo codec, taxa e layout de áudio, depois unido com
-c copy. - Voz melhor:
ELEVENLABS_API_KEY=... build.py plan.json --eleven <voice_id>(modelo eleven_multilingual_v2; clipes em cache por hash de voz+texto, então reexecuções não gastam caracteres). Mantenha a chave em um arquivo 0600, nunca no plano, e delete após o uso. - Demo de um lado (sem A/B): grave um cenário, dê a
cards.jsonum banner, e corte o mesmo clipe em vários segmentos do plano, uma afirmação cada, comspansacelerando as esperas (ex.: 5x). Mesmo build, sem lado A. - O usuário pode colar apenas
<voice_id> <key>. Isso significa reconstruir com--eleven <voice_id>. Uma voz mais lenta estica o vídeo (72s comsayviraram 92s), já que o build.py segura o último quadro até a voz terminar. - Restaurar uma demo desmontada antes de filmar: autenticação de curta duração (JWTs locais, URLs de túnel, recursos cloud temporários) geralmente expira no dia seguinte. Re-verifique com uma execução de API antes de gravar; um 401 "JWT token expirado" teria filmado uma rodada cujos resultados nunca chegam.
- Clipe raw perdido: corte a filmagem desse lado de um mp4 de saída anterior (encontre seu span amostrando a cor do canto do banner), salve como
<dir>/a.webmcom-f mp4e um marks.json vazio, e use um span explícito. Remova obannerpois já está embutido. - Áudio:
say -oescreve arquivos apenas. Nunca reproduza o vídeo ou qualquer áudio sem a autorização explícita do usuário. Abra pausado e entregue. - Prove antes de filmar. Execute o A/B e verifique o resultado (API ou log) primeiro. O vídeo mostra um resultado comprovado; não é o teste.
- Cartões devem corresponder ao tamanho do clipe. O build.py não escala. Gravar com
"viewport": [1440, 900]requer"size": [1440, 900]no cards.json, ou a concatenação terá tamanhos de quadro mistos. - UIs assíncronas precisam de marcas, não esperas fixas.
waitTextmarca quando um regex aparece (outimeout:<mark>),probeEnabledcomwaitMsconsulta um botão e registraprobes[]no marks.json,tryMsem type/send/click marcaskipped:<step>em vez de abortar, então um lado "permanece desabilitado" ainda finaliza o clipe. - Consulte o mesmo elemento que você clica. Uma consulta CSS (
button[aria-label=...]) encontrou um botão diferente do role-namesende leu desabilitado enquanto o send passava; use"role"emprobeEnabled. - Overlays de modo dev (consulta devtools, toasts de erro) aparecem no clipe. Adicione
{"clickIfPresent": "^Fechar .* devtools$"}após a primeira espera. - Esperando uma resposta que nunca "estabiliza": um badge de tempo decorrido ao vivo muda o texto do corpo a cada segundo. Verifique
marks.jsonpor uma marcarepliedantes de construir. - Verifique se a prova está em texto visível. Cartões de ferramenta recolhidos podem não expandir (
expandsilenciosamente não clica em nada). Leia obodydo marks.json para a string de afirmação. Se estiver faltando, mude o prompt ou prove em um cartão. - Prove a paridade antes de filmar uma afirmação de "base falha". Uma vez uma base local falhou por um motivo (uma flag que estava ativa localmente, desligada remotamente) que o ambiente real nunca encontra, e a narração afirmou. Corresponda as flags remotas primeiro, então filme.
- Cartão de título: commits testados e flags de cada lado. Uma afirmação por segmento de clipe. Termine com um cartão de veredito.
Relacionados
narrated-screenshot: um único still anotado em vez de um vídeo.pr-ab-evidence: o método A/B vermelho/verde cujo resultado este vídeo filma.