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.
- 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. $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 usenpx openfilm(ignora a fixação) ounpx skills add openfilm/openfilm(uma skill a montante que compete com esta).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.
| Passo | Comando |
|---|---|
| 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 viawindow.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 comloudnorm=I=-16:TP=-1.5:LRA=7; para uma masterização final, executeloudnormduas vezes (meça, depois alimente os valoresmeasured_*de volta) para que o ganho seja linear. lookimprime a loudness da mixagem, efootage.py checkfalha 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.proxymapeia tons comavconvertintegrado do macOS, senão com ffmpegzscale(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.
probesinaliza 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
checkdeve passar antes de entregar um arquivo: H.264, yuv420p, tamanho par, taxa de quadros constante,moovantes demdat(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
lookno próprio MP4 como última verificação.sharefaz 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.gifusa 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.
proxyesharedescartam tudo (-map_metadata -1). O arquivo original, ou uma cópia feita por AirDrop ou exportação do Fotos, mantém. Verifique comexiftool -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:
| Ferramenta | Autoria | Notas |
|---|---|---|
| HyperFrames (HeyGen, Apache-2.0) | HTML/CSS + GSAP, renderizado por Chrome headless | o análogo mais próximo; portão check --json lint/layout/contraste, instantâneos, um plugin para Claude Code |
| Remotion | Componentes React | maduro, skills oficiais de agente; licença source-available, empresas acima de um tamanho pequeno precisam de uma |
| Manim (MIT) | Cenas Python | explicadores de matemática e diagramas |
| MoviePy (MIT) / ffmpeg puro | Python / grafos de filtro | cortes 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
| Erro | Correçã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 PNG | Leia a folha; uma verificação aprovada não diz nada sobre layout |
| Cortar ou olhar diretamente metragem de iPhone | probe, depois proxy: HDR, rotação e VFR todos prejudicam |
| Enviar o MP4 mestre para um chat | share-o, depois check a cópia |
| Um GIF para um README ou página | WebP, ~4× menor |
| Studio desatualizado após uma atualização | Pare os processos antigos de studio/server/main.mjs (pgrep -fl openfilm); um Studio são dois processos |