O que animate-file-history faz?
Construa um GIF (ou MP4) de como algo se parecia ao longo da vida do repositório. A solicitação está em linguagem natural
($ARGUMENTS), portanto seu trabalho é: descobrir quais arquivos ela significa, coletar cada versão deles do git, renderizar
cada uma, descartar versões que pareçam iguais à anterior e unir o resto em uma animação.
O script incluído faz a navegação pelo git, renderização, deduplicação visual e codificação:
scripts/animate-history.sh, relativo ao diretório base desta skill — não ao repositório do usuário. Abaixo,
$SKILL representa esse diretório; chame o script pelo caminho absoluto. --help lista todas as opções. Sua parte é escolher os arquivos e,
para páginas, produzir as capturas de tela.
1. Verifique as ferramentas
command -v git ffmpeg rsvg-convert; ls "/Applications/Google Chrome.app" 2>/dev/null; command -v chromium google-chrome
ffmpeg é obrigatório. SVG precisa de rsvg-convert (brew install librsvg / apt install librsvg2-bin) ou
Chrome/Chromium. Legendas (--label) e páginas HTML precisam de Chrome/Chromium (CHROME=/path substitui
a detecção automática). Se algo estiver faltando, informe o que e como instalar — não descarte versões SVG silenciosamente.
2. Resolva a solicitação para os arquivos
Pesquise no histórico completo do branch atual, não apenas na árvore de hoje — logotipos são renomeados, movidos e reexportados, e arquivos deletados ainda fazem parte da história:
git log --format= --name-only -- ':(glob,icase)**/*logo*' | sort -u
Pesquise pelo nome do que a coisa é chamada, não apenas pela palavra do usuário. Um logotipo também vive em favicon*,
apple-touch-icon*, *mark*, *lockup*, *wordmark*, *brand* e no nome do próprio produto — versões antigas
frequentemente estão apenas no favicon. Amplie a lista de globs de acordo e veja o que retorna.
Filtre para tipos renderizáveis: png jpg jpeg gif webp bmp svg para imagens; html para páginas estáticas. Ignore
saída de build e cópias de terceiros (dist/, build/, node_modules/, .next/).
Em seguida, agrupe as correspondências em linhagens — uma linhagem por animação:
- A mesma arte através de renomes, movimentos ou mudança de formato (
logo.png→brand/logo.svg) é uma linhagem. Passe todos os seus caminhos para uma execução; o script os mescla em uma única linha do tempo por data de commit. - Variantes que coexistem (
logo-dark.svg,logo-mono.svg,favicon.png, exportações com tamanhos como[email protected]) são linhagens separadas. Por padrão, uma animação por linhagem, e anime apenas as variantes que a solicitação plausivelmente significa (geralmente o logotipo principal, não todos os tamanhos de favicon).
Se o agrupamento for genuinamente ambíguo (vários arquivos "logo" não relacionados, ou nada corresponde), mostre a
lista de candidatos com contagens de commits (git log --follow --oneline -- <caminho> | wc -l) e pergunte antes de renderizar.
3a. Imagens: execute o script
"$SKILL/scripts/animate-history.sh" -o logo-history.gif --label <caminho> [<caminho-mais-antigo> ...]
Opções úteis: -s 512 ou -s 1200x800 para canvas, -t 0.25 segundos por versão (padrão para imagens; capturas de página via --frames padrão é 0.8; use o valor do usuário se
fornecido, ex.: "0.5s por quadro" → -t 0.5), --hold 1.5 segundos no quadro final, --bg '#0b0b0b' para logotipos desenhados para fundos escuros, --keep DIR para manter os quadros,
-o x.mp4 para vídeo, --skip <sha> (repetível) para descartar uma versão que o usuário não quer. Ele imprime keep/skip por commit e manteve N de M versões no stderr.
Os caminhos são relativos ao diretório atual (ou -C DIR), como qualquer pathspec do git; execute da raiz do repositório
e passe-os como a lista de histórico os mostra. O script segue renomes automaticamente (git log --follow), então o caminho atual geralmente é suficiente, a menos que o arquivo tenha sido recriado com um novo nome.
3b. Páginas: capture cada versão e depois execute o script na pasta
Uma página precisa ser renderizada em cada commit. Encontre a fonte da página
(index.html, app/page.tsx, src/pages/index.vue, ...) e liste os commits que a alteraram ou o que ela
renderiza — a aparência de uma página inicial também muda através de seus componentes e CSS:
git log --format='%H %cs' --reverse -- <arquivo da página> <diretórios de componentes/estilos>
Se isso for mais de ~40 commits, faça uma amostragem (um por semana ou mês, mais o primeiro e o último) e informe.
As capturas vão em uma pasta nomeada <AAAA-MM-DD>_<sha-curto>.png, para que os arquivos sejam ordenados por data e o nome vire a legenda.
-
HTML estático: sem build. Exporte o commit com
git archive <sha> | tar -x -C "$snap"e capture o arquivo com"$CHROME" --headless=new --hide-scrollbars --window-size=1280,800 --screenshot=... "file://$snap/<página>.html". Delete$snapdepois e mantenha-o fora do repositório. -
Página de framework (React, Next, Vue, Astro, ...): precisa ser executada para renderizar. Use
snapshot-commit.shpor commit:"$SKILL/scripts/snapshot-commit.sh" -C <repositório> -r /<rota> -f https://<site de produção> <sha> "$shots"Ele exporta o commit, instala o próprio lockfile do commit (em cache por lockfile), inicia o servidor dev (
-d 'comando com {porta}'se não fornpm run dev -- --port {porta}), e captura a tela via Playwright (scripts/screenshot-page.mjs, precisa deplaywright-coree Chrome — o do repositório é encontrado viaPLAYWRIGHT_DIR). Ele espera pela rede inativa e cada<img>, descarta um banner de cookies e imprime uma linha:ok,blank,error(uma página de erro como "não foi possível carregar neste navegador") oufail(instalação ou servidor dev). Apenasokescreve um PNG. Pergunte antes de executar isso se significar mais do que algumas instalações.
Verifique os resultados antes de animar, não confie apenas em ok:
- Nunca pegue emprestado o
node_modulesatual. Commits antigos importam pacotes que a árvore atual descartou (ex.:react-router-dom), e a página renderiza em branco. Por isso o script instala por commit. - Commits
blank/error/fail: veja o log do dev, tente uma vez corrigir a causa (variável de ambiente faltando, comando-derrado,--ignore-scriptspulando uma etapa de build necessária), caso contrário pule o commit e informe quantos. - Imagens quebradas (
broken-images=Nna linha deok, com as URLs): ativos que o servidor dev não consegue servir (caminhos hospedados em plataforma como/__l5e/..., arquivos gitignorados ou enviados).-f <site de produção>os busca da produção. Se as imagens ainda estiverem quebradas, informe no relatório — não envie um GIF cheio de caixas vazias silenciosamente. Corrija na hora em vez de relatar depois. - Veja uma folha de contato dos quadros (
ffmpeg -pattern_type glob -i '*.png' -vf scale=320:-1,tile=6x6 -frames:v 1 sheet.png) antes da execução final.
Então:
"$SKILL/scripts/animate-history.sh" --frames "$shots" -s 1280x800 --label -o home-page-history.gif
Capturas idênticas são descartadas da mesma forma que imagens idênticas, assim como as em branco (uma cor sólida)
(--keep-blank para mantê-las). Use um tamanho de janela fixo para cada
captura e prefira -o x.mp4 para páginas longas ou detalhadas — GIFs de páginas completas ficam grandes.
3c. Em vários repositórios
Quando o logotipo vive em mais de um repositório (um app, um dashboard, um site), execute o script em cada repositório com
--keep <dir> e sem --label, depois copie cada quadro mantido em uma pasta nomeada
<AAAA-MM-DD>_<repositório>-<sha-curto>.png — as linhas keep no stderr fornecem a data e o sha de cada quadro mantido em
ordem. Adicione -2, -3 a nomes que colidem (vários arquivos alterados em um commit). Em seguida, execute
--frames <pasta> --label -t 0.25 na pasta mesclada para obter uma única linha do tempo em todos eles.
4. Relatório
Informe o caminho de saída, quantas versões foram encontradas e quantas entraram na animação, o intervalo
de datas e qualquer coisa pulada (não renderizável, builds com falha, amostrada). Abra se solicitado (open x.gif).
Escreva a saída onde o usuário quiser, padronizando para o diretório atual — nunca faça commit a menos que seja solicitado.
Pegadinhas
- A deduplicação é nos pixels renderizados, não nos bytes. Um PNG reexportado ou SVG reformatado é pulado se renderizar de forma idêntica; um deslocamento de um pixel conta como mudança. Esse é o ponto — não adicione um filtro de nível de byte por cima.
- SVGs que referenciam arquivos externos (fontes,
<image href>) renderizam sem eles, já que apenas o próprio SVG é extraído do histórico. Conteúdo incorporado é tranquilo. - Fontes de GIF animado contribuem apenas com seu primeiro quadro.
- Commits de merge não são percorridos —
git logmostra as alterações do arquivo no branch que as fez, que é o que você quer para uma linha do tempo. - Clones rasos (CI,
--depth 1) não têm histórico. Verifiquegit rev-parse --is-shallow-repositorye sugiragit fetch --unshallowse imprimirtrue. - Legendas precisam de Chrome/Chromium porque as builds de ffmpeg incluídas frequentemente não têm
drawtext.
Modelo e esforço
O julgamento aqui é pequeno (escolher arquivos, agrupar linhagens, escolher uma amostra); o trabalho pesado é o script e os loops de shell. Padrão para Sonnet com baixo esforço. Opus ou esforço maior não acrescenta nada para esta tarefa, e um fork ou subagente é desnecessário. Aumente o esforço apenas quando o agrupamento de linhagens for genuinamente ambíguo.
A maior parte dos tokens de uma execução é o contexto herdado da sessão (CLAUDE.md, listas de skills e ferramentas, ~100k+), relido do cache a cada turno, não o trabalho em si. Uma execução em uma sessão enxuta custa muito menos do que uma em uma sessão carregada.
Benchmarks
Meça com a transcrição da sessão (soma usage nos turnos do assistente):
f=$(ls -t ~/.claude/projects/<diretório-do-projeto>/*.jsonl | head -1)
jq -s '[.[]|select(.message.usage)|.message.usage]|{turns:length,out:(map(.output_tokens)|add),cache_read:(map(.cache_read_input_tokens)|add),cache_create:(map(.cache_creation_input_tokens)|add)}' "$f"
| Data | Modelo / esforço | Tarefa | Turnos | Tokens de saída | Cache lido | Cache criado | Resultado |
|---|---|---|---|---|---|---|---|
| 2026-10-23 | Sonnet 5.5 / baixo | Página inicial da storra, apenas descoberta (antes da renderização) | 9 | 3.6k | 731k | 134k | arquivos + histórico de rota encontrados em ~7 chamadas |
Adicione uma linha por execução (execução completa, não apenas descoberta); compare Opus / esforço maior apenas se uma execução Sonnet-baixo errar a linhagem ou a amostragem.