Communitygithub.com

kylefritz/video-skill

Crie, edite, verifique e entenda vídeos a partir de um terminal, para um agente que não pode assisti-los.

O que é video-skill?

video-skill é uma skill para agentes de IA (como Claude Code, Cursor) que permite criar, editar, inspecionar e entregar vídeos sem que o agente precise assisti-los visualmente. Em vez disso, cada etapa converte vídeo em algo legível: quadros estáticos (frames) que o agente olha e números que confere. A skill suporta plataformas como OpenFilm (para autoria de filmes baseada em HTML), além de ferramentas como ffmpeg, MoviePy e Remotion. Ela inclui scripts para criação de filmes, ingestão de metragem bruta (com correção de HDR, rotação e VFR), transcrição de áudio com parakeet-mlx, verificação de conformidade (codec, loudness, faststart) e exportação para WebP/GIF. Útil para vídeos de lançamento, demonstrações, montagens de fotos, clipes sociais e análise de conteúdo de vídeo.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/kylefritz/video-skill/tree/HEAD

Perguntar na sua IA favorita

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

Documentação

O que video-skill faz?

Os scripts ficam em scripts/ junto deste arquivo; escreva-os como $S abaixo, mas escreva o caminho absoluto em cada comando, porque variáveis de shell não persistem entre chamadas Bash.

Você não pode assistir vídeos, então cada passo os transforma em algo que pode ler: quadros que você olha e números que confere. Fazer um filme é escrever → renderizar quadros → ler a folha de contato → corrigir. Entender metragem bruta é sondar → fazer proxy → folhas com timestamps + transcrição → julgar. Entregar é um script que verifica codec, taxa de quadros, faststart e loudness, para que "funcione em tudo" seja um fato.

Primeira vez em um Mac

Execute sh $S/setup.sh você mesmo. Ele verifica mise e ffmpeg (instalando ffmpeg com Homebrew quando possível), instala o OpenFilm fixado na primeira utilização e executa openfilm doctor. Corrija cada TODO que ele imprimir, ou explique claramente para a pessoa. É seguro executar novamente.

Fazendo um filme: OpenFilm

OpenFilm (MIT) é o formato de autoria: um filme é uma pasta com um film.html que corta páginas HTML, metragem, imagens e som juntos, cada página desenhando qualquer momento t que for solicitado. Studio é seu editor local no navegador.

  1. Imprima o manual e leia-o por inteiro (é curto e muda entre versões): $S/openfilm. Siga-o, com este arquivo tendo precedência onde diferirem.
  2. $S/openfilm é a única forma de executar o OpenFilm aqui: ele fixa a versão, instala via mise na primeira utilização e impede que o Studio abra uma janela do navegador. Não use npx openfilm (ignora a fixação) ou npx skills add openfilm/openfilm (uma skill a montante que compete com esta).
  3. FILM é sempre um caminho absoluto, $HOME/Movies/OpenFilm/Projects/<nome-do-filme>. Um nome relativo vai para a pasta atual, como em um repositório git de alguém. Filmes nunca vão para um repositório.
PassoComando
Criar ou abrir$S/openfilm open FILM
Verificar o filme inteiro$S/openfilm -C FILM look
Verificar um momento, um trecho, um arquivo… look 4.5, look 3-6, look assets/bed.wav
Verificar uma entrada rápida… look 0-2 --count 24
Renderizar o MP4$S/openfilm -C FILM render
Quais serviços de mídia estão conectados$S/openfilm get
Diagnosticar a instalação$S/openfilm doctor

look e render executam sem o Studio aberto e imprimem caminhos relativos ao FILM. O endereço do Studio contém uma chave de acesso: forneça-a apenas para a pessoa com quem está trabalhando (é 127.0.0.1, Chrome ou Edge, não de um celular).

Leia cada folha de look antes de mostrar qualquer coisa e corrija o que vê. Suas verificações (mesmo t desenha a mesma imagem, fontes carregadas, texto cortado, loudness) não dizem nada sobre gosto ou layout. Um ! sobre texto cortado durante uma entrada é aceitável; cortado em repouso é um bug. Depois, olhe alguns momentos em tamanho real (look 12.5): um bloco de 300 px esconde coisas pequenas, incluindo pessoas.

Como um filme é construído, aprendido ao fazer um:

  • Uma página por tomada; o que as páginas compartilham (um movimento Ken Burns, fontes, cores) vai em um módulo que importam. Todo valor é uma função apenas de t: sem temporizadores, sem loop de animação, sem estado.
  • Páginas desbotam-se a si mesmas (opacidade a partir de t); um fade para preto entre tomadas em uma faixa é a transição mais simples. Uma cross-dissolve precisa da tomada de entrada em uma faixa acima da de saída.
  • Texto sobre fotos precisa de uma sombra atrás (um gradiente inferior), ou desaparece em cenas movimentadas.
  • Fontes vão em FILM/fonts/ com @font-face, aguardadas via window.film.ready (document.fonts.ready). Para fotos, ready: img.decode().
  • Corte com #t=entrada,saida, nunca cortando novos arquivos; um som mais longo que o filme estende o filme.

Som

$S/openfilm get mostra o que está conectado; voz gerada, música e efeitos precisam das chaves do provedor da pessoa (Studio: logotipo OpenFilm → Configurações → Provedores). Sem elas, faça som com ffmpeg, salve em FILM/assets/, mantenha o comando em FILM/sound-notes.txt para poder ser reconstruído e diga qual serviço faria melhor. Você não pode ouvi-lo, então julgue por números:

  • -16 LUFS integrado para uma mixagem final (podcasts, a maioria dos vídeos web); plataformas de streaming normalizam perto de -14. Mantenha o pico verdadeiro em ou abaixo de -1 dBTP. Um fundo sob uma voz fica em ~-22.
  • Meça: ffmpeg -i X -af ebur128=peak=true -f null -. Normalize um fundo gerado com loudnorm=I=-16:TP=-1.5:LRA=7; para uma masterização final, execute loudnorm duas vezes (meça, depois alimente os valores measured_* de volta) para que o ganho seja linear.
  • look imprime a loudness da mixagem, e footage.py check falha em uma renderização que não atinge o alvo.

Metragem recebida: ingestão

Vídeo de celular raramente é o que parece. Execute isso em qualquer coisa antes de olhar ou cortar:

uv run --no-project --with pillow python -I $S/footage.py probe CLIP.mov ...
uv run --no-project --with pillow python -I $S/footage.py proxy CLIP.mov <scratch>/clip.mp4

probe avisa sobre cada um destes, e proxy corrige todos em uma passada (SDR BT.709, rotação incorporada, 30 fps constante, tamanho par, H.264 yuv420p, AAC 48 kHz, faststart):

  • HDR (iPhones gravam HLG por padrão: color_transfer=arib-std-b67, BT.2020). Lido como SDR, parece desbotado e muda cores: vermelhão vira laranja. proxy mapeia tons com avconvert integrado do macOS, senão com ffmpeg zscale (ausente em muitas builds do Homebrew), senão avisa.
  • Rotação: celulares armazenam vídeo na vertical com uma bandeira de rotação; algumas ferramentas ignoram.
  • Taxa de quadros variável: nominal 24, média 23,997. Os tempos dos quadros flutuam e o áudio sai do sincronismo após cortes. probe sinaliza qualquer diferença acima de 0,001 fps.
  • Dimensões ímpares: H.264 yuv420p precisa de largura e altura pares.

Olhe e corte a partir do proxy; mantenha o original para qualquer coisa que precise permanecer em qualidade total.

Entendendo metragem

uv run --no-project --with pillow python -I $S/footage.py frames <scratch>/clip.mp4 <scratch>/sheets --every 4

Isso captura um quadro a cada mudança de cena (--scene 0.3) e pelo menos um a cada --every segundos, limitado a --max 60, em folhas de blocos de 5×6 rotulados 0007 · 1:23.4, com manifest.json mapeando cada id ao seu tempo. Leia as folhas e responda com ids e tempos. Prática, não doutrina:

  • Filmes autorados: amostragem uniforme no comprimento da tomada. Metragem encontrada: mudanças de cena mais um piso de um quadro a cada 2-5 s. Ação rápida: um trecho curto com --every 0.5.
  • Mantenha uma folha com menos de ~2.500 px no lado maior e leia algumas de cada vez; para metragem longa, distribua para subagentes sobre folhas, cada um escrevendo um veredito por id de bloco em JSONL, depois python3 -I $S/check_verdicts.py manifest.json out/*.jsonl (ids faltantes, duplicados ou inventados falham; uma folha onde todos os blocos receberam a mesma resposta foi provavelmente folheada).
  • A maior parte de um vídeo com fala está no áudio. Transcreva no dispositivo com tempos de palavra: uvx parakeet-mlx AUDIO.wav --output-format json --output-dir <scratch> (extraia o áudio primeiro: ffmpeg -i clip.mp4 -ar 16000 -ac 1 audio.wav). Junte palavras a quadros pelo tempo. Nomes próprios saem errados ("torii" → "Torrey"), então verifique nomes contra o que vê antes de citar.

Entregando

uv run --no-project --with pillow python -I $S/footage.py check FILM/<nome>.mp4 --duration 30
uv run --no-project --with pillow python -I $S/footage.py share FILM/<nome>.mp4 <scratch>/<nome>-share.mp4
uv run --no-project --with pillow python -I $S/footage.py gif FILM/<nome>.mp4 <scratch>/loop.webp --start 2.5 --duration 6 --width 480
  • check deve passar antes de entregar um arquivo: H.264, yuv420p, tamanho par, taxa de quadros constante, moov antes de mdat (faststart: toca enquanto baixa), duração, loudness ±1,5 LU, pico verdadeiro.
  • Renderize quando a pessoa pedir o arquivo ou não puder estar neste Mac; execute look no próprio MP4 como última verificação. share faz uma cópia pequena (1280 de largura, CRF 28: uma renderização 1080p de 30 s foi de 34 MB para 3,8 MB) para uma página web ou chat; o MP4 do filme permanece intocado.
  • Loops: WebP animado em vez de GIF. Um loop de fotos de 5,6 s com zoom lento tinha 6,7 MB como GIF e 1,6 MB como WebP: GIF não pode reutilizar pixels quando cada pixel se move. GIF apenas quando o alvo não pode exibir WebP; então footage.py gif X.gif usa uma paleta gerada (palettegen/paletteuse).
  • Remova o que não deve viajar: vídeos de iPhone carregam GPS, modelo do telefone e hora nos metadados. proxy e share descartam tudo (-map_metadata -1). O arquivo original, ou uma cópia feita por AirDrop ou exportação do Fotos, mantém. Verifique com exiftool -GPSCoordinates ARQUIVO.

Fotos em um filme

Use a skill photo-skill (github.com/kylefritz/photo-skill; se não estiver instalada, ofereça-se para cloná-la em ~/.claude/skills/photo-skill) para encontrá-las (pesquise a biblioteca por descrição, depois julgue folhas de contato) e para baixar originais em resolução total: pré-visualizações são pequenas demais para 1080p. Copie o que o filme usa para FILM/assets/, regravado sem EXIF. Antes de um filme com fotos de alguém ir para qualquer lugar, olhe cada tomada em tamanho real: detecção facial perde multidões, e um bloco de 300 px esconde pessoas que um quadro 1080p mostra.

Outras ferramentas

OpenFilm se adapta melhor a um agente porque um filme é HTML puro e look devolve exatamente o que você precisa ver. Alternativas, no final de 2026:

FerramentaAutoriaNotas
HyperFrames (HeyGen, Apache-2.0)HTML/CSS + GSAP, renderizado por Chrome headlesso análogo mais próximo; portão check --json lint/layout/contraste, instantâneos, um plugin para Claude Code
RemotionComponentes Reactmaduro, skills oficiais de agente; licença source-available, empresas acima de um tamanho pequeno precisam de uma
Manim (MIT)Cenas Pythonexplicadores de matemática e diagramas
MoviePy (MIT) / ffmpeg puroPython / grafos de filtrocortes e sobreposições simples; ffmpeg é melhor mantido como camada de E/S

Atualizando o OpenFilm

Atualizações oficiais são frequentes. Leia as notas de versão e execute npm view openfilm scripts primeiro (uma entrada preinstall ou postinstall merece uma olhada), depois altere OPENFILM_VERSION em scripts/openfilm e re-execute setup.sh. Depois ls ~/Library/Caches/ms-playwright: a primeira execução do OpenFilm exclui navegadores Playwright sem marcador de link; setup.sh relata quais removeu, e npx playwright install chromium no projeto que precisa de um o recoloca.

Erros comuns

ErroCorreção
npx openfilm …$S/openfilm …: npx ignora a fixação
look ou render na pasta errada$S/openfilm -C FILM …
Confiar nas verificações de look sem abrir seu PNGLeia a folha; uma verificação aprovada não diz nada sobre layout
Cortar ou olhar diretamente metragem de iPhoneprobe, depois proxy: HDR, rotação e VFR todos prejudicam
Enviar o MP4 mestre para um chatshare-o, depois check a cópia
Um GIF para um README ou páginaWebP, ~4× menor
Studio desatualizado após uma atualizaçãoPare os processos antigos de studio/server/main.mjs (pgrep -fl openfilm); um Studio são dois processos

Habilidades Relacionadas