What it is
A live, public brownness meter: one big orb, a 0-100 percentage, and a word that says what the number means — from 'nothin brown here' to 'MAXIMUM BROWN'. It updates itself on every open screen the moment the owner moves it: log in at /admin, push the slider, and every watcher's tab changes on its own over a server-sent-events stream, no refresh. 8 bands x 8 words = 64 phrasings, each band with its own 'as brown as ___' comparator and rotating flavour lines (75% still reads ouuuu). Plus today's + all-time peak records (breaking one flashes NEW PEAK), a public reaction bar (ouuuu / meh / i'm dead — one tap per visitor per minute, counts pushed live), and an optional 'vibe mode' where the hourly cron drifts the meter 1-9% on its own. Installable (inline SVG icon + manifest) and shareable (og: preview tags). One worker.js, zero dependencies, 173/173 assertions. Built after the class in-joke Netlify page of the same name could not be found — so it was made instead.
Version history
Straight from the project’s own card data — what each version added.
Worker + KV with a password-gated admin panel; public page, /api/rate, live push, logout that really revokes (KV session generation).
Admin panel rebuilt: slider, presets, nudge, undo, change history + stats; 2-second micro-cache so N viewers cost one KV read per TTL; 117/117 tests.
24 words -> 64 (8 per band) with 'as brown as ___' comparators and flavour lines; daily + all-time peak records; public reaction bar with live counts; hourly auto-drift 'vibe mode' via cron; inline icon + manifest + og tags; 173/173 tests, live-verified (429 on a repeat tap, real SSE stats push).
Files on the site
What broke, and what I’d change
Not written yet. This is the part only I can write — what actually went wrong, and what I’d do differently. It lives in builds/reflections/brown-meter.md (see _TEMPLATE.md); as soon as that file has words in it, this section fills in on the next build.
Everything else on this page — the spec, the version history, the file counts — is generated from the project’s own build notes and files, so nothing here is guesswork.
Build spec
The project’s own build notes, rendered. Open the raw .md ↗
Show the spec
The Brown Meter — a live brownness meter on a Cloudflare Worker
A public page that shows exactly how brown something is, on a 0-100 scale: one big icon, a percentage, and a word that says what that number means. The owner logs in at /admin and pushes the slider — and every open screen changes by itself, over a server-sent-events stream, with no refresh.
Live
- App: https://brown-meter.isaac1804.workers.dev
- Admin:
/admin— password-gated (credentials kept out of the repo, 0600 file on disk) - Backend: Cloudflare Worker
brown-meter+ KV namespaceBROWN - Free tier only: no card, no build step, no dependencies — one
worker.jsfile.
Where it came from
The original job was to find someone else's Netlify page called "Brown Meter" — a class in-joke whose exact URL could not be recovered. Rather than keep hunting for a link, the meter was built properly, on Isaac's own domain, and it came out better than the joke.
What it does
- 8 bands, 64 words. Every band has eight phrasings, its own "as brown as ___"
- Live, not polled.
/api/streamis a real SSE endpoint; a change is pushed to every - Records. Today's peak and the all-time peak are tracked in KV. Beat one and a
- A public reaction bar. Visitors tap ouuuu / meh / i'm dead; counts push live to
- Vibe mode. Optional hourly cron tick that drifts the meter 1-9% on its own,
- Installable + shareable. Inline SVG icon, web manifest,
og:link-preview tags. - Honest admin panel. Slider + presets, nudge buttons,
🎲 surprise me, undo (a real
comparator and rotating flavour lines — nothin brown here → a hint of beige → hmm → ohh → ohhhh → ouuuu → OUUUUUU → MAXIMUM BROWN. The canonical word is biased to the front of the rotation so 75% still reads ouuuu.
viewer in the same tick. Clients reconnect + fall back to polling if the stream dies.
"NEW PEAK!" flash drops onto the public page.
everyone. One tap per visitor per minute (hashed IP + 60 s cooldown, 429 with a countdown), and the client never gets to name the counter.
bouncing between 8% and 97% instead of sticking to a wall. Off by default — when it is off the cron costs a single read and does nothing.
toggle, not a fake stack), a recent-changes list, and a wipe button for the reactions.
Build path
- V1 — Worker + KV, password-gated admin, public page,
/api/rate, live push, logout - V2 — admin panel rebuilt (slider, presets, history, stats); a 2-second in-isolate
- V3 — 24 words → 64; "as brown as" comparators; daily + all-time peaks; public
that actually revokes (a KV session generation bump).
micro-cache so N viewers cost one KV read per TTL; screenshot + live verification.
reactions with live counts; hourly auto-drift; icon + manifest; 173/173 assertions.
Verified, not assumed
173/173 offline assertions (fake-KV harness: bands, rotation, sessions, lockout, undo, records, reactions, vibe ticks, icon/manifest). Live: reaction tap returns 200 then 429 for the repeat, a captured SSE stream really carried the stats event, the mode toggle flipped vibe → manual and the public badge followed, and the admin password appears zero times in the public HTML.