A self-ranking sustainability game for Burning Man theme camps. Each spin of the wheel plays one of six sectors — Food, Water, Waste, Transport, Shelter, Power — answering its ten Yes/No questions across four progressively harder tiers. Every Yes fills one segment of that tier's ring — gaps are fine, there's no penalty for a skipped question. Six spins, one per sector, build your camp's unique Green Radius.
Live at https://greenradi.us.
The mechanics and copy come from the Green Theme Camp Community's BLAST framework; this implementation began from a Claude Design handoff bundle.
- Play two ways — spin the wheel one sector at a time (board-game mode) or fill the whole thing out as a form. Same questions, same scoring.
- Six sectors, four tiers each — Food, Water, Waste, Transport, Shelter, Power, with each tier asking for more than the last.
- Shareable result card — every finished game gets a permanent link
(
/result/…) with a rendered card, handed to the OS share sheet or copied to post. - Green-Up Plan — on the done screen, every "No" becomes a concrete next-year suggestion, grouped by sector.
- Public city tally —
/city/rolls every camp's results into one community-wide radius, aggregate-only, no login. - Printable board game —
downloads/has PDFs for playing on paper at camp, no phone required.
- Static HTML + Preact (via preact/compat, UMD, vendored same-origin in
vendor/, exposed under the React names by a shim); the game's.jsxsources are precompiled to classic-runtime JS by a small Bun build step (scripts/build.js) into committeddist/artifacts, which the browser loads directly - No bundler, no npm — the compile step is one Bun script, not a build pipeline
- A small Cloudflare Worker (
worker/index.js) backs seven dynamic routes:POST /api/complete(saves a result row to a Google Sheet and emails the camp a shareable link),POST /api/event(anonymous funnel telemetry, log-only) andPOST /api/client-error(client-side error beacon, log-only), the Cloudflare Access–gatedGET /api/admin/responses(the read path behind the internal admin viewer),GET /api/city(the public, aggregate-only community tally behind the/city/page, colo-cached ~5 min),GET /result/?r=…(rewrites the result page's Open Graph title and description for a per-camp share unfurl, pinned to the Worker viarun_worker_firstinwrangler.jsonc), andGET /api/health(a liveness probe for the external uptime monitor). Everything else is served as static assets. - Deployed on Cloudflare Workers + Static Assets
| Path | Role |
|---|---|
index.html |
Entry point; mounts <GreenRadiusGame/> |
green-radius.jsx |
Main game component (GreenRadiusGame) — game state, done screen, Green-Up Plan; loads last |
src/ |
The rest of the game UI (shared global scope): core, fx, badge, wheel, question flow, share card, home, form mode, plus per-page boot scripts |
dist/ |
Committed, compiled classic-JS artifacts (built by scripts/build.js from the .jsx sources) — what the HTML entry points actually load |
game-data.js |
window.SECTORS — sector / tier / question content |
result-state.js |
window.ResultState — encode/decode a result to/from the ?r= share payload (legacy #hash fallback) |
result/ |
Stateless shareable result page |
city/ |
Public community-progress page (/city/), rendered from GET /api/city |
admin/ |
Internal Cloudflare Access–gated response viewer (City + Camps), read-only |
worker/ |
Cloudflare Worker — eight routes: /api/complete, /api/event, /api/client-error, /api/admin/responses, /api/admin/visit, /api/city, /api/health, and the /result/?r= OG unfurl |
vendor/ |
Pinned Preact runtime (+ React-names shim), served same-origin |
robots.txt, sitemap.xml, llms.txt |
Crawler surface: rules + sitemap pointer + content signal, the indexable URL list, and a plain-language summary for LLM consumers |
favicon.ico, favicon.svg, apple-touch-icon*.png |
Icons, including the exact paths clients request whether or not the HTML links them |
downloads/ |
Printable board-game + how-to-play PDFs |
The end-to-end wiring — data flow, the /api/complete contract, and the external
integrations (Google Sheets via Apps Script, Resend, Cloudflare) — lives in
docs/architecture.md.
Any static server works for the UI:
python3 -m http.server 8000
# open http://localhost:8000(file:// won't work — browsers block cross-origin <script src> reads.) To run the
Worker/API locally too, use npx wrangler dev. See
CONTRIBUTING.md for the full dev + contribution flow.
Hosted on Cloudflare Workers + Static Assets. Merging to main auto-deploys to
https://greenradi.us — there is no separate staging environment, and main is
branch-protected, so changes land via pull request. Branch pushes build
Access-gated preview URLs for review; the Worker's workers.dev route is
disabled, so the app answers only on greenradi.us.
Manual deploy, if ever needed (requires Node.js):
npx wrangler deployThe Worker's secrets (SHEETS_WEBAPP_URL, SHEETS_SHARED_SECRET, RESEND_API_KEY)
are stored in Cloudflare and never committed.
See CONTRIBUTING.md. New contributors join as collaborators on this
repo (it's the canonical one) and open PRs against main.
MIT — see LICENSE.
