Dateiverlauf animieren
Erstelle ein GIF (oder MP4) davon, wie etwas im Laufe des Lebens des Repositorys aussah. Die Anfrage erfolgt in natürlicher Sprache
($ARGUMENTS), also besteht die Aufgabe darin: herauszufinden, welche Dateien gemeint sind, jede Version von ihnen aus Git zu sammeln,
jede zu rendern, Versionen zu verwerfen, die genauso aussehen wie die vorherige, und die restlichen zu einer Animation zusammenzufügen.
Das gebündelte Skript erledigt das Git-Durchlaufen, Rendern, visuelle Deduplizieren und Kodieren:
scripts/animate-history.sh, relativ zum Basisverzeichnis dieser Fähigkeit – nicht zum Repository des Benutzers. Im Folgenden
steht $SKILL für dieses Verzeichnis; rufe das Skript mit seinem absoluten Pfad auf. --help listet alle Optionen auf. Dein Teil ist es, die Dateien auszuwählen und
bei Seiten die Screenshots zu erstellen.
1. Prüfe die Werkzeuge
command -v git ffmpeg rsvg-convert; ls "/Applications/Google Chrome.app" 2>/dev/null; command -v chromium google-chrome
ffmpeg wird benötigt. Für SVGs wird rsvg-convert benötigt (brew install librsvg / apt install librsvg2-bin) oder
Chrome/Chromium. --label Beschriftungen und HTML-Seiten benötigen Chrome/Chromium (CHROME=/path überschreibt
die Erkennung). Wenn etwas fehlt, sage was und wie man es installiert – lasse keine SVG-Versionen stillschweigend weg.
2. Löse die Anfrage in Dateien auf
Durchsuche die gesamte Historie des aktuellen Branches, nicht nur den heutigen Baum – Logos werden umbenannt, verschoben und neu exportiert, und gelöschte Dateien gehören trotzdem zur Geschichte:
git log --format= --name-only -- ':(glob,icase)**/*logo*' | sort -u
Suche nach dem, wie das Ding heißt, nicht nur nach dem Wort des Benutzers. Ein Logo lebt auch in favicon*,
apple-touch-icon*, *mark*, *lockup*, *wordmark*, *brand* und dem eigentlichen Produktnamen – frühe Versionen
sind oft nur im Favicon. Erweitere die Glob-Liste entsprechend und schaue, was zurückkommt.
Filtere nach renderbaren Typen: png jpg jpeg gif webp bmp svg für Bilder; html für statische Seiten. Ignoriere
Build-Ausgaben und eingekaufte Kopien (dist/, build/, node_modules/, .next/).
Gruppiere dann die Treffer in Abstammungslinien – eine Abstammungslinie pro Animation:
- Dasselbe Kunstwerk über Umbenennungen, Verschiebungen oder einen Formatwechsel hinweg (
logo.png→brand/logo.svg) ist eine Abstammungslinie. Übergib alle seine Pfade an einen Durchlauf; das Skript führt sie in einer einzigen Zeitleiste nach Commit-Datum zusammen. - Varianten, die nebeneinander existieren (
logo-dark.svg,logo-mono.svg,favicon.png, exportierte Größen wie[email protected]) sind getrennte Abstammungslinien. Standardmäßig wird eine Animation pro Abstammungslinie erstellt, und es werden nur die Varianten animiert, die die Anfrage plausibel meint (normalerweise das primäre Logo, nicht jede Favicon-Größe).
Wenn die Gruppierung wirklich mehrdeutig ist (mehrere nicht zusammenhängende "Logo"-Dateien, oder nichts passt), zeige die
Kandidatenliste mit Commit-Anzahlen (git log --follow --oneline -- <pfad> | wc -l) und frage vor dem Rendern.
3a. Bilder: Führe das Skript aus
"$SKILL/scripts/animate-history.sh" -o logo-history.gif --label <pfad> [<älterer-pfad> ...]
Nützliche Optionen: -s 512 oder -s 1200x800 Leinwand, -t 0.25 Sekunden pro Version (Standard für Bilder;
Seitenscreenshots via --frames standardmäßig 0,8; verwende den Wert des Benutzers, wenn
er einen angegeben hat, z.B. "0,5s pro Frame" → -t 0.5), --hold 1.5 Sekunden auf dem letzten Frame, --bg '#0b0b0b'
für Logos, die für dunkle Hintergründe gezeichnet wurden, --keep VERZ um die Frames zu behalten,
-o x.mp4 für Video, --skip <sha> (wiederholbar) um eine Version zu verwerfen, die der Benutzer nicht möchte. Es gibt keep/skip
pro Commit und behielt N von M Versionen auf stderr aus.
Pfade sind relativ zum aktuellen Verzeichnis (oder -C VERZ), wie bei jedem Git-Pfadspezifikator; führe das Skript vom Repository-Stamm
aus und übergib sie so, wie die Historie sie oben zeigt. Das Skript folgt selbst Umbenennungen (git log --follow), daher reicht der aktuelle Pfad normalerweise aus, es sei denn, die Datei wurde unter einem neuen Namen neu erstellt.
3b. Seiten: Screenshot jeder Version, dann führe das Skript im Ordner aus
Eine Seite muss bei jedem Commit gerendert werden. Finde die Quelle der Seite
(index.html, app/page.tsx, src/pages/index.vue, ...) und liste die Commits auf, die sie oder das, was sie
rendert, berührt haben – das Aussehen einer Startseite ändert sich auch durch ihre Komponenten und CSS:
git log --format='%H %cs' --reverse -- <seitendatei> <ihre komponenten-/styles-verzeichnisse>
Wenn das mehr als ~40 Commits sind, nimm eine Stichprobe (eine pro Woche oder Monat, plus den ersten und letzten) und sage dies.
Screenshots kommen in einen Ordner mit dem Namen <JJJJ-MM-TT>_<kurzer-sha>.png, damit die Dateien nach Datum sortieren und der Name zur
Beschriftung wird.
-
Statisches HTML: kein Build. Exportiere den Commit mit
git archive <sha> | tar -x -C "$snap"und mache einen Screenshot der Datei mit"$CHROME" --headless=new --hide-scrollbars --window-size=1280,800 --screenshot=... "file://$snap/<seite>.html". Lösche$snapdanach und behalte es außerhalb des Repositorys. -
Framework-Seite (React, Next, Vue, Astro, ...): Sie muss laufen, um zu rendern. Verwende
snapshot-commit.shpro Commit:"$SKILL/scripts/snapshot-commit.sh" -C <repo> -r /<route> -f https://<Produktionsseite> <sha> "$shots"Es exportiert den Commit, installiert die Lockdatei dieses Commits (pro Lockdatei zwischengespeichert), startet den Dev-Server (
-d 'Befehl mit {port}'wenn es nichtnpm run dev -- --port {port}ist) und macht einen Screenshot über Playwright (scripts/screenshot-page.mjs, benötigtplaywright-coreund Chrome – das eigene des Repos wird gefunden überPLAYWRIGHT_DIR). Es wartet auf Netzwerkinaktivität und jedes<img>, schließt ein Cookie-Banner und gibt eine Zeile aus:ok,blank,error(eine Fehlerseite wie "konnte in diesem Browser nicht geladen werden") oderfail(Installation oder Dev-Server). Nurokschreibt ein PNG. Frage vor der Ausführung, wenn dies mehr als eine Handvoll Installationen bedeutet.
Überprüfe die Ergebnisse vor dem Animieren, vertraue nicht blind auf ok:
- Verwende niemals das aktuelle
node_modules. Alte Commits importieren Pakete, die der aktuelle Baum fallen gelassen hat (z.B.react-router-dom), und die Seite wird leer gerendert. Deshalb installiert das Skript pro Commit. blank/error/failCommits: Sieh dir das Entwickler-Log an, versuche einmal, die Ursache zu beheben (eine fehlende Umgebungsvariable, ein falscher-dBefehl,--ignore-scripts, das einen benötigten Build-Schritt überspringt), überspringe andernfalls den Commit und sage wie viele.- Kaputte Bilder (
broken-images=Nin derok-Zeile, mit den URLs): Assets, die der Dev-Server nicht ausliefern kann (plattform-gehostete Pfade wie/__l5e/..., git-ignorierte oder hochgeladene Dateien).-f <Produktionsseite>holt sie von der Produktion. Wenn Bilder immer noch kaputt sind, sage dies im Bericht – liefere nicht stillschweigend ein GIF voller leerer Boxen aus. Behebe es im laufenden Betrieb, anstatt danach zu berichten. - Sieh dir ein Kontaktblatt der Frames an (
ffmpeg -pattern_type glob -i '*.png' -vf scale=320:-1,tile=6x6 -frames:v 1 sheet.png) vor dem endgültigen Durchlauf.
Dann:
"$SKILL/scripts/animate-history.sh" --frames "$shots" -s 1280x800 --label -o startseiten-geschichte.gif
Identische Screenshots werden auf die gleiche Weise wie identische Bilder verworfen, ebenso wie leere (einfarbige)
(--keep-blank um sie zu behalten). Verwende eine feste Fenstergröße für jeden
Shot und bevorzuge -o x.mp4 für lange oder detaillierte Seiten – GIFs von ganzen Seiten werden groß.
3c. Über mehrere Repos hinweg
Wenn das Logo in mehr als einem Repo lebt (eine App, ein Dashboard, eine Website), führe das Skript in jedem Repo mit
--keep <verz> und ohne --label aus, kopiere dann jeden behaltenen Frame in einen Ordner mit dem Namen
<JJJJ-MM-TT>_<repo>-<kurzer-sha>.png – die keep-Zeilen auf stderr geben das Datum und den Sha jedes behaltenen Frames in
Reihenfolge an. Füge -2, -3 zu Namen hinzu, die kollidieren (mehrere Dateien wurden in einem Commit geändert). Führe dann
--frames <ordner> --label -t 0.25 auf dem zusammengeführten Ordner aus, um eine einzige Zeitleiste über alle hinweg zu erhalten.
4. Bericht
Gib den Ausgabepfad an, wie viele Versionen gefunden wurden und wie viele es in die Animation geschafft haben, den Datumsbereich
und alles, was übersprungen wurde (nicht renderbar, fehlgeschlagene Builds, ausgestichprobt). Öffne es, wenn darum gebeten wird (open x.gif).
Schreibe die Ausgabe dorthin, wo der Benutzer sie haben möchte, standardmäßig in das aktuelle Verzeichnis – committe sie nie, es sei denn,
darum gebeten.
Fallstricke
- Die Deduplizierung erfolgt auf Basis gerenderter Pixel, nicht von Bytes. Ein neu exportiertes PNG oder neu formatiertes SVG wird übersprungen, wenn es identisch rendert; eine Verschiebung um ein Pixel zählt als Änderung. Das ist der Sinn – füge keinen Byte-Level-Filter hinzu.
- SVGs, die auf externe Dateien verweisen (Schriftarten,
<image href>) rendern ohne sie, da nur das SVG selbst aus der Historie geholt wird. Eingebettete Inhalte sind in Ordnung. - Animierte GIF-Quellen tragen nur ihren ersten Frame bei.
- Merge-Commits werden nicht durchlaufen –
git logzeigt die Änderungen der Datei auf dem Branch, der sie vorgenommen hat, was für eine Zeitleiste gewünscht ist. - Flache Klone (CI,
--depth 1) haben keine Historie. Überprüfegit rev-parse --is-shallow-repositoryund schlagegit fetch --unshallowvor, wenn estrueausgibt. - Beschriftungen benötigen Chrome/Chromium, weil die gebündelten ffmpeg-Builds oft
drawtextfehlt.
Modell und Aufwand
Das Urteilsvermögen hier ist gering (Dateien auswählen, Abstammungslinien gruppieren, eine Stichprobe wählen); die Hauptarbeit liegt im Skript und Shell-Schleifen. Standardmäßig Sonnet mit geringem Aufwand. Opus oder höherer Aufwand bringt für diese Aufgabe nichts, und ein Fork oder Subagent ist unnötig. Erhöhe den Aufwand nur, wenn die Gruppierung der Abstammungslinien wirklich mehrdeutig ist.
Die meisten Tokens eines Durchlaufs sind der geerbte Kontext der Sitzung (CLAUDE.md, Fähigkeits- und Werkzeuglisten, ~100k+), der jedes Mal aus dem Cache gelesen wird, nicht die Arbeit selbst. Ein Durchlauf in einer schlanken Sitzung kostet weit weniger als einer in einer vollen.
Benchmarks
Messe mit dem Sitzungsprotokoll (summiere usage über die Assistenten-Durchgänge):
f=$(ls -t ~/.claude/projects/<projekt-verz>/*.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"
| Datum | Modell / Aufwand | Aufgabe | Durchgänge | Ausgabe Tok | Cache gelesen | Cache erstellt | Ergebnis |
|---|---|---|---|---|---|---|---|
| 2026-10-23 | Sonnet 5.5 / niedrig | storra Startseite, nur Erkundung (vor dem Rendern) | 9 | 3.6k | 731k | 134k | Dateien + Routenhistorie in ~7 Aufrufen gefunden |
Füge eine Zeile pro Durchlauf hinzu (vollständiger Durchlauf, nicht nur Erkundung); vergleiche Opus / höheren Aufwand nur, wenn ein Sonnet-niedrig-Durchlauf die Abstammungslinie oder Stichprobenziehung falsch macht.