Building Commit Canvas: from git log to story
The idea was simple. The audit was not. This is the story of v1, the bugs it was quietly hiding, and the rebuild that turned a neat script into a real product.
The idea
Commit Canvas started the way most tools do: I ran git log on a project I'd spent years on, scrolled the wall of subjects, and thought — this is a story, rendered in the worst possible format. Timestamps, gaps, bursts, the 2am fixes, the release weeks: all there, all invisible.
v1 was a weekend-shaped idea: a Python CLI that turns a repository into one cinematic HTML page. A title reveal, a timeline, an activity ring, contributor medals, a certificate at the bottom. Self-contained output, no server, no account. It worked, and it made people smile at their own history — which is the whole product, honestly.
The audit that hurt
Before building v2, I audited v1 the way I'd audit someone else's code. Findings, in the order they stung:
- The "zero dependencies" claim was false. The launcher script said "needs only git + python3" — while the generator imported a template engine. Anyone who cloned and ran it without that package installed got a stack trace for their trouble.
- The parser corrupted commits containing
|. Fields were split on a pipe separator. A commit message likefix | broken | login— a perfectly legal message — silently broke the parse. - Merge commits were discarded. The log ran with
--no-mergesfor cleanliness. Clean, yes — and it threw away the entire branch-and-merge story. - Tags were read one subprocess per tag. On a repo with 69 tags, that's 69 extra process spawns to learn what one
for-each-refcould say. - The heatmap anchored to today. For any repository older than a year, the interesting history rendered outside the grid. On a 15-year project, the first decade was blank.
- The narrative oversold. v1's story arcs triggered on thin evidence and said confident things about repos with four commits.
None of these were exotic. They were the difference between "demo" and "tool" — and every one of them was fixable.
The rebuild
v2's architecture came from one constraint: every claim in the story must be traceable to a measurement. Everything else followed.
One pass, not many
The whole history is read in a single git log --all --numstat --summary call, with fields separated by an ASCII unit separator (\x1f) that will never appear in a message. Merges are kept and counted. File creation and deletion come from summary-mode lines — the authoritative source — instead of guessing from numstat, which can't distinguish "file deleted" from "file emptied." A 30,000-commit synthetic repository analyzes in about two seconds.
Deterministic story engines
Chapters (Beginning, Sprint, Silence, Grind, Launch, Evolution), the shape (Marathon, Climb, Return…), the fingerprint archetypes, and the roast are all plain rules over plain numbers. No AI anywhere in the core path — not because language models can't write, but because a story about your data shouldn't have an imagination in the loop. If the evidence is thin, the tool says the story is just starting.
One renderer, two doors
The output is a static shell — inline CSS, inline JS, a JSON model baked in — that renders entirely client-side. The CLI injects data into that shell; the web version fetches the same shell in the browser and analyzes public repos through the GitHub API with the same narrative rules ported to JavaScript. Same story from either door.
Exports that aren't buttons
Every export is real: PNG cards for socials, an animated GIF of the timeline (a GIF89a encoder written in vanilla JS, because I refused to ship a fake download button), WebM video via the browser's own recorder, SVG timelines, a README block, and the full self-contained HTML. If a browser can't do something, the button says so instead of pretending.
What I learned
- Audit your own claims first. The most embarrassing bug wasn't in the code — it was in the README.
- Deterministic is a feature. The same repository must produce the same story, forever. That's what makes it evidence rather than content.
- The emotion is in the recognition. People don't share Commit Canvas because the charts are pretty. They share it because it says something true about them that they'd never articulated.
- Offline-first is a product decision. "Your code never leaves your machine" isn't a policy page — it's an architecture. No backend, no database, nothing to leak.
Run it yourself
git clone https://github.com/ahmadrrrtx/commit-canvas
cd commit-canvas
./run.sh /path/to/your-project
# → story.html — open it. scroll slowly.
And if you find a repository whose story comes out wrong — tell me. The history doesn't lie, but the parser might.