Communitygithub.com

videolabs: criar um vídeo (estilo curso de terminal)

Crie um curso técnico em vídeo narrado de aproximadamente 30 minutos usando Remotion + ElevenLabs no estilo de terminal Omarchy/Tokyo Night (Waybar, janela lado a lado, prompt oh-my-zsh, cabeçalhos markdown), com cada elemento na tela revelado exatamente quando o narrador o menciona, pausas entre frases, legendas simples, renderização remota rápida e um player web com capítulos. Para tópicos práticos, primeiro constrói um laboratório real (máquinas virtuais qemu/KVM) e usa a saída real de comandos do laboratório na tela e na narração.

O que é videolabs: criar um vídeo (estilo curso de terminal)?

O skill videolabs permite que um agente de IA crie cursos técnicos em vídeo de alta qualidade, narrados e com estilo de terminal, usando Remotion e ElevenLabs. Ele é particularmente útil para desenvolvedores que desejam criar vídeos explicativos, tutoriais, cursos ou laboratórios práticos sobre tópicos técnicos, com todos os elementos visuais sincronizados com a narração. O skill suporta a construção de laboratórios reais (qemu/KVM) para tópicos práticos e usa a saída real de comandos desses laboratórios tanto na tela quanto na narração, garantindo precisão. Todo o fluxo de trabalho, desde a criação do script até a renderização e publicação, é gerenciado por comandos CLI no repositório `/opt/opus/videolabs`. Ele se integra com o skill irmão `videolabs_publish` para publicar o site final. O usuário pode editar, regravar, rerrenderizar ou republicar vídeos já criados.

Funciona com✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/bigzaqui/videolabs/tree/HEAD/skills/videolabs_create-video

Perguntar na sua IA favorita

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

Documentação

O que videolabs: criar um vídeo (estilo curso de terminal) faz?

Tudo reside em um único repositório, /opt/opus/videolabs (github.com/bigzaqui/videolabs, público: nunca commitar credenciais; execute scripts/check-secrets.sh antes de commitar). A fonte deste skill está em skills/videolabs_create-video/ nesse repositório, vinculada a ~/.claude/skills por scripts/setup.sh. Suas configurações (chaves ElevenLabs e Cloudflare, o host de renderização) estão no .env na raiz do repositório (ignorado pelo git), veja .env.example.

O repositório contém: um motor genérico (ferramentas Remotion + ElevenLabs, um npm ci) e uma pasta por laboratório em labs/. Usado para "kafka - em poucas palavras" (26 aulas / 18 min), "ceph - primeiros passos" (14 aulas / 11.6 min) e, anteriormente, "ceph em poucas palavras" (41 aulas / 30 min; seu script e visuais estão em reference/ como exemplo de cartões, comparação, medidor, árvore, incidente, estados e sites). Ambos os laboratórios atuais são práticos: todos os comandos foram executados primeiro em um laboratório real (veja "Laboratório real").

/opt/opus/videolabs/
  engine/                       ferramentas genéricas: engine/cli.mjs <laboratorio> <comando>, src/ (Remotion), scripts/
  labs/<slug>/
    lab.config.json             entrada de catálogo (título, descrição, tags) + aparência (marca, logotipo, barra de status, nomes de ferramentas, corte de amostra)
    script/script.md            narração, uma cena por cabeçalho ###
    visuals.ts                  o que cada cena mostra + substituições de dica
    lab/                        create-lab.sh, destroy-lab.sh, cap.sh, captures/, lab-meta.json
    audio/raw/                  saída ElevenLabs (paga; commitada no git)
    out/ data/ public/voiceover/  gerados, ignorados pelo git
  site/  scripts/publish-all.sh  state/    o site e sua publicação (skill videolabs_publish)

script.md ──cli cenas──▶ data/scenes.json
   └─ cli tts (timing de palavras ElevenLabs) ─▶ audio/raw ──pace──▶ public/voiceover/* + data/{durations,captions}.json
visuals.ts + engine/src/cues.ts (revelar = quando a palavra é dita) ─▶ Remotion ──cli render──▶ out/<slug>.mp4
cli player ─▶ out/player/{chapters.json,lab.json} ──videolabs_publish──▶ videolabs.pages.dev

Todos os comandos: node engine/cli.mjs <laboratorio> <cenas|tts|pace|dicas|stills|typecheck|studio|amostra|render|player>, mais list e new <slug> (README.md do repositório tem a tabela). A pasta do laboratório é a única coisa que difere entre cursos; nunca copie código do motor para dentro de um laboratório.

Fluxo de Trabalho (concorde o esboço e o script com o usuário; tudo depois disso é executado sem perguntar)

Autorização permanente do usuário: uma vez que o script esteja acordado, execute o tts pago do ElevenLabs, a auditoria de dicas, a renderização no host de renderização, o passo do player/pôster e o desmonte do laboratório sem pedir permissão em cada etapa. Relate os resultados e a nova duração depois. Só pare para perguntar quando algo estiver fora deste fluxo de trabalho (por exemplo, uma ação destrutiva em coisas que o laboratório não criou, ou publicação no site quando o usuário não pediu).

  1. Tópico prático? Construa e execute um laboratório real primeiro (veja "Laboratório real" abaixo). Nunca escreva a saída de comandos de memória: o primeiro rascunho do script ceph-primeiros-passos estava errado em dez lugares quando executado em um cluster real. Depois escreva o script a partir do que realmente aconteceu.
  2. Primeiro o script, depois o vídeo. Proponha um esboço (módulos → aulas, com o diagrama planejado por aula), obtenha concordância e então escreva labs/<slug>/script/script.md. Mudar texto é muito mais barato que regenerar áudio. Marque na velocidade 1.0 com pausas ≈ 160 palavras por minuto: 1.500 palavras ≈ 9.5 min incluindo cartões de módulo; a 1.08 ≈ 168 ppm. Verifique a duração real com a linha Paced … total X min logo após tts e ajuste antes de renderizar. Para comandos específicos de versão, verifique o release atual (documentação e os downloads/imagens do projeto) primeiro. Formato (analisado por engine/scripts/build-scenes.mjs):
    ## Módulo 1 — Arquitetura Principal
    ### S02 · RADOS
    **Visual:** notas para o designer
    **Comandos:** `ceph -s` `ceph osd tree`        (opcional, apenas na tela)
    **Narração:**
    Um parágrafo, escrito para ser falado. Soletre comandos como são falados ("ceph dash s").
    
    Termine a última aula de um módulo com "Resumo do módulo: …" — a palavra resumo dispara a janela de resumo.
  3. node engine/cli.mjs new <slug> cria a estrutura labs/<slug>/ (config, um script de três cenas, um visuals.ts); preencha lab.config.json (título, descrição, tags para o catálogo; brand, user, logo, statusbar, statusCmd, networkLabels, session, tools, sample para a aparência) e execute node engine/cli.mjs <slug> scenes.
  4. Visuais em labs/<slug>/visuals.ts (tipos em engine/src/types.ts, colors de @engine/theme), uma entrada por id de cena. Tipos de diagrama (engine/src/components/Diagrams.tsx):
    • topology: hosts (nome, ip, chips de daemon, discos/réplicas) em uma ou duas linhas de rede, uma linha de status opcional (rótulo statusCmd, padrão da config), e flows (blocos se movendo entre hosts, de cue até until). Qualquer host/daemon/disco/status pode ter um cue (aparece quando falado) e changes: [{cue, state, label}] (disco empty|osd|leader|idle|down|destroyed|new, host ok|spare|down|maint). Elementos sem cue são visíveis desde o início. Construa o estado do laboratório com helpers (host(n), built(n)) para que o diagrama cresça aula por aula.
    • session: um shell realista; cada cmd se digita quando falado, então suas linhas out aparecem; mantém as linhas mais recentes. host define o prompt completo de uma linha (padrão session.prompt da config). Uma topology compacta opcional acima dela. A barra de comandos na parte inferior fica oculta para cenas de sessão. Outros tipos: title (cartão fastfetch; user, rows extras), layers, cards, flow, tree, compare, gauge, terminal (saída de comando com anotações), incident (sintoma/verificação/ação), checklist, states, sites; opcionais takeaway e commandCues por cena. Use saída real de lab/captures/ para cada out e symptom.
  5. Revise os visuais antes de pagar pelo áudio: node engine/cli.mjs <slug> stills (um quadro por cena a 60%; S04,S11 --at=12.5 para um momento) e monte em folhas de contato 2×2 com ffmpeg xstack para examiná-los. Verifique estouro, quebra de linha, layouts vazios.
  6. Voz: .env na raiz do repositório com ELEVENLABS_API_KEY / ELEVENLABS_VOICE_ID, depois node engine/cli.mjs <slug> tts (execute diretamente, sem necessidade de aprovação; pula existentes; --only=S03,S04 --force para refazer apenas as cenas cuja narração mudou, o que também salva créditos). Ele executa pace automaticamente. Informe ao usuário a nova duração quando o script crescer. Commit labs/<slug>/audio/ (saída paga).
  7. Auditoria de sincronia: node engine/cli.mjs <slug> cues (após qualquer alteração em um comando, altere também sua entrada commandCues: um chip para dmesg ainda com dica em "smartctl" é uma incompatibilidade silenciosa) — lista a palavra que revela cada elemento e cada linha de comando (MISS = espalhado entre vizinhos). Corrija correspondências erradas com substituições de dica (abaixo). Reexecute após qualquer alteração na narração ou na voz.
  8. Pré-visualização: node engine/cli.mjs <slug> sample (≈1 min no servidor de renderização), verifique quadros com ffmpeg -ss <t> -frames:v 1, volumedetect para níveis (sem corte: máx < -1 dB).
  9. Renderize o curso completo (remoto, abaixo), depois node engine/cli.mjs <slug> player, faça o pôster labs/<slug>/out/spot.jpg, destrua as VMs do laboratório e publique todo o site com o skill videolabs_publish.

Regras de design aprovadas pelo usuário

  • Aparência: Área de trabalho Omarchy/Hyprland, paleta Tokyo Night (src/theme.ts; nomes semânticos como rados, mon, cephfs são apenas slots da paleta). Barra Waybar com módulos como áreas de trabalho 0–7, um status (HEALTH_WARN no módulo de solução de problemas), contador de aula 07/41. Uma janela lado a lado, borda quadrada de 2px, sem raio/brilho/gradiente. Cada aula abre com um prompt digitado robbyrussell ➜ modulo-1-arquitetura-principal git:(s03) cat os-daemons.md, depois um # Cabeçalho. Notas renderizadas como // comentários, comandos como linhas ❯ cmd, resumos como janela flutuante cat resumo-sre.md, divisores de módulo como cd modulo-N-… + título grande, abertura como fastfetch. Tudo JetBrains Mono; Inter apenas para legendas. Isso substituiu uma aparência "genérica" de gradiente escuro que o usuário não gostava.
  • Sincronia de revelação: nunca espaçar por tempo. Cada elemento aparece quando o narrador diz seu nome pela primeira vez (engine/src/cues.ts: token significativo mais longo, com stemização de prefixo, pesquisado para frente a partir da dica anterior). Substituições no visuals.ts do laboratório:
    • cue: "=gerentes" palavra falada exata (hífens/pontuação ignorados: "=write-ahead"), cue: null = nenhuma palavra, interpolar.
    • pointCues (lados de comparação), noteCue (árvore), linkCue (sites), cues (emblemas de título), commandCues (linhas de comando, por cena).
    • A ordem dos rótulos em cueLabels() deve coincidir com a ordem de índices que o renderizador usa em engine/src/components/Visuals.tsx (topology/session usam traversal por chave em topologyKeys/sessionKeys).
    • Um cursor para frente percorre todos os rótulos de uma cena, então um rótulo posterior reutilizando uma palavra comum ("três", "recuperação", "adicionar") pode cair em uma ocorrência posterior. Prefira uma palavra que ocorra uma vez perto do momento ("=repetir", "=começa"), e sempre leia a auditoria de cues.
  • Legendas: frases simples, quebradas no final de frases/períodos, uma linha ≤ 64 caracteres, sem destaque karaoke palavra por palavra ("cansativo").
  • Respiração: engine/scripts/pace.mjs insere 250 ms após . ? ! e 120 ms após : ; no áudio bruto do ElevenLabs e desloca os timings das palavras. Os pontos de corte vêm do ffmpeg silencedetect (estrito -38 dB/40 ms, depois -30 dB/20 ms), ou então a janela mais silenciosa de 5 ms, com fades de 8 ms — nunca apenas dos limites das palavras do ElevenLabs (que caem dentro das palavras). Ajuste SENTENCE_PAUSE/CLAUSE_PAUSE, reexecute node engine/cli.mjs <slug> pace (grátis; áudio bruto é mantido em audio/raw/). O ritmo depende da versão do ffmpeg (7.1.5 e 8.0.1 deram 17.9 e 17.8 min para o mesmo áudio Kafka): faça o ritmo onde renderiza, ou copie data/ e public/voiceover/ para o host de renderização.
  • Transições: crossfades de 15 quadros via @remotion/transitions TransitionSeries; elas sobrepõem apenas o lead-in silencioso (0.4 s) / tail (0.8 s). engine/src/timeline.ts subtrai sobreposições; engine/scripts/player.mjs e stills.mjs espelham essas constantes — mantenha-as em sincronia.
  • Voz escolhida pelo usuário: ElevenLabs "Mark" v3p1kjzUvro6S76qmYmH (Biblioteca de Vozes; funciona para TTS embora GET /v1/voices/{id} retorne 404), eleven_multilingual_v2, velocidade 1.08, endpoint with-timestamps, previous_text/next_text para continuidade. Sempre verifique um id de voz com uma chamada TTS de 1 frase antes de uma execução completa (um id anterior em .env estava truncado).

Configurações por curso (labs//lab.config.json)

Os workspaces na barra Waybar e as contagens de módulo/aula no fastfetch seguem as cenas automaticamente. Todo o resto específico do curso são dados na config, nunca código: brand (nome Waybar), user (prompt no cartão de título), logo (cinco linhas de letras em bloco), statusbar (texto ok/warn, texto right, warnModule = o módulo que mostra o aviso), statusCmd e networkLabels (padrões de cenas de topologia), session.prompt/session.title (sessões de terminal), tools (palavras de comando ignoradas ao dar dica automaticamente a uma linha de comando), sample (ids de cena do corte de Amostra), mais title, description, tags para o catálogo. Um novo laboratório com aparência diferente não precisa de alteração no motor; um novo tipo de diagrama ou estado precisa (engine/src/types.ts, componentes, cues.ts) e então beneficia todos os laboratórios.

Práticas do Remotion aplicadas (dos skills remotion-*)

Fontes via @remotion/google-fonts (nunca confie em fontes do sistema); <Audio> de @remotion/media com from; TransitionSeries; calculateMetadata dimensiona a composição a partir das durações de áudio; anime com interpolate/Easing.bezier e translate (sem transições CSS). Não adotado propositalmente: Interactive.create/composições conectadas (útil apenas para edição manual no Studio), mínimos grandes de texto para vídeo social, efeitos sonoros de meme.

Renderização

  • VIDEOLABS_RENDER_HOST (alvo ssh do servidor de renderização e laboratório, chaves já configuradas) vem do .env na raiz do repositório: execute set -a; . /opt/opus/videolabs/.env; set +a antes dos comandos abaixo, e escreva essa variável, não um endereço literal, em qualquer coisa que commitar. O mesmo host executa as VMs do laboratório.
  • TMPDIR=/var/tmp é definido pelo CLI: /tmp é um tmpfs RAM pequeno nesses hosts e uma mixagem de áudio longa falha com "No space left on device" bem no final.
  • Máquina local (4 vCPU) ≈ 45 min por 30 min de vídeo. Servidor de renderização remoto $VIDEOLABS_RENDER_HOST (Ubuntu 26.04, 24 threads, 31 GB RAM, RTX 3090 Ti, KVM; Node 22, ffmpeg, rsync e as bibliotecas Chromium do apt) renderiza o curso ceph de 11.6 min em 3 min e o curso kafka de 18 min em 5 min com concorrência 12–16. O repositório reside em /opt/opus/videolabs em ambas as máquinas. Fluxo:
    rsync -az --delete --exclude node_modules --exclude out --exclude .env --exclude .git --exclude site --exclude state ./ $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/   # de /opt/opus/videolabs
    ssh $VIDEOLABS_RENDER_HOST 'cd /opt/opus/videolabs/engine && npm ci && cd .. && node engine/cli.mjs <slug> scenes && node engine/cli.mjs <slug> pace && node engine/cli.mjs <slug> render --concurrency=12 --log=error'
    rsync -a $VIDEOLABS_RENDER_HOST:/opt/opus/videolabs/labs/<slug>/out/<slug>.mp4 labs/<slug>/out/ && node engine/cli.mjs <slug> player
    
    (Para manter o timing idêntico ao que você revisou, sincronize labs/<slug>/data e public/voiceover em vez de executar scenes/pace no servidor.) Nunca copie .env para lá. Execute renderizações longas detached (nohup bash script & iniciado com ssh -f -n) e aguarde com um Monitor na linha real do time; não grep o log por "error" (a linha de comando tem --log=error). Se o código do Waybar/diagrama mudar, verifique ambos os laboratórios (stills), pois eles o compartilham.
  • Verificando uma alteração no motor: renderize o corte de Amostra com o código antigo e o novo e compare ffmpeg -i a.mp4 -i b.mp4 -lavfi ssim -f null -; scenes/durations/captions.json regenerados e a auditoria cues devem

… [truncado para tradução]

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Habilidades Relacionadas