Every Goose show, every night. Setlists with segues and jams, songs, venues, tours — and statistics that don't overstate what the numbers say.
The statistics pages don't use a chart library. Every mark is hand-rolled SVG, because each question gets the form its number actually is — a duration is drawn as a length, a cycle as a dial, a level as a meter.
Screenshots above are from 2026-07-13, before the pen & instrument redesign — the forms they show (rings, dials, meters, tape) are still how these charts draw; the colors and chrome around them are not. Current look: gooseindex.com/stats.
The catalog profile — the stats hub opens with every played song ranked by plays, as one stepped shape: a steep head of staples, a long flat tail. The cuts are bracketed onto it (Most Played is the head, the rarity ceiling marks the tail), and the one yellow reading is the rank where the running total of plays crosses half — how few songs carry half the nights. Each cut beneath it then shows its first lines in the number's own form: a count as a length, a gap as a closing ring, debuts as columns by year.
Three rules hold across all of them. A change that breaks one is a bug, even if it renders.
- Each question gets the form its number is. Duration → length. Cycle → dial. Sequence → setlist notation. Level → meter. Gap → a closing ring.
- Color means exactly one thing per section. On The Shelf it means how long since the last play — which is why the tape is graphite and only the ring is lit. Ink follows significance: the song that most deserves your attention carries the most of it.
- A claim never travels without its evidence. Skewed data is log-scaled (gaps span 88–1367 days). Where the data is too thin to be honest about, the chart draws nothing rather than something misleading.
Five roles carry that color, and each keeps to one job everywhere on the site:
| Role | Carries |
|---|---|
--steel |
Field and structure. |
--hand |
The reading, now — marks only (a dot, a stroke), never running text. |
--ember |
Heat and overdue — the one amber allowed as text (--hand never is). |
--spruce |
Links, and the footnote marks that pair with them. |
--pencil |
The human margin — captions, footnotes, the caveat channel. |
--hand on running text is the bug this split exists to catch; the suite greps for it.
| Shows | Every show, with full setlists — segues, jams, track times, footnotes — plus the tape above. |
| Songs | Per-song history: every performance, gaps, debuts, bust-outs, covers. |
| Stats | Six cuts — Most Played, Rarities, Most Overdue, Debuts, Set Stats, and Oracle. |
| Browse | By venue, tour, year, and On This Day. Full-text search. |
| Live | While a show is on stage, the setlist re-pulls from elgoose and the page refreshes itself. |
| Blog | Notes from the desk. Markdown files in the repo, a bespoke engine (lib/blog/), full-post RSS. Authoring guide: docs/BLOG.md. |
Scale, as of 2026-07-13: 823 shows played (from 2014-09-27), 615 songs, 592 venues, 7,504 performances. These grow nightly — live counts are on /stats.
Every page renders in one of three editions, chosen from the gear in the header and remembered per visitor:
| Edition | What you get |
|---|---|
| 3.0 | Charts, hand-drawn, light and dark. The default. |
| 2.0 | Same charts, glossy skin — striped ledger rows, classic blue links, gel buttons; its own period-literal palette, independent of the fog/slate values above. |
| 1.0 | Plain document, no charts. |
Appearance is a 3.0-only switch, and it's two fixed looks, not a wardrobe of named themes: fog (light), slate (dark), or auto (follows the OS — the default). 2.0 and 1.0 each render a single fixed look.
elgoose.net ──(nightly Action: npm run sync)──▶ Supabase Postgres ◀──(reads)── Vercel (Next.js) ──▶ visitors
The web app only ever reads. Catalog queries are cached for an hour, so most page loads never touch the database; a live show busts just that night's cache. Every write happens out of band in the sync job, so page loads never depend on the elgoose API being up.
- Next.js (App Router) + TypeScript — server-rendered. No client-side charting library; every chart is SVG against role tokens, so it reskins with the edition and, inside 3.0, with fog/slate.
- Postgres + Drizzle — a cached copy of the live-performance record.
- Vitest — the suite runs fully offline (fixtures + in-memory PGlite). No network, no database.
- Vercel Web Analytics — cookieless page views, on every edition.
Getting started
Needs Node 22+ and Docker (or a native Postgres 16).
npm install
npm run db:up # local Postgres via docker compose
npm run db:migrate
npm run sync # pull elgoose.net -> Postgres
npm run verify # expect: VERIFY OK
npm run dev # http://localhost:3000Checks: npm test (offline) and npm run typecheck.
The band's liner notes ("From the coach's desk") come from Bandcamp via a separate pipeline —
the site works without them. Full detail in docs/SETUP.md.
Deployment
Vercel (Next.js) reading from Supabase (managed Postgres). Full runbook in docs/DEPLOY.md.
Two things worth knowing up front:
- Production builds migrate before they build.
vercel-buildrunsdb:migrate && next build, so the schema can't lag the code that depends on it. A bad migration fails the deploy instead of shipping a broken route. - Preview builds deliberately do not migrate. Previews read the production database, so letting them migrate would let any pushed branch alter the production schema before review. A preview of a schema-changing branch will 500 on the new route until it merges. That's expected.
Roadmap
| Phase | Status | |
|---|---|---|
| 0 | Data foundation — sync elgoose → Postgres, verified | done |
| 1 | Shows & discovery — setlists, search, On This Day, upcoming | done |
| 2 | Songs & stats — per-song pages, song index, /stats cuts |
done |
| 3 | Jam & set-flow analytics — segue lines, jam density by night and venue, the shelf | Oracle ships the first cut; era-aware analysis still open |
| 4 | Fan tracking — shows I've seen, personal stats, song life-list | planned |
Design specs per phase: docs/superpowers/specs/.
Non-commercial fan project, not affiliated with Goose.
Live-performance data comes from the community database at elgoose.net
(the keyless v2 API), is cached locally, and is credited on
every page. Show notes under "From the coach's desk" are the band's own liner notes, scraped from
their official Bandcamp releases — see
scripts/README-bandcamp.md.
Inspired in spirit by dmbalmanac.com. Full data landscape:
docs/research/2026-06-26-data-landscape.md.
The code is MIT.
The data is not mine to license. Setlists, shows, venues and songs belong to the elgoose
community; the coach's notes belong to the band. MIT covers what's in this repository and
nothing more — see NOTICE.
Made by Tim VanBenschoten.



