piyush140104/screen-record-skills

Skill Claude Code: vídeos roteirizados de demonstração de navegador com narração ElevenLabs, música, efeitos sonoros de clique e legendas integradas.

O que é screen-record-skills?

Esta skill capacita o Claude Code a produzir vídeos polidos e roteirizados de navegação em sites, ideais para LinkedIn, Twitter, apresentações de vendas e documentação de onboarding. O usuário descreve o que deve aparecer na tela, os movimentos do cursor e o texto da narração; a skill gera automaticamente um vídeo 1920×1080 com animação do cursor, narração via ElevenLabs, música ambiente, efeitos sonoros de clique e legendas no formato ASS. O fluxo de trabalho envolve a criação de um arquivo de cena em JavaScript que utiliza a engine `engine.mjs`, a qual coordena a geração de áudio, a gravação headless do Chromium e a mixagem final. É necessário configurar uma chave de API da ElevenLabs (conta gratuita oferece 10.000 caracteres/mês), e a skill fornece orientações claras para lidar com erros de autenticação ou cota. Plataformas suportadas: macOS (reprodução com afplay), output em MP4 e WebM, compatível com LinkedIn e outras redes.

Funciona com✓Claude Code~Codex CLI✓Cursor
npx skills add piyush140104/screen-record-skills

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

/screen-record — Vídeos roteirizados de demonstração de navegador

Quando usar

O usuário deseja um vídeo polido de um site realizando alguma ação — normalmente para LinkedIn, Twitter, uma apresentação de vendas, uma atualização para investidores ou documentação de onboarding. Eles descrevem o que deve aparecer na tela, o que o cursor faz e, aproximadamente, o que a narração deve dizer. Você cria o roteiro; o mecanismo cuida da animação do cursor, TTS via ElevenLabs, música, efeitos sonoros de clique e legendas embutidas.

Não use esta skill para: gravações de tela reais de uma sessão já em andamento (use Captura de Tela do macOS ou QuickTime), GIFs (use uma ferramenta de GIF) ou vídeos que precisam de uma narração humana real (você ainda pode criar o roteiro e depois eles regravam).

Como funciona

O mecanismo está em engine.mjs. Ele exporta runDemo(config) que:

  1. Gera um clipe TTS por dica com ElevenLabs.
  2. Gera uma faixa de música ambiente suave + um efeito sonoro de clique de UI com ffmpeg.
  3. Inicia o Chromium headless em 1920×1080, grava o vídeo.
  4. Executa sua função scenes(helpers) que controla o navegador.
  5. Mixa o áudio (narração alta + música baixa + cliques sutis) e queima legendas no estilo ASS.
  6. Retorna os caminhos para os arquivos finais .mp4, .webm, .srt, .ass.

Fluxo de trabalho

Passo 1 — leia a solicitação do usuário

Defina: URL a ser gravada, fluxo (o que o cursor deve fazer), tom (formal/casual), duração alvo. Se algo estiver faltando, faça uma pergunta focada em vez de adivinhar.

Passo 2 — verifique a chave da API

Procure por ELEVENLABS_API_KEY nesta ordem:

  1. $CLAUDE_PLUGIN_ROOT/.env.local (ou a pasta .env.local da própria skill)
  2. O .env.local do projeto atual
  3. process.env

Se estiver ausente, informe ao usuário:

Preciso de uma chave de API do ElevenLabs. Obtenha uma gratuita em https://elevenlabs.io/app/settings/api-keys (10.000 caracteres/mês, suficiente para ~15 demonstrações). Cole no chat e salvarei no .env.local da skill, ou adicione você mesmo.

Se a chave estiver presente, mas o mecanismo lançar ApiKeyDeadError (HTTP 401/402/403), informe ao usuário:

Sua chave do ElevenLabs foi rejeitada (revogada, expirada ou sem cota). Rotacione-a em https://elevenlabs.io/app/settings/api-keys e atualize o .env.local. Não tentarei novamente até que você faça isso.

NÃO tente novamente silenciosamente, NÃO recorra ao comando say do macOS a menos que o usuário peça explicitamente.

Passo 3 — escolha uma voz

O padrão é Liam (TX3LPaxmHKxFdv7VOQHJ) — masculino americano enérgico, moderno. Mais leve que George (britânico) e Sarah (feminina americana). Outras vozes do plano gratuito estão em engine.mjs sob FREE_TIER_VOICES. Se o usuário disser "use a voz X", encontre-a no catálogo. Se disser "grave/profundo/leve/quente/feminino", escolha de acordo.

Vozes da biblioteca (Charlotte, Rachel, Adam, etc.) exigem uma assinatura paga do ElevenLabs. Se o usuário pedir uma e estiver no plano gratuito, você receberá HTTP 402 — recorra à voz gratuita mais próxima e avise o usuário.

Passo 4 — analise a página alvo (apenas se necessário)

Se você não conhece a estrutura da página, use Playwright ou curl para inspecionar o DOM e encontrar seletores. Não adivinhe — seletores importam, correspondências ambíguas farão a gravação expirar.

Para um SPA com conteúdo dinâmico, prefira aria-label, role ou seletores de texto em vez de nomes de classe. Use a semântica page.locator(s).first() (os helpers do mecanismo já fazem isso).

Passo 5 — escreva um arquivo de cena

Crie um arquivo em /tmp/screen-record-<nome>.mjs (não polua o repositório do usuário) que importe o mecanismo e chame runDemo. Modelo:

import { runDemo } from '/Users/<você>/Desktop/Projects/skill/screen-record-skills/engine.mjs';
// ou, se instalado via symlink:
// import { runDemo } from '/Users/<você>/.claude/skills/screen-record/engine.mjs';

await runDemo({
  baseUrl: 'http://localhost:3000',
  outputDir: './output/onboarding-demo',
  outputName: 'onboarding',

  splash: {
    label: 'Visite-nos em',
    url:   'www.yourapp.com',
    footer: 'YourApp — fluxo de onboarding',
  },

  cues: [
    { id: 'intro',   text: 'Bem-vindo ao YourApp. Deixe-me mostrar a você.' },
    { id: 'signup',  text: 'Toque em Cadastre-se para criar uma conta.' },
    { id: 'form',    text: 'Digite seu e-mail e uma senha.' },
    { id: 'done',    text: 'E é isso — você está dentro.' },
  ],

  // Opcional: simular backend para que a demonstração seja determinística.
  routes: [
    { match: /\/api\/signup$/, fulfill: { status: 200, body: { ok: true } } },
  ],

  // Opcional: pré-carregar um usuário autenticado para pular o login.
  // initialAuth: { id: 'u1', email: '[email protected]', name: 'Usuário Demo' },

  scenes: async ({ page, baseUrl, sleep, speak, awaitCue,
                   clickAt, typeInto, moveCursorTo, hideSplash, typeSplashUrl,
                   configSwitch, showSwitch, hideSwitch, setAuth }) => {

    // Cena 0: tela de splash (o mecanismo já navegou para baseUrl fora da câmera).
    speak('intro');
    await typeSplashUrl('www.yourapp.com');
    await awaitCue('intro');
    await hideSplash();
    await sleep(750); // corresponde ao fade do splash

    // Cena 1: clicar em cadastre-se
    speak('signup');
    await clickAt('button:has-text("Cadastre-se")');
    await awaitCue('signup');

    // Cena 2: preencher o formulário
    speak('form');
    await typeInto('input[type="email"]', '[email protected]');
    await typeInto('input[type="password"]', 'CorrectHorseBattery');
    await awaitCue('form');

    // Cena 3: enviar
    speak('done');
    await clickAt('button[type="submit"]');
    await sleep(1000);
    await awaitCue('done');
  },
});

Passo 6 — execute

cd /Users/<você>/Desktop/Projects/skill/screen-record-skills
# Apenas na primeira vez:
npm install --silent
# Todas as vezes:
node /tmp/screen-record-<nome>.mjs

Cada execução leva aproximadamente o tempo do vídeo final mais ~10s de overhead.

Passo 7 — reporte

Informe ao usuário:

  • Caminho para o .mp4 final (pronto para LinkedIn, 1920×1080, H.264 + AAC)
  • Caminho para o .srt (o LinkedIn importará automaticamente como legendas ocultas)
  • Ofereça-se para reproduzir com afplay <caminho> no macOS

Referência de helpers (o que suas cenas podem chamar)

HelperO que faz
pagePágina Playwright bruta, se necessário
baseUrlA URL base configurada
sleep(ms)await sleep(800)
moveCursorTo(x, y, durationMs?)Movimento suave para coordenadas
moveToSelector(selector, durationMs?, offset?)Movimento suave para o centro do elemento
clickAt(selector, durationMs?)Mover + pulsar + clicar (registra o tempo do clique para SFX)
typeInto(selector, text, perChar?)Clicar + limpar + digitar caractere por caractere
recordClick()Registrar manualmente um timestamp de clique (para SFX)
speak(cueId)Marcar início da dica. O fim é start + audioDuration + 0.35s
awaitCue(cueId)Dormir até que a narração da dica termine
typeSplashUrl(text, perChar?)Digitação animada na barra de URL do splash
hideSplash()Esmaecer o splash (sempre dormir ~750ms depois)
configSwitch({ fromInitial, fromLabel, toInitial, toLabel, title, sub })Definir o conteúdo do cartão de troca de conta
showSwitch() / hideSwitch()Alternar a sobreposição de troca de conta
setAuth(user)Definir localStorage[authStorageKey] para um novo usuário (usado com showSwitch para demonstrações de troca de conta)

Regras básicas de ritmo

  • Uma frase por dica. Mantenha abaixo de ~12 palavras.
  • Para ações de UI, speak(cue) ANTES da ação para que a narração toque enquanto o cursor se move.
  • Para cenas com muita digitação, a digitação leva mais tempo que a narração — use sleep em vez de awaitCue para controlar o ritmo.
  • A duração total do vídeo é geralmente sum(audioDurations) + sum(sleeps). Aponte para 30–75s no LinkedIn.

Seletores comuns que quebram

  • text=Foo sozinho pode corresponder a muitos elementos. Use page.locator(...).first() que é o que o mecanismo já faz, OU use button:has-text("Foo") para limitar a uma tag.
  • Nomes de classe do Tailwind são frágeis. Prefira aria-label, role, tag semântica + texto.
  • Modais/diálogos: aguarde por [role="dialog"] ou pelo texto do título do modal antes de clicar dentro.

O que NÃO fazer

  • Não escreva texto de narração real no arquivo de cena — mantenha a narração em cues[].text para que legendas e áudio permaneçam sincronizados.
  • Não queime o cursor no CSS da página — o mecanismo o injeta.
  • Não use await page.screenshot() no meio da cena — você capturará o cursor em posições estranhas; use extractFrames posteriormente, se necessário.
  • Não faça commit do .env.local (ele está em .gitignore).

Fim das instruções da skill.

Habilidades Relacionadas