Vídeo teaser
Produza um teaser de qualidade de lançamento (~30-45s) de um aplicativo em execução: crie um storyboard, filme-o automatizando a interface real, edite com ffmpeg e entregue um MP4 mais um GIF para o README.
O resultado deve parecer um vídeo de produto, não uma gravação de tela. A diferença é direção — encenação, enquadramento e ritmo —, não resolução.
As implementações de referência estão em reference/; são módulos ESM funcionais, não pseudocódigo. Configure em um diretório temporário — nunca dentro do projeto:
cp -r <skill>/reference/* "$SCRATCH/" && cd "$SCRATCH" && npm install
export TEASER_BASE_URL="https://the-app.example.com"
reference/package.json declara "type": "module" e as três dependências. Todo script lê TEASER_BASE_URL, então nada é hardcoded para um único app.
Antes de tudo: as duas regras rígidas
1. Nunca acione efeitos colaterais no mundo real sem consentimento explícito e itemizado.
Filmar um app real significa clicar em botões reais. Alguns deles enviam e-mail, postam publicamente, cobram dinheiro ou enviam formulários para terceiros. Antes de tocar no app:
- Enumere cada ação no seu storyboard que saia da máquina.
- Diga ao usuário exatamente o que cada uma faz e quantas vezes, e obtenha concordância sobre a contagem.
- Prefira um modo que pare antes da etapa irreversível (uma prévia, uma execução de teste, uma confirmação que você pode filmar e depois recusar).
Não existe sonda somente leitura contra um sistema ativo. Um clique "diagnóstico" que cai em uma sessão já em execução dispara de verdade. Se você estiver depurando por que uma ação não funcionou, assuma que seu próximo clique funcionará, e esteja preparado.
Se algo disparar que você não pretendia: interrompa o processo na origem imediatamente (mate a sessão/worker, não apenas o botão da interface, que pode não ter efeito), verifique o estado interrompido lendo-o de volta e informe o usuário claramente na sua mensagem final — contagem incluída.
2. Assuma que cada quadro é público e cheio de dados pessoais.
Contas reais carregam nomes, e-mails, endereços e documentos. Decida a política com o usuário de antemão:
- Enquadre ao redor (padrão) — componha tomadas que excluam identidade. Corte a interface persistente (barras laterais, avatares, menus de conta) na etapa do ffmpeg.
- Oculte antes de gravar —
page.evaluatecomvisibility: hiddennos cartões problemáticos antes da câmera gravar. Nunca filme esperando cortar depois. - Use uma conta demo pré-configurada — a mais limpa quando existe.
Revise cada quadro do corte final em resolução total antes de entregar. Não o contact sheet — os quadros.
Fluxo de trabalho
1. Explore e crie o storyboard
Tire screenshots autenticados de cada tela candidata primeiro (reference/scout.js). Olhe para eles. Em seguida, escreva uma tabela de storyboard: cena, tomada, o que o espectador deve sentir e duração. Uma tomada sem função atribuída é cortada antes de ser filmada.
Arco que funciona: tensão (o problema) → revelação (o produto) → prova (ele realmente faz a coisa) → escala (os resultados) → confiança (onde roda) → fechamento.
Anote no storyboard quais telas contêm dados pessoais e quais são seguras.
2. Prepare o cenário
Curadoria antes de gravar, nunca depois:
- Escolha visualizações onde os dados pareçam melhores — gráficos completos, listas ativas, nomes reconhecíveis, contagens diferentes de zero. Nunca filme um spinner, um estado vazio ou um gráfico meio renderizado.
- Defina o estado da interface deliberadamente (larguras de painéis, recolhido/expandido, filtros, posição de rolagem) via
localStorageem um script de inicialização ou umpage.evaluatepré-gravação. - Dispense toasts, banners e barras de cookies fora da câmera.
- Deixe os dados estabilizarem:
networkidlemais alguns segundos.
3. Filme
Use CDP screencast (Page.startScreencast), não gravação de tela. Ele captura a página em segundo plano a ~100fps, então nada que o usuário está fazendo aparece no quadro e a máquina permanece utilizável. Playwright dirige; CDP filma. reference/rig.js implementa isso.
- Um assunto por tomada. Enquadre a coisa, não "o app inteiro".
- Movimentos de câmera vêm de rolagem suave com easing dentro da página (
cameraScroll), nunca de um filtro. Veja o aviso sobre zoompan abaixo. - O cursor é um ator: use o cursor SVG injetado (
cursorClick) que desliza com easing e mergulha ao pressionar, ou oculte-o. Nenhum desvio ocioso. - Ensaie cada tomada, extraia quadros, olhe para eles, ajuste, depois filme de verdade.
Filmar uma janela externa (um navegador que o próprio app abre, um app desktop) precisa de captura do SO — gdigrab/x11grab/avfoundation (recordDesktop no rig). Isso captura tudo na tela, incluindo o trabalho do próprio usuário. Avise o usuário, peça para ele se afastar e revise o resultado quadro a quadro; delete se pegar algo particular.
4. Cartões de título
HTML/CSS animados filmados no navegador, não imagens estáticas. Injete a marcação do cartão em uma página em branco na própria origem do app para que suas fontes web e paleta sejam resolvidas, depois faça o screencast. Extraia a fonte de exibição real da página ativa (getComputedStyle) e fixe uma pilha monoespaçada conhecida, em vez de adivinhar.
Combine com a linguagem de movimento do app (suas próprias curvas de easing e durações). Carregue a skill frontend-design antes de projetá-los se o projeto não tiver um estilo de cartão estabelecido.
5. Edite
reference/build.js normaliza cada segmento para um tamanho/fps comum, depois faz crossfade da sequência. Mantenha cortes a cada ~2.5-4s. Dê espaço ao momento de recompensa em velocidade normal enquanto comprime o rotineiro ao redor.
6. Revise, depois entregue
- Gere um contact sheet e quadros em resolução total por segundo.
- Leia os quadros em busca de dados pessoais, painéis cortados e texto ilegível.
- Verifique duração e dimensões com uma sonda.
- Entregue um MP4 mais, para READMEs, um GIF otimizado com paleta (GitHub não reproduzirá um MP4 commitado inline). Mantenha o GIF abaixo de ~10 MB.
- Deixe sem áudio a menos que solicitado; você não pode licenciar música. Diga isso.
Especificações conquistadas com esforço
Nunca use zoompan para aproximações. Ele recalcula o zoom por quadro e arredonda a janela de corte para pixels inteiros, então a imagem balança para frente e para trás — parece um terremoto. Use tomadas fixas mais rolagem real dentro da página. Se precisar de uma aproximação, pré-redimensione a fonte 4x antes e verifique com uma medição de diferença entre quadros (reference/jitter.js): uma tomada estática fixa deve medir bem abaixo de 1.0 de delta médio; tremor visível mede 3+.
O screencast para de emitir quadros quando a animação estabiliza. Um cartão cuja animação termina após 1.2s produz um clipe de 1.2s. Preencha com tpad=stop_mode=clone:stop_duration=N e corte para o comprimento desejado com -t.
Monte quadros com timestamps, não a uma taxa fixa. Os quadros do screencast chegam com metadata.timestamp; escreva uma lista de concatenação do ffmpeg com durações reais por quadro, depois reamostre para 60fps constantes. Assumir um intervalo fixo produz trepidação.
ffmpeg-static como dependência de desenvolvimento, resolvida pelo caminho do módulo. Nunca dependa do ffmpeg estar no PATH. (ffprobe não está nesse pacote — analise a saída de erro padrão de ffmpeg -i.)
Captura autenticada: faça login uma vez com interface visível, salve storageState, reutilize em todas as tomadas (reference/login.js). Sessões expiram — termine a filmagem no mesmo dia ou execute novamente. Também semeie quaisquer preferências de interface do localStorage lá.
Localhost de uma origem implantada é bloqueado pela política de acesso à rede local do Chrome. Se a página precisar acessar um serviço local, inicie com --disable-features=LocalNetworkAccessChecks,PrivateNetworkAccessChecks,BlockInsecurePrivateNetworkRequests.
Corte a interface persistente com um deslocamento fixo. Filme com largura de viewport 1920 + railWidth, depois crop=1920:1080:railWidth:0 para remover a barra lateral e cair exatamente em 1080p.
Entregas
Relate o caminho, duração e dimensões; declare claramente o que ainda é necessário do usuário (música, upload de vídeo nativo do GitHub); e divulgue qualquer coisa que tenha acontecido durante a filmagem que eles gostariam de saber.