Skip to content

Repository files navigation

Shelf Life 📚

The daily book-spine poetry game. Every day at midnight Eastern, the Daily Shelving Society puts ten real books on the returns cart. Pick five, arrange them so the spines read like found poetry, and shelve it. Then judge anonymous head-to-head matchups from other players — the society's votes decide the day's canon.

Play it: shelflife.cortech.online

How Not to Die
After All
Into the Wild
No One Belongs Here More Than You
The Living Mountain
№ 15, found on shelf

How it works

  • Shelve — tap books from the cart (or drag to reorder) into 5 slots; the catalog card previews your poem. One shelf per player per day.
  • Vote — pairwise "this one's funnier" ballots on anonymous shelves. 3 ballots unlock the rankings; 20 per day max. No self-votes, each pair judged once.
  • Ranks — live standings by smoothed win rate (w+1)/(n+2); finalized at the midnight-ET rollover.
  • Card — your streak, played-days calendar, career record, past shelves, share card, and the opt-in daily reminder.

The deck is drawn deterministically per day (seeded RNG) from a curated dataset of 1,001 real book titles tagged as openers, connectors, punchlines, and wildcards — so every day's cart can actually make poetry.

Stack

One Cloudflare Worker (Hono + TypeScript) serving a vanilla-TS Vite frontend via Workers Static Assets, with D1 for persistence and an hourly cron that finalizes completed days and sends the daily Web Push tickle (VAPID via WebCrypto, payload-free). Anonymous identity: HMAC-signed player tokens; every game rule is enforced server-side. Full architecture: docs/superpowers/specs/2026-07-28-shelf-life-design.md.

Development

npm install
npx wrangler d1 migrations apply shelflife --local
node scripts/seed-titles.mjs        # seed 1,001 titles locally
echo 'TOKEN_SECRET=dev-secret' > .dev.vars
npm run build && npm run dev        # wrangler dev on :8787

Gates (all must pass before merge): npm run typecheck · npm test (vitest + @cloudflare/vitest-pool-workers against real D1) · CI runs both on every PR.

Deploy

CI=true npx wrangler d1 migrations apply shelflife --remote
node scripts/seed-titles.mjs --remote
npm run deploy                       # builds + deploys, custom domain + cron
node scripts/smoke.mjs https://shelflife.cortech.online && node scripts/clean-smoke.mjs --remote

Secrets (once, via wrangler secret put): TOKEN_SECRET, VAPID_PUBLIC, VAPID_PRIVATE, VAPID_SUBJECT.

After a deploy that touches push code, prove delivery end to end — a throwaway player subscribes through the live app in headless Chrome, the real push service accepts a payload-free tickle (HTTP 201), and a gone-stale subscription is pruned from push_subs (HTTP 410 → row deleted, asserted in D1):

node scripts/push-e2e.mjs && node scripts/clean-smoke.mjs --remote

Full runbook (flags, requirements, troubleshooting) in the scripts/push-e2e.mjs header. It never touches real players' subscriptions: POST /api/push/verify only tickles the caller's own.

Quality gate

Releases are judged by an independent LLM critic (scripts/critic.mjs): a fresh-context Codex CLI session reviews a clean checkout plus a live production capture and scores gameplay, mobile UX, multiplayer integrity, performance, and spec completeness 1–10. Reports live in critic-reports/. Ship bar: every category ≥ 8 on two consecutive cycles.


Built with Claude Code. Book titles are facts; the books belong to their authors, whom we thank for the poetry.

About

Shelf Life — daily book-spine poetry game. Pick 5 real titles, make the shelf read like it means it, judge your neighbors.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages