Generated 2026-06-24, viewed through the bent lens of Build to Think.

“No design doc could have described this project, because the project didn’t exist until I started building it.”

Last audit had a headline: a sketch became a finished, deployed game — Flow Slays IO, four playable characters with hand-drawn pixel portraits, a Slay-the-Spire engine that never hardcodes a card, synthesized sound, a boss. The thing that was a curiosity became a thing you can lose. This round is the epilogue nobody plans for, and it is the quietest in the lineage: one commit in seven days.

That’s the whole delta — and it’s a telling one. Having finished the game, the author kept using it, hit the friction of authoring cards one JSON object at a time, and built the tool that fixes it: a CSV bulk-import pipeline with a tiny effects DSL, server-side validation, and a paste-and-preview admin UI. No spec asks for a content importer up front; only living inside your own finished product surfaces the need. Below: the telemetry, the screenshots (the game still looks like this), and the portfolio project by project. The author is a PM on Google Flow who refuses to write design docs and then writes this. The building is the thinking — and this round, the maintaining was the thinking.

Flow Slays IO character-select screen — four pixel-art PMs and a starting deck
Flow Slays IO, flowtcg — pick your PM, survive the road to launch. Four characters (Amar the Builder, Olivia the Assassin, Thomas the Boss, Anika the Agent Wrangler), each a real deck rendered with the in-game card component. Finished last round; this round it grew a CSV importer so new decks paste in instead of being typed by hand.

Audit Meta — the audit, audited

REPOS THAT MOVED 1 one repo, onecommit, seven days DAYS SINCE LAST AUDIT 7 a quietweek PERMISSION PROMPTS 0 by policy — seesettings.local.json COMMITS INSPECTED 1,073 across 20 repos,3 locations

Every audit wants to measure itself. This one obliges — and records the smallest round in the lineage: one commit in seven days. No new repos; the entire delta is a single content-pipeline commit in flowtcg, the game that finished shipping last round. The audit is downstream of the building, and this round the building did the quiet thing — maintained what it had already finished.

Metric Value
Repositories crawled 20 (across ~/CodeProj, ~/ummerr.github.io, /tmp/archetypes-audit) — no new repos this round
Shipped to production 11
Total tracked commits ~1,073 (mainline, no-merges; StreakUp excluded)
Infrastructure cost $0 (Vercel Hobby, GitHub Pages, Supabase Free, itch.io, OpenStreetMap, USGS 3DEP)
Prior audits in the lineage 7 — Apr 12, Apr 16, Apr 18, May 29, Jun 7, Jun 17, Jun 24 (this one)
Engineers employed on this portfolio 1 (not by training)

The year at a glance

Zoom out from the one-commit week to the twelve-month backdrop. Most of it is empty. The live cells cluster in the right-hand third — the “2026 run” — and the rightmost edge is nearly flat now: not a cooling-off so much as a finished project resting, with a single tooling commit as the week’s only mark on the curve.

Cumulative commits — rolling 52 weeks · Jun 2025 → Jun 2026

JunJulAugSepOctNovDecJanFebMarAprMayJun0377754cumulative commitsApr 12 · +84Mar 26 · +55

The same year as a running total. Flat through summer and fall, then the line tilts up hard in late winter and never quite settles — the labelled dots are the two steepest single days. The line draws itself left-to-right as it scrolls into view; the endpoint is today.

Daily commits — rolling 52 weeks · Jun 2025 → Jun 2026

JunJulAugSepOctNovDecJanFebMarAprMayJunMWF2025-06-15: 0 commits2025-06-16: 0 commits2025-06-17: 0 commits2025-06-18: 0 commits2025-06-19: 0 commits2025-06-20: 0 commits2025-06-21: 0 commits2025-06-22: 0 commits2025-06-23: 0 commits2025-06-24: 0 commits2025-06-25: 1 commits2025-06-26: 0 commits2025-06-27: 0 commits2025-06-28: 0 commits2025-06-29: 0 commits2025-06-30: 0 commits2025-07-01: 0 commits2025-07-02: 0 commits2025-07-03: 0 commits2025-07-04: 0 commits2025-07-05: 0 commits2025-07-06: 0 commits2025-07-07: 0 commits2025-07-08: 0 commits2025-07-09: 0 commits2025-07-10: 0 commits2025-07-11: 0 commits2025-07-12: 0 commits2025-07-13: 0 commits2025-07-14: 0 commits2025-07-15: 0 commits2025-07-16: 0 commits2025-07-17: 0 commits2025-07-18: 0 commits2025-07-19: 0 commits2025-07-20: 0 commits2025-07-21: 0 commits2025-07-22: 0 commits2025-07-23: 0 commits2025-07-24: 0 commits2025-07-25: 0 commits2025-07-26: 0 commits2025-07-27: 0 commits2025-07-28: 0 commits2025-07-29: 0 commits2025-07-30: 0 commits2025-07-31: 0 commits2025-08-01: 0 commits2025-08-02: 0 commits2025-08-03: 0 commits2025-08-04: 0 commits2025-08-05: 0 commits2025-08-06: 0 commits2025-08-07: 0 commits2025-08-08: 0 commits2025-08-09: 1 commits2025-08-10: 0 commits2025-08-11: 0 commits2025-08-12: 0 commits2025-08-13: 0 commits2025-08-14: 0 commits2025-08-15: 0 commits2025-08-16: 0 commits2025-08-17: 0 commits2025-08-18: 0 commits2025-08-19: 0 commits2025-08-20: 0 commits2025-08-21: 0 commits2025-08-22: 0 commits2025-08-23: 0 commits2025-08-24: 0 commits2025-08-25: 0 commits2025-08-26: 0 commits2025-08-27: 0 commits2025-08-28: 0 commits2025-08-29: 0 commits2025-08-30: 0 commits2025-08-31: 0 commits2025-09-01: 0 commits2025-09-02: 0 commits2025-09-03: 0 commits2025-09-04: 0 commits2025-09-05: 0 commits2025-09-06: 0 commits2025-09-07: 0 commits2025-09-08: 0 commits2025-09-09: 0 commits2025-09-10: 0 commits2025-09-11: 0 commits2025-09-12: 0 commits2025-09-13: 0 commits2025-09-14: 0 commits2025-09-15: 0 commits2025-09-16: 0 commits2025-09-17: 0 commits2025-09-18: 0 commits2025-09-19: 0 commits2025-09-20: 0 commits2025-09-21: 0 commits2025-09-22: 0 commits2025-09-23: 0 commits2025-09-24: 0 commits2025-09-25: 0 commits2025-09-26: 0 commits2025-09-27: 0 commits2025-09-28: 0 commits2025-09-29: 0 commits2025-09-30: 0 commits2025-10-01: 0 commits2025-10-02: 0 commits2025-10-03: 0 commits2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 3 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-08: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 2 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 1 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 4 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 1 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 1 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 3 commits2026-02-16: 1 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 0 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 2 commits2026-03-01: 2 commits2026-03-02: 1 commits2026-03-03: 2 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 6 commits2026-03-08: 11 commits2026-03-09: 27 commits2026-03-10: 11 commits2026-03-11: 0 commits2026-03-12: 15 commits2026-03-13: 19 commits2026-03-14: 18 commits2026-03-15: 2 commits2026-03-16: 0 commits2026-03-17: 3 commits2026-03-18: 2 commits2026-03-19: 0 commits2026-03-20: 3 commits2026-03-21: 6 commits2026-03-22: 0 commits2026-03-23: 5 commits2026-03-24: 2 commits2026-03-25: 14 commits2026-03-26: 55 commits2026-03-27: 32 commits2026-03-28: 22 commits2026-03-29: 12 commits2026-03-30: 9 commits2026-03-31: 0 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 3 commits2026-04-04: 5 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 0 commits2026-04-08: 0 commits2026-04-09: 2 commits2026-04-10: 0 commits2026-04-11: 13 commits2026-04-12: 84 commits2026-04-13: 17 commits2026-04-14: 35 commits2026-04-15: 5 commits2026-04-16: 21 commits2026-04-17: 16 commits2026-04-18: 35 commits2026-04-19: 4 commits2026-04-20: 29 commits2026-04-21: 0 commits2026-04-22: 24 commits2026-04-23: 2 commits2026-04-24: 8 commits2026-04-25: 5 commits2026-04-26: 6 commits2026-04-27: 2 commits2026-04-28: 0 commits2026-04-29: 0 commits2026-04-30: 0 commits2026-05-01: 0 commits2026-05-02: 0 commits2026-05-03: 1 commits2026-05-04: 0 commits2026-05-05: 0 commits2026-05-06: 0 commits2026-05-07: 1 commits2026-05-08: 2 commits2026-05-09: 2 commits2026-05-10: 0 commits2026-05-11: 0 commits2026-05-12: 0 commits2026-05-13: 0 commits2026-05-14: 0 commits2026-05-15: 0 commits2026-05-16: 0 commits2026-05-17: 0 commits2026-05-18: 0 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 0 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 0 commits2026-05-26: 4 commits2026-05-27: 48 commits2026-05-28: 12 commits2026-05-29: 7 commits2026-05-30: 8 commits2026-05-31: 0 commits2026-06-01: 1 commits2026-06-02: 2 commits2026-06-03: 22 commits2026-06-04: 0 commits2026-06-05: 0 commits2026-06-06: 4 commits2026-06-07: 4 commits2026-06-08: 0 commits2026-06-09: 0 commits2026-06-10: 0 commits2026-06-11: 5 commits2026-06-12: 4 commits2026-06-13: 3 commits2026-06-14: 0 commits2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 8 commits2026-06-18: 0 commits2026-06-19: 0 commits2026-06-20: 0 commitslessmore

Eleven months of quiet, then the 2026 run — the GitHub-style heatmap renders the shape of the portfolio on a single row. The brightest cell is Apr 12 (the day inference shipped). The second-brightest is May 27 — `sf`'s arcade-mechanics explosion, 43 commits in that repo alone. The cluster on the far-right edge is the move to San Francisco: six weeks of terrain pipelines, biometric crons, and a drivable LiDAR city. Grayscale by default — density is the signal — with a single spot of warmth on the busiest day. Hover any cell for the date, its commit count, and the repos behind it; the week and weekday light up so you can place it.


What changed since June 17

One commit. In seven days the entire portfolio advanced by a single commit, in flowtcg: “Add CSV import tool for bulk-seeding cards.” Having finished the game last round, the author ran into the most mundane post-ship friction there is — adding new cards meant hand-writing one JSON object at a time — and built the cure. lib/cardCsv.ts is a pure CSV parser with a compact effects DSL (damage 7; vulnerable 1, damage 4 x2; blank effects default by role), mapping rows to CardDefs validated by the existing CardDefSchema. A new app/api/admin/cards/import route re-validates server-side, bulk-upserts, and can append a per-row deck to a named character; CardImporter.tsx adds paste/upload, a New/Update/Error preview, a download-template, and a confirm step. 616 lines of content-pipeline for a game that already shipped. Everything else — sf, golf, bookmarks, gravityDopeRat, archetypes, bass, inference, minecraft-mods, kareemrpg — sat exactly where it was. (One new face in the ls: a godot/ workspace, last touched mid-2025 — not new work, but the cradle where kareemrpg was built. Logged in the footnotes.)

Lifetime commits per project

commitstotalummerr.github.io368bookmarks276archetypes160sf118inference63gravityDopeRat35flowtcg16bass10minecraft-mods9archetypes-audit8golf6dopeRatGravity2film1testExport1

Every repo the author owns, ranked by lifetime commits — regenerated live each audit. ummerr.github.io (11+ years) and bookmarks (the flagship) still lead; sf holds fourth at 118 after last round's surge. The bars barely moved this week — only flowtcg ticked up by one — which is the point: a portfolio that finished its headline and is letting it rest. Strict grayscale; the cloned-reference StreakUp is excluded.

The throughline this round is maintenance. Last round was about finishing — pushing a build through the unglamorous last 20% that a design doc can’t motivate. This round is the part that comes after finishing, and it’s even quieter: you keep using the thing, and the use generates the work. Nobody specs a CSV importer before there are cards to import; you only feel the need once you’re living inside the finished product, seeding decks by hand and getting tired of it. One commit in a week isn’t a slow round — it’s a builder maintaining something real, letting the next task announce itself instead of inventing one.


The day’s hours, plotted as a clock

The pattern is still resolutely bimodal — a late-night building wing and a morning sprint, with a dead zone in the 4–6am window where even this keyboard sleeps. The shape is the whole point. This is work that happens around a full-time job, in the hours the job doesn’t claim. Nobody schedules a game’s boss-entrance animation for 11pm; it schedules itself. (The exact spoke heights are recomputed live below — the radial reflects the repos as they stand today.)

Commits by hour of day — 24-hour radial

commitshour (00–23, local)02040608010000:00 — 19 commits0001:00 — 8 commits02:00 — 0 commits03:00 — 0 commits0304:00 — 6 commits05:00 — 96 commits06:00 — 58 commits0607:00 — 45 commits08:00 — 59 commits09:00 — 83 commits0910:00 — 38 commits11:00 — 26 commits12:00 — 32 commits1213:00 — 38 commits14:00 — 51 commits15:00 — 52 commits1516:00 — 22 commits17:00 — 58 commits18:00 — 70 commits1819:00 — 51 commits20:00 — 76 commits21:00 — 99 commits2122:00 — 60 commits23:00 — 26 commits

The warm spokes — around 8am and the late-night 11pm–midnight band — anchor a resolutely bimodal day: a morning sprint and a building wing after dark, recomputed live from every repo. The 4–6am wedge is still the only stretch the keyboard reliably rests. This is what work that happens *around* a full-time job looks like in aggregate.


The portfolio, project by project

Jump to any deep-dive below. Bold marks what changed since the last audit.

This round’s deltasFlow Slays IO — a CSV bulk-import tool for the finished game

Shipped & steadysf · golf · bookmarks · Dopamine Rat (v1 → v3) · Archetypes · inference · bass · minecraft-mods · kareemrpg · the site

Bench & footnotesVidMetaPrompt · smaller projects (now incl. godot/) · the Build-to-Think scorecard


The Headline’s Quiet Sequel: Flow Slays IO → flowtcg

Status: Playable & deployed • Commits: 16 (1 new since Jun 17) • Born: Jun 2, 2026 • This round: a CSV bulk-import pipeline Stack: Next.js 15 · React 19 · Zustand · Zod · Tailwind v4 · Framer Motion · Web Audio · Vercel Blob · Vitest

“A minimal Slay the Spire–style deckbuilder — a team toy for the Google Flow org, themed around the launch of Gemini Omni Flash at Google I/O. HP = Morale, energy = Focus, enemies = launch hazards.” — the README, describing a finished game.

Last audit, this repo was the whole story: a three-commit sketch that became Flow Slays IO — a named, deployed, drawn, scored, boss-fight-having roguelike about surviving a product launch. This round it did the thing finished software does — it asked for a tool. Exactly one commit, and it’s the least glamorous, most honest kind there is: a content pipeline.

What landed this round — the tooling tail. Adding a card to the game meant hand-authoring a JSON object; do that a few times and you build the importer. A new admin “Import CSV” panel parses a CSV of team members into validated CardDefs and bulk-upserts them. The parser (lib/cardCsv.ts) is pure and tested, with a compact effects DSLdamage 7; vulnerable 1, damage 4 x2 — and sensible role defaults (a blank attack becomes damage 5, a blank skill block 5). The app/api/admin/cards/import route re-validates server-side against the same CardDefSchema the rest of the game uses, upserts in bulk, and can append an optional per-row deck to a named character. CardImporter.tsx gives it a face: paste or upload, a New / Update / Error preview so you see exactly what each row will do before committing, a download-template button, and a confirm step. Cards stay textual-only; art still flows through the existing per-card upload. 616 lines, four files, zero new dependencies.

Flow Slays IO combat — Amar versus Scope Creep, a fanned hand of cards below
Combat, Phase 4. Amar (58 Morale) faces Scope Creep (48 Morale); the hand fans across the bottom — Sol Byte, Quinn Vega, Priya Sharma, Nina Patch, Tess Relay — each a real teammate, each just a JSON entry plus a PNG. The engine never branches on a specific card; it interprets a generic Effect[].

Still engineered like a product, not a toy. Everything card-related is data-driven: the combat engine interprets a generic Effect[] and never branches on a specific card, so adding a person is adding a row (and optionally a PNG) — no engine changes, no restart. The importer just makes that truth faster: it speaks the same CardDefSchema and the same effect vocabulary as the hand-authored path, so a pasted spreadsheet and a typed JSON object are validated identically. A whole run is still deterministic through a seeded RNG, which is what lets npm run balance headlessly simulate 20 runs × 4 characters and report win rate, fight length, and card usage. The deck is still the org; the enemies are still what breaks your build.

Build to Think verdict. Last round’s question was whether a PM finishes what he builds. This round answers a quieter one: what happens after he finishes? The honest answer is the least cinematic commit in the whole portfolio — a CSV importer — and that’s exactly why it matters. You cannot design a content pipeline before you have content to feel annoyed by; the need is invisible until you’re inside the finished thing, seeding cards by hand. A spec would never have asked for this. Using the product did. The building is the thinking, and so, it turns out, is the maintaining.


The Ongoing Headline: sf → sf.ummerr.com

Status: Shipped • Commits: 118 • Sprint: Apr 19 – Jun 17, 2026 • This round: no change (steady since last audit) Stack: Astro 5 · React 19 (islands) · Three.js 0.184 · Rapier (WASM physics) · r3f + drei + postprocessing · MapLibre GL · @turf/turf · Tailwind v4 · TypeScript · pnpm Live: sf.ummerr.com

One of the most active repositories in the portfolio, and it still committed today — 59 days after it began as a one-line README about moving to San Francisco. It is two apps sharing one repo and one obsession with SF’s actual topology.

/ — the atlas. A hand-drawn paper-and-ink map of San Francisco on MapLibre (no Mapbox token; OpenStreetMap data, free tier), DEM topography with hillshade and contours, personal waypoints layered on top: the apartment as a blueberry, family, Equinox gyms, Google offices, and toggleable layers for cafes, bars, burritos, groceries, golf, parks, microclimate, isochrones. A relocation processed as a GIS project — the way to learn a city is to draw it.

sf atlas — a hand-drawn paper-and-ink map of San Francisco with a personal legend
The atlas at sf.ummerr.com — Cole Valley rendered like an antique survey, with a legend keyed to a life: home, burritos (14 of them), cafes, bars, groceries, Equinox, Google, the Marin family. Contours and street grid are real OSM + DEM data.

/rush — the driving game. A full 3D arcade racer in the lineage of SF Rush 2049, built as a single Astro client:only React island so Rapier’s WASM and Three.js never touch the server, with the basemap’s LiDAR elevation as a heightfield collider you actually drive on. A garage of vehicles (car, motorcycle, bus, a Waymo robotaxi, a pickup, an e-bike), a panel-crumpling damage model, skid ribbons, a boost meter, stunt scoring, post-FX, a topographic minimap with district-warp buttons, and synthesized audio.

sf rush — driving a cab across LiDAR terrain with map tabs for San Francisco, Googleplex and Office
The Rush at sf.ummerr.com/rush — a cab mid-air over real San Francisco elevation. Note the world tabs up top: San Francisco · Googleplex · Office. The "Office" map landed last round — a tiny car on a giant startup-office floor.

Where it stands. Last round it grew two worlds: a living city pass on San Francisco (ambient traffic, near-miss and punt scoring, bay life, +13 streets) and a brand-new “The Office” map — a tiny car loose on a giant startup-office floor, the pluggable MapDef system stretched to its silliest. This round it sat still — last commit Jun 17. The atlas-plus-arcade is, for now, done.

Build to Think verdict. This is the thesis at full volume. There is no spec for “process a cross-country move” — there’s only the act of redrawing the city until it’s yours, then driving through it until it’s fun, then adding traffic so it feels alive. The atlas is the author learning where he now lives; the racer is what it feels like to move through it. Both are the same LiDAR data, read two ways. No design doc gets you from “I moved” to “a Waymo you can drive across a startup-office floor.” Only building does.


The Sibling: golf

Status: In development (local-only) • Commits: 6 • Sprint: May 7 – Jun 17, 2026 • This round: no change Stack: pnpm monorepo · Next.js 16 + React 19 + Tailwind v4 + Supabase (web) · Vite 6 + Three.js + lil-gui (sim) · Python: rasterio, numpy, shapely, geopandas (DEM pipeline)

sf’s quieter sibling, born from the same terrain obsession: a personal golf journal that renders the courses you’ve played as interactive 3D terrain from public LiDAR elevation models — plus an embedded Three.js simulator to eventually play those courses on the same data. The journal and the sim load the same elevation.json for every course. One source of truth.

Three layers: a Python pipeline that pulls DEM tiles from USGS 3DEP (no auth), reprojects with rasterio, masks course polygons from OSM, detects feet-vs-meters, and emits elevation.json + hillshade.png; a Next.js web app (home grid, /courses/[slug] 3D viewer with a 1–6× exaggeration slider, round-logging form, sim iframe wrapper); and a Vite + Three.js sim played inside that iframe. A 244-line DECISIONS.md records the reasoning: why raw Three.js over r3f, why an iframe for the sim, why base: '/sim-app/'.

Where it stands. Last round’s single commit was all feel: clearer hole HUD, a longer driver, more forgiving putts — the tuning notes of someone actually playing the prototype and bumping into its rough edges, not speccing it. No change this round. You can’t write “the putts feel punishing” into a design doc you haven’t played.

Build to Think verdict. The loop is explicit in the product: play a course → log the round → study its real terrain in 3D → play it in the sim. Same learning ladder as sf (it even shares Three.js 0.184), pointed at a hobby instead of a city. Two projects, one pipeline — discovered by building the first and reusing it for the second.


The Flagship: bookmarks → prompts.ummerr.com

Status: Shipped • Commits: 276 (unchanged since Jun 3) • Sprint: 96 days, Feb 28 – Jun 3, 2026 Stack: Next.js 16 · React 19 · TypeScript · Tailwind v4 · Supabase Postgres · Claude Haiku (triage) + Sonnet (depth)

Steady this round — the flagship sat at the high-water mark it reached last audit, when it did something a PM org would normally staff a team to do: measured the reception of its own launch, rigorously, and packaged it to travel. (It’s also the one project I can’t screenshot for you — the whole site is password-gated, which is itself the point.) That earlier work is worth recapping, because it’s the clearest example of the side project and the day job finally touching:

The Flow + Omni exec brief (new). A share-ready reception snapshot at /flow-brief, framed as Launch → Reaction → Landing, opening with a TL;DR positive/negative split and backing every point with an exemplar quote and a source-thread link. It surfaces the uncomfortable findings honestly — a dedicated section on safety filters overfiring (over-restriction complaints), a clustered Verbatims section of two-dozen-plus quotes, and first-hand June Reddit data folded into the table. It ships with a “Copy-as-Markdown” button (“Paste straight into a Google Doc, Slack, or email”) and named-exec references deliberately removed so it circulates without blast radius. The rest of the site is password-gated; this brief was built to be handed up.

The Omni Report, rev. 7. The underlying corpus grew to 132 posts (from 98), scored day-by-day across Reddit + tweets + open web: 66% positive / 8% negative, peaking at 72% positive on launch+4. The research instrument now runs a press desk on the day job’s own launch.

The Omni Report (new, unlisted). A build-time-rendered editorial page at /omni-report analyzing the open-web reception of Google’s Gemini Omni / Omni Flash video model. A curated 98-tweet corpus (rev. 6, grown from 79) across nine source clusters plus a Reddit deep-dive of ~140 threads. The data tells a story of a narrative flip: the launch-day verdict was “worse than Seedance”; within days the framing pivoted to “fundamentally a video editor, not a generator — Nano Banana for video.” Server-rendered SVG sparklines, numbered executive-summary cards, sentiment-by-day tables with inline %-bars (66.3% positive, +57 net), noindex‘d and absent from the nav. It is the first time the site tracks a specific competitor’s launch rather than the field in aggregate — the research instrument grew a press desk.

Dataset slicing (new). Four derived sub-datasets — T2I, R2I, T2V, R2V (text/reference × image/video) — each at /dataset/[slice] with its own stats and independent JSONL/CSV/JSON downloads, backed by SQL predicates over prompt_category and requires_reference. A shared lib/datasetSchema.ts centralizes the 27-field canonical schema so master and slices can’t drift; old ?slice=-less download URLs still resolve to the master set.

Research export (new). A ?variant=research flag strips PII (tweet_text, author handle/name, media_urls) while retaining tweet_id for rehydration — GDPR- and ToS-compliant academic sharing, exposed as a radio toggle in the download modal.

The access-gate detour (added, then removed). Apr 23–25 saw a client-side password gate, then a fake-404 overlay shown on every page load. Both were stripped by May 27 (Remove fake-404 gate overlay from site). The site is fully open again — a small, public, reverted experiment, the flagship’s signature move.

Everything load-bearing still loads. Two-tier classifier (Haiku triage, Sonnet depth), Chrome extension (Manifest V3), Image-to-Prompt reverse tool, quality audit, dataset datacard, methodology page, State of Prompting essay — all live, all free-tier.

Build to Think verdict. A mature project keeps discovering surfaces it couldn’t have specified. “A Chrome extension for bookmarks” became a dataset became an editorial became a competitive-intelligence desk with compliance affordances. The Omni Report is what it looks like when the day job (a PM on Flow, an AI video product) and the side project finally touch: the side project now reports on the competition, in public, for free.


The Long-Running One: ummerr.github.io

Status: Shipped (continuously, since 2014) • Commits: 367 • Lifespan: 11.7 years Stack: Jekyll • GitHub Pages • Bulma + custom CSS + Tailwind v4 • Geist + Instrument Serif

The heartbeat of the portfolio. Every other project ships through or alongside this site. 11 published essays, 10 portfolio case studies (Amex, Tradesy, Breazy, Kollider, Level, TheKind, Battle Bakery), a film photography gallery, a split-pane markdown editor with localStorage auto-save, and a 57MB Godot WebAssembly game embedded because at some point it became easier to embed it than not.

Tuesday is still the giant — 81 commits, 43% of all weekday activity. Noon peak. The daytime counterweight: the site is the writing project, everything else is the building project.

As ever, the site mostly carries other repos’ news: its recent commits are audit posts themselves (Regenerate project audit …). It’s the publication layer for its own telemetry — including this very page, which lands here as the next commit. It also hosts the screenshots in /images/ from last round, when the audit started shipping pictures of the work alongside the count of it.


The Trilogy: The Dopamine Rat (v1 → v2 → v3)

A habit tracker starring an emotional pixel rat. Steady this round, but worth keeping on the board: three versions trace a philosophy pivot from gamification to harm reduction, and v3 (gravityDopeRat) grew a nervous system. Across six deployed phases (Apr 26 – May 8), the tracker that once only knew what you told it learned to read what your body did: a Hevy auto-pull every four hours (strength workouts log themselves as auto-strength), a Garmin cron (10am + 9pm ET, pulling HRV / body battery / resting heart rate), and a vitality-compute engine (Sleep 0–40 + Recovery 0–30 + Training 0–30, with mismatch flags) that rewires the rat’s emotional state to biometrics. Then a cull: manual fitness and sleep-duration scoring removed, the dashboard recomposed, a Zustand persist migration (v3→v4) adding an overrides slice. 35 commits on the mainline.

The trilogy — a philosophy by subtraction

V1 · FEB 2026 codexDopeRat ~700 activities · 0 commits "grind for points" Lab Rat → Free Rat V2 · FEB–MAR 2026 dopeRatGravity 38 components · 2 commits "every tool that fits" Claude API + WebLLM + Supabase V3 · MAR–MAY 2026 gravityDopeRat 35 commits · +sensor layer "measured recovery" Garmin + Hevy · vitality scoring · cron pulls

v1 named the problem. v2 tried every tool that sounded relevant. v3 asked what actually helps someone recover? — cut everything that didn't, and then learned to measure what's left: Garmin HRV, body battery, Hevy lifts, a subjective sleep tap, reconciled into one vitality score. The pivot from grind for points to measured recovery could not have been written down in February. It had to be built, used, and re-built.

The v3 mechanics underneath the new sensor layer: a 5-mood × 6-emotional-state × trajectory engine; blended scoring; urge surfing with a 20-minute timer and tiered partial credit; parent mode; harm-reduction physics (edible above spliff; alcohol escalates at drink 3+); offline-first with an async Supabase sync queue. Deployed on Vercel Node functions with three cron schedules (heartbeat, Hevy pull, Garmin pull). You could not have specified “reconcile a Garmin body-battery reading against a subjective sleep tap and a Hevy lift log” in February, because in February the product didn’t yet know it was a recovery instrument. It learned that by being used.


The Experiment, Doubled: Archetypes (v1 + v2)

It began life as a “single-commit experiment,” grew into a “mobile-iconography endgame,” and back in April reached feature-completeness — a full Quiz + Reading assessment flow — and then stopped. Silent since Apr 23, and silent again this round. The project finished; the author’s attention moved on (first to a moving truck, now to a card game). Notable mostly because of how it was built: v1 (archetypes, on GitHub) was written entirely on the Claude Code mobile app, thumb-typed, as an experiment in whether a real app could be built without a laptop. The answer turned out to be yes.

Archetypes — breadth → depth

V1 · BREADTH 10 systems × 3 interfaces vanilla JS · 5-day mobile sprint · 13 commits across 5 branches Jng Enn MBT Tar WZd CZd Grk Hin Nrs Kbl Compare Constellation Swipe "Can I map every system on a phone?" Built entirely on the Claude Code mobile app. V2 · DEPTH 6 systems × 37 routes Next.js + Three.js + Framer · desktop sprint · 163 commits KWML Jung Enn MBTI Tarot Hero "What if I pick six and treat them as editorial?"

Left: ten archetypal systems spread laterally, three interfaces beneath them, all drawn with vanilla JS on a phone. Right: six systems chosen, each given vertical depth — KWML as the pedagogical spine, plus an Atlas layer for cross-system mappings, a Mirror for shadow prompts, a Profile for cross-system tensions, and a Today surface for daily archetype. The decision to go deep was only thinkable after the wide version had shipped.

v2’s grammar. A DESIGN.md enforces a shared visual language across all six systems: KWML uses 3D platonic solids with bloom; Jungian organic forms; Enneagram instruments; MBTI animated cognitive glyphs; Tarot halos; Hero’s Journey silhouettes. Four motion primitives (breath, spin, pulse, shimmer) defined once. Five semantic totem scales (xs–hero, 22–200+ px) with animation budgets. Cards layer frame → field → token. This is the part where the project becomes serious.

v2’s editorial scaffolding. Debates taxonomy (confidence/impact/status fields). Exemplars network with source attributions — /atlas/exemplars was just expanded by 25 figures with a tiered index. A weak-hermeneutic methodology page with pipeline infographics. Citations linked from debates back to bibliography entries — a real graph, not a citation theater.

What +44 commits looks like. The assessment flow. /quiz (landing), /quiz/take (stratified item draw, a Likert scale with a gold spine and warm gradient, section progression, resume/undo), and /quiz/r/[code] — an editorial “Reading” spread with a constellation centerpiece and URL-encoded answers. Feature-vector visualizations (radar + resonance network) wired into all six archetype detail pages, rich snippets across every page, the completion screen previewing your cast and routing into the Reading. The pixel-level polish stayed (Likert spine snapped to whole-pixel rows, axis-label clip fixes) right up to the last commit on Apr 23.

Build to Think verdict. v1 asked can I map every system on a phone? v2 asked what if I pick six and treat them as editorial? — and, with the quiz, finally answered the question the editorial implied: how does someone find their own archetype? The assessment was the last thing built and the only thing that turns a beautiful reference into a usable tool. That it shipped and then went quiet is itself a data point: the project reached completeness exactly as a cross-country move arrived. It is still pre-launch — Vercel-ready, no public domain yet.


The Mods: minecraft-mods

One directory, two projects, two entirely different personalities.

MTL Memories (Forge 1.20.1, Java 17). A nostalgia mod for Montreal and McGill 2004–2008. 14 custom items (poutine, Montreal bagel, smoked meat, Gerts token, Arcade Fire vinyl). 5 quest storylines. Status: exploratory. The quest framework runs, but it’s a foundation without the visual layer — which is roughly the state of memory itself.

LabsCraft (Fabric 1.21.4, Java 21 + a Node.js agent server). An LLM-powered mod simulating an APM internship at “Google Labs” on an AI video product called “Flow.” The centerpiece is Josh Woodward, a PM NPC whose dialogue is generated by Claude Sonnet (Gemini fallback). This is exactly as on-the-nose as it sounds, which is the point.

The mod (46 Java files, 5,391 LOC) sends world state every tick via HTTP to an agent server (13 TS files, 1,394 LOC) running Express on port 3001. Six trigger types (chat, interaction, idle-near-objective, quest-complete, danger, periodic proximity). SQLite stores conversation history, top-5 extracted memories per player, and quest state. Memory extraction every five conversations; summarization at threshold. Josh’s character brief: deadpan PM humor, references to syncs/sprints/P0s/OKRs, max three sentences per turn. Status: shipped — built jar at build/libs/labscraft-1.0.0.jar, 148 unit tests, three Claude worktrees active during the build.

Build to Think verdict. Two modes sharing a disk and nothing else. MTL Memories is pure nostalgia-as-enumeration: the act of listing what to include is the project. LabsCraft is the technically serious frontier — an agentic NPC architecture (perceive → decide → reason → execute) with per-player memory and multi-provider LLM fallback, emerging from iteration.


The Gift: kareemrpg

Shipped on itch.io. A birthday gift for a friend named Kareem. Five learning projects in 16 days, each one existing solely so the next one could exist:

kareemrpg on itch.io — a Godot game loading, above a note about celebrating Kareem's 40th birthday
Live at ummerr.itch.io/kareemrpg — a real Godot game, exported to WebAssembly. "We are celebrating Kareem's 40th birthday, using this game as a chance to reflect on where we have been and where we came from." Zero Godot experience to a published, playable gift in 16 days.
  1. learningproj (May 24) — first GDScript, 25 lines, “what is a node?”
  2. kareemrpg-beta (May 24) — mobile RPG skeleton
  3. dialogictut (May 25) — Dialogic addon + NPC basics
  4. daytworpg (May 25) — 9 scripts, dialogue, audio, NPC/follower systems
  5. dialogictutotrial (Jun 9) — final game: 66 scripts, 68 dialogic files, 29 scenes

Exported as WebAssembly, published on itch.io, embedded at ummerr.com/kareemrpg. The fastest build-to-learn cycle in the portfolio: from zero Godot experience to a published game in 16 days. The learning ladder is the project history — if you opened the directory cold you could reconstruct the syllabus from the timestamps alone.


The Explainer: inference → inference.ummerr.com

Status: Shipped • Commits: 63 • Last commit: Apr 17, 2026 Stack: React 19 · TypeScript · Vite · Tailwind v4 · Lucide React Live: inference.ummerr.com

“The Fun Inference Calculator.” An interactive web explainer for generative AI compute costs across modalities. Unchanged since the last audit — shipped, stable, and still doing its job. All 12 sections live: Frontier Frictions, Lifecycle, Techniques Ladder, Forward Bets, Failure Modes, Unit Swap, Hidden Costs, Cost Drop Tracker, Video Price Watch, Silicon, Batch vs Realtime, Napkin Math Playground.

inference.ummerr.com — an editorial explainer asking what it costs to generate a picture, a video, audio, a world
inference.ummerr.com — "What does it actually cost to generate a picture, a video, a bit of audio, a world?" An explainer that reads like a magazine spread, not a calculator.

Build to Think verdict. The third audit doesn’t change the verdict — it reinforces it. A one-day explainer became a six-day site; the “Cost Drop Tracker” could only be imagined after the calculator existed. Specs don’t generate second-order surfaces. Only running code generates second-order surfaces.


The Ritual: bass

Status: Live structure (unshipped domain) • Commits: 10 (+6) • Last commit: Apr 20, 2026 Stack: Next.js (App Router) · TypeScript · Tailwind v4 · pnpm · flat markdown content · zod

Born the day of the last audit, bass got two more days of attention before the move arrived. A personal site that scaffolds a daily 15 minutes of bass practice — not a content library but a daily loop: warm up → skill of the week → fretboard minute → play something fun → log it. Git is the streak tracker. All content is flat markdown.

What the six new commits added: a real tab system. A tab library with a color-per-key palette tied to the circle of fifths; a zod-validated structured tab schema (Phase A); a three-view reader — beat grid / ASCII / fretboard (Phase B); a guided practice path; and a 30-tab library with “Start here” grouping. Then, on Apr 20, it stopped.

What shipped in v1. / — the daily loop: five numbered steps + streak + 90-day heatmap + explore nav. /lessons — ten beginner lessons with status badges (not-started / learning / practicing / comfortable / retired). /lessons/[slug] — lesson detail. /fretboard — fretboard explorer, beginner-default (neutral dots, note-name labels, four presets: All notes / C major / A minor / E minor pentatonic); “Show advanced” reveals 12 roots, 5 scales, degree/interval labels. /drills/fretboard-notes — silent note-recognition drill, two modes (Name→Fret, Fret→Name), 12 prompts per round, single-string SVG. /log — copy-template flow for today’s practice entry, filename hint, recent-entries list. URL presets supported: /fretboard?preset=c-major.

The pedagogy. A PLAN.md file — 15KB, six build phases, references to BassBuzz / Scott’s Bass Lessons / StudyBass / TalkingBass / Justin Guitar / Berklee / Fogg & Clear habit-formation science — enumerates the thesis before any code:

“The site is not a content library. It is the scaffold around Ummerr’s daily 15 minutes with the bass in hand.”

Six principles are written down explicitly: beginner-first defaults, one next action, silent-first (no audio in v1), git is the database, progress must be visible (heatmap, lesson-status transitions, streaks), pedagogy over features. The site’s home page is the five-step loop. Not a dashboard of features — the loop itself.

The AGENTS.md reveal. A single file in the repo, eight lines:

“This is NOT the Next.js you know. This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.”

That one file — a one-sentence correction to the agent’s priors — is a complete Build to Think artifact: the author noticed the tool’s training data was stale, wrote down the correction in eight lines, and moved on. No meeting. No ticket.

Build to Think verdict. The clearest Build to Think instance in the entire portfolio, because the product is literally the loop that Build to Think advocates: a daily 15 minutes with an instrument, logged in markdown, streak-tracked by git. The site isn’t for visitors. It’s a personal scaffold that happens to be public because it’s easier to ship Next.js on Vercel than to build a bespoke tracker. Five small things, ≈15 minutes, skip any of them. Showing up is the win.

That it paused mid-stride doesn’t undercut the thesis — it’s a personal scaffold, and personal scaffolds wait for you. The tab reader is now there for whenever the bass comes out of its case in the new apartment. bass joins bookmarks, inference, and the Dopamine Rat as a tool whose use is indistinguishable from its design.


The Test Bench: VidMetaPrompt

A framework for transforming high-level creative video ideas into structured 7-component prompts for Veo-3 generation. Modular: Analysis Engine, Knowledge Base, Character Builder, Generation Engine, Quality Validator. 15+ implementation modules; UI scaffolds exist and are empty. Where bookmarks discovered its shape through deployment, this one discovers its shape through tests. Same principle, different probe.


Footnotes: smaller projects

cursorMint — Personal finance tracker. Loads bank CSVs, standardizes transactions, stores in SQLite, plots spending. ~350 lines. No git. Functional utility — it exists because the alternative was a SaaS that would have cost more than the groceries it tracked.

godotNew to the ls this round, but not new work. A 2025-era Godot workspace — kareemrpg-beta, daytworpg, two Dialogic tutorials, learningproj — last touched mid-2025. No git history of its own. It’s the cradle where kareemrpg (the shipped birthday gift on itch.io) was learned and built, surfaced now only because the audit re-scanned the directory. A delta in the listing, not in the work.

film — Astro 6 photography portfolio scaffold. Single commit. Template stage.

StreakUp — Cloned from rezahedi/StreakUp as an architectural reference. This is not my code. A production-quality habit tracker studied for patterns (CRUD flow, streak lifecycle, timezone handling, Prisma schema design).

testExport — Godot web export test. Binary artifact. Not a development project; it’s evidence.

dopRatTest — An empty directory. The most honest project in the portfolio. It knows it doesn’t exist.


The Build-to-Think Scorecard

Every project started without a spec. The interesting column is the right one — what only became visible because building forced it into the open.

Spec → Reality — the gap building made visible

bookmarks a Chrome ext for bookmarks a competitive-intelligence desk Dopamine Rat a point tracker "measured recovery" — reads your body archetypes v1 "can I build on a phone?" 3 interfaces, mobile-native archetypes v2 "pick fewer, go deeper" a quiz-complete Three.js platform inference a one-day explainer a 12-section pricing handbook LabsCraft "what if an NPC had memory?" a full agentic architecture, per-player kareemrpg "learn Godot for a birthday" 5 projects in 16 days, shipped MTL Memories "what do I remember?" enumeration as the project VidMetaPrompt started with tests discovering shape through TDD bass "15 min of bass a day" site = the loop · git = the streak ummerr.github.io started 11 years ago still the place every project lands sf ← NEW "a log of my move to SF" a LiDAR atlas + drivable arcade city golf ← NEW "render the courses I play" a DEM pipeline + 3D viewer + sim SPEC REALITY

Every project started with code, not a spec. Constraints taught. Writing followed building. The arrows are the gap building made visible — and the two newest, sf and golf, are the clearest of all: you cannot design a move into a repository, you can only build it.


Closing

Seven audits in, the lineage has a rhythm, and this is its quietest beat: one commit in seven days. It would be easy to read that as nothing happening. It’s the opposite — it’s what finished looks like. Last round closed with a game shipped; this round opens with the game still shipped, and the only new work is the small, unasked-for tool that using a finished thing eventually demands. A CSV importer is not a headline. But it’s the most faithful Build-to-Think artifact in the whole round, because nobody could have specified it in advance — the need was invisible until someone sat inside the product and got tired of typing.

That’s the half of the thesis the loud rounds hide. New repos and launches are easy to narrate; the unglamorous after — maintaining, tooling, smoothing the friction you only feel once the thing is real — is where most side projects quietly rot instead. This portfolio didn’t rot this week. It noticed an annoyance and built the fix, then stopped. One commit, scoped exactly to the problem, and not a line of busywork to make the audit look busier.

No design doc asks for a content pipeline. Only a finished product, in use, does. The building was the thinking; this week, the maintaining was too — and the smallest commit in the lineage is the clearest evidence yet that the loop is real and not just productive when it’s exciting.


This audit was generated by Claude Code across 3 filesystem locations and 20 repositories, inspecting ~1,073 commits. Screenshots captured with headless Chrome via Puppeteer. Zero permission prompts, by design. To regenerate, run /audit from ~/CodeProj/.