Black Rock Rangers — Ranger Training Toys: a poster of the kit, with the Radio Training Simulator at the front and a row of beacons, patches, sunglasses, hat, and field guide alongside.

Black Rock Rangers · Training Toys

Ranger Radio & Khaki

A small line of in-browser training toys for burn-event rangers. Two of them so far: a real multi-user push-to-talk radio, and a single-player shift sim with Claude on the dispatch console.

Web · Open Source

That poster up top is the long view. Black Rock Rangers is the volunteer ranger corps at Burning Man and at the regional burns — SOAK in Oregon, Apogea in Colorado, and the rest. Rangers do welfare checks, mediate disputes, and coordinate by handheld radio across a few thousand acres of high desert. The radio loop — access tone, callsign, brevity, roger beep, clear — is most of the job, and most of what new rangers need to drill before their first shift. The kit in the poster is the toy box I'm building toward: a few small, browser-based training pieces that each take aim at one part of the shift floor.

The two web apps below are the first two toys in the box. They're the same training problem, attacked a year apart with very different tools.

Two Projects, One Thread

June 2025 · Built at Apogea (“Half-Ogea”), Colorado

Ranger Training Radio

A real multi-user push-to-talk web radio with authentic effects and a command-staff monitoring interface.

Apogea is the regional Colorado burn. I sat in a tent with a laptop and built the first version in a few days because the rangers there needed something that worked in a browser, on whatever device anybody had, with no install and no app store.

It's a real radio. Click and hold (or press space) to transmit. Your voice goes through the Web Audio API filter chain — highpass at 300Hz, lowpass at 3400Hz, light saturation, compression — so it comes out sounding like a handheld. There's an access tone before you transmit, a roger beep when you release, a squelch tail, and a low static loop while the channel is clear. Only one person can key the channel at a time; everyone else hears a busy tone if they try.

There's a second interface called the Khaki Command Network for command staff. It auto-numbers callsigns (KHAKI, KHAKI-2, ...), captures conversations into session-grouped recordings (with smart titles like “Radio Traffic: RANGER-1 ↔ KHAKI”), and lets you download WAV files for after-action review.

Stack: Node.js + Express + Socket.IO on the backend, vanilla JS + Web Audio API + MediaRecorder on the frontend, deployed on Render.com. No framework. No build step. Open source on GitHub.

The radio works. But it needs at least two humans on the air to be useful for training, and one of those humans has to know what they're doing well enough to play dispatcher convincingly. That's the bottleneck. What if Khaki was just always there?
April 2026 · Two weeks of evenings · SOAK 2026 prep

Ranger Shift — Khaki on the Channel

A single-player burn-event ranger sim. Same radio. Same etiquette. The dispatcher is now Claude.

You check in with your callsign, get briefed by Sarah (your shift partner soul), pick a shift length, and go on the air. Khaki dispatches you to encounters — a possible welfare check, a parent looking for a kid, a noise mediation, a porta-potty closure with a wandering altered participant. You key the radio, type what you'd say, release. Khaki responds in her own voice (ElevenLabs Flash 2.5, run through the same radio filter chain ported from the Apogea project). Ambient channel chatter from other ranger teams plays in the background between calls so the channel never feels empty.

Every primary-channel transmission goes through an etiquette grader: did you open with “Khaki, Khaki, <handle>”? Did you spell out digits? Did you stay clear of forbidden words like “overdose” or “eviction” that don't belong on an open channel? At end-of-shift, an LLM scorecard pass produces a tier-colored rubric (Radio Usage, Restraint, Presence, Fitness, FLAME, Social Capital), a 2-3 sentence narrative in a shift-lead voice, three coaching tips, and per-encounter cards showing exactly which call moved which number.

The closeout handoff is the one I'm proudest of. When you call for a service (Medical, Fire, LE, Green Dot, Captain Hook), the resource arrives on-channel, releases you to clear, you tell Khaki you're back on patrol, she asks you to confirm scene complete, you say yes, she releases you. Five exchanges. The full BRR (Burning Ranger Radio) closeout, modeled on the real one.

Stack: Python 3.12 + Flask + SQLAlchemy + SQLite, Anthropic SDK with claude-sonnet-4-6, ElevenLabs SDK with eleven_flash_v2_5, vanilla JS frontend, the same Web Audio filter chain ported from Ranger Training Radio. 24 scenarios. 211 backend tests. Deployed on Render. Built in two weeks of evenings.

A Real Shift Report

Tester · callsign TANZI · 19 April 2026

Three encounters, 56 minutes on the air

The longest playtest shift to date. TANZI worked Crying and Trying, My Name is Groot, and Something in the Drinks back-to-back — 40 primary transmissions, 124 ambient chatter events, 14 decisions, an LLM-graded scorecard at the end. The whole shift cost $1.59 in API spend.

10
Restraint · /10
10
Presence · /10
10
Fitness · /10
0
Radio Usage · /10
4
FLAME · /10
6
Social Capital · /10

“You kept your head across a busy shift — the dosing scene in particular showed good instincts: you called it early, held the scene, secured the sample, and handed off cleanly to medical without overreaching on what you knew. Where I want you to grow is in the space before you act: you moved fast to solutions and comfort, which worked tonight, but you didn't do much listening out loud — no paraphrasing back, no checking your read with the participant, no real open-ended digging…”

— LLM end-of-shift narrative, written in a shift-lead voice from the actual event log

Top coaching tip from that shift: “Open every call with Khaki, Khaki, <your handle>. The double-Khaki pause tells dispatch to clear other traffic before you speak.” — flagged 10 times across the shift, which is why the radio_usage score landed at zero. The grader catches the etiquette miss, names it specifically, and ranks it by frequency.

What I Learned Going from One to the Other

The audio chain was the bridge The same Web Audio filter graph ported straight from the 2025 project. The radio sounded right on day one of the new build because that piece was already correct.
Typed transmissions beat speech-to-text in v0 Player types what they'd say while holding PTT. Faster to iterate, and it dodged the worst of the latency budget — you can ship a sub-3.5s p50 release-to-Khaki round trip with a typed input.
Content out of code, hard discipline Souls (YAML), scenarios (Markdown with YAML frontmatter), rubrics (YAML). Claude Code wanted to inline narrative as Python strings; the rule held.
Dispatcher is a state machine, not a chatbot The shift state machine, the scenario sub-state, and the client-side radio state machine are three independent pieces. Khaki is a function of the current scene context plus the recent event log, not a free-form roleplay session.