/github-year-in-review
Dein Jahr auf GitHub, als 45-Sekunden-Film, den du posten kannst.
Geschwister von /brag: brag macht aus einem Projekt ein Launch-Video, dieses hier macht aus einem Jahr eines Menschen eines. Gleicher Rendering-Pfad (HyperFrames), gleiche Auslieferung (Poster als Frame 0 eingebrannt, Teilen-Text). Der Unterschied: Die Geschichte sind Daten, also werden die Daten und die Beat-Logik als Skripte ausgeliefert und der Job des Agenten ist es, die Zahlen zu prüfen, den Text zu schärfen, sich die Frames anzusehen und auszuliefern.
Aufruf
/github-year-in-review
/github-year-in-review --user octocat --year 2025
/github-year-in-review --include-private --no-music
| Option | Standard |
|---|---|
--user | der authentifizierte gh-Benutzer |
--year | das aktuelle Jahr (bis 31. Dezember mit „bisher“ gekennzeichnet) |
--tz | Zeitzone dieser Maschine (für den Tageszeit-Beat) |
--include-private | aus: private Repos werden gezählt, aber nie genannt |
--no-music | Musik an, wenn ein Track verfügbar ist |
--format | portrait 1080x1350 (das einzige ausgelieferte Format) |
Die Ausgabe erfolgt in year-in-review-<benutzer>-<jahr>/ im aktuellen Verzeichnis (füge einen Zeitstempel hinzu, falls es bereits existiert). <skill-verz> ist das Verzeichnis, das diese Datei enthält.
Voraussetzungen
gh authentifiziert (gh auth status), Python 3.9+, Node 18+ mit npx hyperframes, ffmpeg.
Die HyperFrames-Domain-Skills (hyperframes-core, hyperframes-cli) für Prüfung und Rendering.
Schritt 1: Sammeln
python3 <skill-verz>/scripts/collect.py --user <login> --year <jahr> --out <ausgabe>/year.json
Etwa zwei Minuten für ein aktives Konto (der Commit-Verlauf wird für den Uhrzeit-Beat abgetastet). Es schreibt Summen, den täglichen Kalender, Rhythmus (Serie, Stunden, Wochentage), Top-Repos, Sprachen, Pull Requests, neue Repos, in diesem Jahr erhaltene Sterne und Automatisierung: Repos, in denen mindestens 60 % der abgetasteten Commits eine gemeinsame Nachrichtenvorlage teilen (ein Cron-Job, der als der Benutzer commitet). Automatisierung wird aus Rhythmus- und „Arbeits“-Beats herausgehalten und wird ein eigener Überraschungs-Beat.
Es sammelt auch die optionalen, thematischen Daten: Agenten (mit KI-Coding-Agenten gemeinsam verfasste Commits, nur anhand von Signaturen erkannt, plus Agent-PRs anhand von Fußzeilen, App-Autor und claude/-artigen Branch-Präfixen), Releases, die in diesem Jahr getaggt wurden, und den größten gemergten PR. Diese werden nur dann zu Beats, wenn die Zahlen vorhanden sind (Schwellenwerte in references/story.md).
Gate: Lies year.json und führe einen Plausibilitätscheck durch, bevor du baust. Die Kopfzahl sollte mit der Zahl auf dem GitHub-Profil des Benutzers für dieses Jahr übereinstimmen. Wenn etwas falsch aussieht (ein Bot, den der Detektor übersehen hat, ein Repo, das nicht genannt werden sollte), korrigiere den Collector oder verwende Überschreibungen in story.json; editiere niemals Zahlen von Hand in die Komposition.
Schritt 2: Geschichte
python3 <skill-verz>/scripts/build.py <ausgabe>/year.json --out <ausgabe> \
[--music <track.mp3> --cues <track.music-cues.json>]
Dies schreibt <ausgabe>/story.json (Beats, Text, Timings), <ausgabe>/composition/ (den Film) und <ausgabe>/thumbnail/ (ein Ein-Sekunden-Standbild des Endes für das Cover, siehe Schritt 4). Beats, ihre Daten und Fallbacks sind in references/story.md. Beats mit dürftigen Daten fallen weg, sodass ein ruhiges Jahr einen kürzeren Film ergibt, keinen leeren.
Lies dann story.json und verbessere den Text, wo du spezifischer sein kannst als die Vorgaben (Untertitel, der Archetyp-Name und -Grund, das Arbeits-Beat-Zitat). Regeln:
- Jede Behauptung muss in
year.jsonwahr sein. Keine erfundenen Zahlen, keine Superlative, die die Daten nicht hergeben. - Kurze Zeilen. Die Schriftart ist absichtlich groß; alles, was länger als etwa 12 Wörter ist, bleibt nicht lange genug stehen.
- Keine privaten Repo-Namen, es sei denn
--include-private. - Keine Emojis, keine Gedankenstriche, kein „Crushing-it“-Registers. Es kommt auf LinkedIn.
- Stelle Agenten und Automatisierung als ein Team dar, das die Person geführt hat („ausgeliefert mit“, „gemeinsam verfasst mit“). Beschäme niemals, impliziere niemals, dass die Arbeit weniger ihre war; Agentenzahlen sind untere Grenzen.
Baue aus der bearbeiteten Geschichte neu mit --story <ausgabe>/story.json (Timings werden neu abgeleitet).
Musik: Falls /brag installiert ist, funktionieren dessen gebündelte Tracks und Cue-Voreinstellungen sofort
(<brag-verz>/assets/music/*.mp3, <brag-verz>/assets/music/cues/*.music-cues.json). Bevorzuge einen Track, der mindestens so lang ist wie der Film. Mit --cues rasten Szenenanfänge auf den nächsten Beat ein. Ohne einen Track ist der Film stumm, was in Ordnung ist: LinkedIn spielt automatisch stumm ab.
Schritt 3: Prüfen, rendern, anschauen
cd <ausgabe>/composition
npx hyperframes check # Gate: null Fehler; behebe auch line_unread- und type-floor-Warnungen
npx hyperframes render --quality draft --output ../draft.mp4
Extrahiere einen stabilen Frame pro Beat und sieh dir jeden selbst an, bevor du das finale Rendering erstellst. Sieh dir auch jede Kapitelkarte an, nachdem sich ihr Befehl eingetippt hat (etwa 2,5 s nach Kartenbeginn): der vollständige Befehl muss auf dem Bildschirm sein, eine Zeile, Schrift auf dunklem Grund.
for t in $(jq -r '.beats[]|.start+.duration-0.5' ../story.json); do
ffmpeg -loglevel error -ss $t -i ../draft.mp4 -frames:v 1 ../frame-$t.png; done
Achte auf: überlaufenden oder abgeschnittenen Text, eine Zahl, die nicht zu year.json passt, einen leeren oder langweiligen Beat, Text, der in Telefongröße nicht lesbar wäre (skaliere einen Frame auf 540 px Breite), einen schwachen ersten Frame. Behebe die Ursache in story.json (Text) oder melde es als Skill-Bug; dann:
npx hyperframes render --quality high --output ../year-in-review.mp4
Schritt 4: Ausliefern
Poster: Der stabile Frame des Hooks (etwa 2,9 s) ist das Thumbnail. Brenne es als Frame 0 ein, damit es jede Plattform anzeigt (gleiche Technik wie bei /brag Schritt 4):
cd <ausgabe>
ffmpeg -ss 2.9 -i year-in-review.mp4 -frames:v 1 -q:v 2 poster.jpg
ffmpeg -y -i year-in-review.mp4 -i poster.jpg \
-filter_complex "[0:v][1:v]overlay=0:0:enable='eq(n,0)'[v]" \
-map "[v]" -map '0:a?' -c:v libx264 -crf 20 -preset slow -pix_fmt yuv420p \
-c:a aac -b:a 160k -movflags +faststart tmp.mp4 && mv tmp.mp4 year-in-review.mp4
Thumbnail: Das Ende (Jahresraster, Handle, „, im Rückblick.“) als sauberes Standbild, ohne Folienzähler, Hash-Label, Fußzeilenleiste oder CTA. Lade es als benutzerdefiniertes Thumbnail des Videos auf LinkedIn hoch (es entspricht dem 4:5-Seitenverhältnis des Videos, das LinkedIn erwartet) und verwende es überall dort, wo ein Coverbild verlangt wird:
cd <ausgabe>
npx hyperframes check thumbnail
npx hyperframes snapshot thumbnail --at 0.5 --no-end -o thumbnail/shots
cp thumbnail/shots/frame-00-at-0.5s.png thumbnail.png
Gate: year-in-review.mp4 ist H.264, 1080x1350, unter 50 MB, 25–75 s (der Bau begrenzt auf 70 plus Kapitelkarten); poster.jpg existiert; thumbnail.png ist 1080x1350 und du hast es dir angesehen (keine Zähler, keine Leiste, nichts abgeschnitten).
Schreibe <ausgabe>/share-copy.txt: zwei oder drei einfache Sätze in der Stimme des Benutzers, aufgebaut aus den stärksten wahren Fakten (der Archetyp, eine Zahl, ein Projekt). Keine Hashtag-Wand; maximal zwei. Beispiel: „Mein 2026 auf GitHub, bisher: 30 neue Repos, eine 44-tägige Serie und ein Bot, der mehr committed hat als ich. Erstellt mit github-year-in-review.“
Sage dem Benutzer, wo das Video, das Thumbnail, das Poster und der Teilen-Text sind, und eine Zeile darüber, was der Film aussagt.
Kreative Gesetze
- Frame 0 ist der Beitrag. Name, Jahr und die Kopfzahl, stabil.
- Eine Frage, ein Fokuspunkt pro Beat. Große Zahl oder eine Form; alles andere ist ein Label.
- Identität vor Inventar. Der Film endet damit, wer sie waren (Archetyp), nicht mit einer Summe.
- Ehrlich. Automatisierung wird genannt, private Namen werden versteckt, Teiljahre sagen „bisher“.
- Lesbar stummgeschaltet. Jeder Beat ergibt Sinn, wenn der Ton aus ist.
- Git, nicht GitHub. Getippte Eingabeaufforderungen, Hash-Label, Diff-Hunks und Footer; keine Logos, keine GitHub-Grüns oder UI-Chrome.
- Originallook. Die Ledger-Identität in references/story.md; gestalte es nicht in Wrapped- oder Unwrapped-Stil um.