It started with a photo on Instagram. Somebody posted the 1983 Star Frontiers Referee’s Screen — that beautiful Elmore-adjacent cover with the aliens in the bar, the one where a Dralasite is holding a drink with an arm it grew for the occasion. And I thought: I was too young for this game when it came out, I don’t own it anymore, and I would very much like to roll some percentile dice.

Four games and about two thousand lines of JavaScript later, here we are.

What’s actually there

Four playable things, all living at /games, all built on one shared engine.

🚀 Kellath’s Drift — a percentile roll-under adventure in the spirit of the old TSR games. You’re a scout, your survey skiff is a smoking wedge in red scrub, and there’s a relay tower eleven kilometres north. Roll 2d10, try to roll under your target. That’s the whole system and it’s beautiful.

🛸️ Offline Protocol — Murderbot, essentially. You’re a security construct escorting a survey crew to a decommissioned mining rig, and you quietly disabled your own governor module a while back. Seven acts, five crew members who can genuinely die, an old guard construct you can fight or talk down, and a sarcastic transport intelligence called Latitude who works out your secret in the first hour and then spends the rest of the contract deciding whether to make you say it out loud.

Latitude also remembers you between playthroughs. Come back after a run where you lost people and it opens with: “We do not have to talk about Nadia Okonkwo and Teodor Ruiz. I am saying that so you know I remember, not so you have to answer.”

🗃️ Adjuster’s Report — no combat at all. You’re an insurance loss adjuster on a station where a death has already been ruled accidental, and the policy pays eleven million dollars if it stays that way. Five pieces of evidence, three suspects with real motives, and one of them is lying. The culprit is redrawn every single run, so you can’t solve it once and replay from memory.

🏜 Railroad Valley: Nine Litres — the big one. More on this in a minute.

The engine, and why extracting it was the best decision

The first two games were self-contained HTML files, which meant the dice code, the audio, the navigation, the character sheet — all of it — existed twice. Fix a bug, fix it twice. Add a feature, add it twice.

So I pulled it all out into /games/engine.js and /games/engine.css. Now a module is content plus a config object:

Engine.init({
  id: 'adjusters-report',
  title: "ADJUSTER'S REPORT",
  mode: 'over',              // roll high vs DC ('under' = percentile)
  state: () => freshState(),
  status: statusFields,      // what's in the status bar
  sheet: sheetHTML,          // what's in the character sheet
  start: startCase
});

A scene is just a function that writes some HTML and wires up buttons:

function theHatch(){
  Engine.badge('ACT 2');
  Engine.render(`...prose... <button id="h1">HACK THE LOCK</button>`);
  document.getElementById('h1').onclick = ()=>{
    Engine.check({die:10, mod:player.stats.ANALYSIS, dc:DC.lock}, (success)=>{
      Engine.render(success ? `...it opens clean...` : `...feedback spike...`);
      Engine.wire(interior);   // next scene
    });
  };
}

Engine.check handles everything visible — spawning the dice panel, tumbling the faces, playing the sounds, showing the verdict, waiting for you to click Continue — then hands back true or false. You never touch a timer.

The real test came when I wrote the third game entirely as content, with zero engine changes. New stats, new dice mapping, a custom evidence list in the sheet, a countdown clock in the status bar, six endings — all through the existing API. That’s when I believed the abstraction was drawn in the right place.

The fourth game broke it, but usefully: a Leaflet map can’t survive Engine.render() wiping the DOM every scene. So the engine grew persistent panels — a module-owned region that gets built once and never torn down. Thirty lines, and now every future module has it.

The dice look like dice

Small thing, big payoff. Each die type gets its own silhouette via CSS clip-path — a d4 is a triangle, a d8 a rhombus, a d10 the classic kite, a d20 the hexagonal profile — with faint interior facet lines drawn in SVG so it reads as a solid object rather than a badge with a number on it.

And all the audio is synthesized in Web Audio. No files to host. A dice tick is a filtered noise burst with a randomized bandpass so it doesn’t sound like a loop; a landing die adds a low triangle sweep; success is a rising two-note chime; failure is a falling sawtooth through a lowpass. About a hundred lines total.

Railroad Valley, or: the one where I got ambitious

I’m a GIS analyst. I have a cartography publication. At some point it was inevitable that I’d build a game on real terrain.

So: Railroad Valley, Nye County, Nevada. Real USGS National Map topo tiles, 37 locations on genuine coordinates, terrain classified as playa, bajada, wash, ridge, mine workings, ruin. Your Jeep breaks down on a two-track and you have nine litres of water.

Every distance is real. Every walking time is computed from terrain pace plus a Naismith climb penalty. US-6 is 44 kilometres away, which on foot in that country is a two-to-three-day walk, which is a death sentence, which is the point.

There’s a real day-night cycle — 14°C at 4 a.m., 38°C at 4 p.m. — and everything hangs off it:

Walking:   0.40 + (T โˆ’ 20) ร— 0.055  L/hour
In shade:  0.10 + (T โˆ’ 20) ร— 0.016  L/hour

At 38°C that’s 1.33 litres an hour walking and 0.39 in shade. You have nine. The entire game is that ratio.

Heat strain builds when you work in high sun and sheds at night. Your feet wear with distance and get worse when you’re dehydrated, which slows you down, which costs more water. Rattlesnakes are a hazard check on warm ground at dusk, not a fight. There’s no hunting — and that’s not squeamishness, it’s accuracy. In a desert you die of heat in days and of hunger in weeks. Food is nearly irrelevant.

The lesson the game is actually about

Search and rescue finds vehicles. It does not find people. Most desert deaths in Nevada are somebody who walked away from a working shade structure with water still in the back.

So the game was originally called Stay With the Vehicle — and that was a mistake, because the title answered its own question before you pressed a button. My friend playing it put it perfectly: “the title says stay with the jeep, so what’s the motivation to leave?”

He was right, and the fix taught me something. The real advice isn’t “stay with the vehicle.” It’s “stay with the vehicle if somebody knows where you went.” A search assumes somebody noticed. That’s the part nobody puts on the poster.

Now every trip rolls one of three states, and tells you at the start:

WHO KNOWS YOU CAME OUT HERE

You did not tell anyone. Not because you are careless โ€”
because there was nobody to tell, and because it was going
to be a day trip, and because it always has been before.

โ†’ Nobody knows you are out here. No search will start.
  Waiting is not a plan.

Here’s the outcome matrix from automated playtesting, twelve trials each:

stay with the Jeep walk out at noon walk out at night
Told your sister rescued 8/8 died 8/8 rescued 6/8
Mentioned it to a clerk rescued 4/8 died 8/8
Nobody knows died 8/8 died 7/8 rescued 7/8

That’s a real decision now. Same advice, opposite correct answers, and the game tells you which situation you’re in.

The other situation

This is my favourite part.

There’s a geocache out there — a .30 cal ammo can under a cairn, gasket still good, with a logbook in a freezer bag. Forty-one entries. The first is dated 2001. The last is dated 2004.

Twenty-six of those entries are the same handwriting, getting smaller over four years. A man called R.H. He brought his daughter once and she found it before he did and wouldn’t let it go. Then the entries stop being about the cache:

02/2002 โ€” Followed the trench line 2.6km. It does not go
          to the site. It goes past it, parallel, on this side.

10/2002 โ€” Scanned the AM band all night from the truck
          because I could not sleep. There is a carrier on
          1530. No station, no ID. It does not go off.

01/2004 โ€” White pickup on the rise when I came out. Sat
          there the whole time I was at the cairn, and left
          when I left.

08/2004 โ€” Roll of film came back with 24 blanks. Could be
          the developer. Going back out in September to do
          it properly.

The book stops in August.

And the radio is real. At night, AM skywave propagation drags in clear-channel stations from six hundred miles out. KFI 640 out of Los Angeles giving you a 405 traffic report at 2 a.m. while you’re lying in a broken Jeep with a litre and a half of water. Mattress ads from Torrance, delivered with tremendous urgency, to you, here. KSL 1160 with a forecast that might actually matter. Somebody on 1200 taking calls about lights over Nye County — describing a ridge you happen to be looking at.

And 1530, which is a transmitter that’s switched on with nobody talking into it. Sit with it long enough and it starts dropping out for eleven seconds every four minutes. Machines keep time like that. Nothing else does.

Eventually, in the gap, a voice reads twelve digits. Twelve digits in that format is a position.

There’s a Ford out there. Sun-bleached from red to pink, tyres rotted off the rims, tags expired 2004, driver door open a long time. Nobody in it. Keys in it. Four sealed jerry cans in the bed.

He brought plenty of water. That’s the part that stays with you. He brought plenty and it’s still there.

His last notebook ends: “Walked the line 2km N of the box. There is a lid.”

And there is a lid.

The trick that makes it work

Every description of anything strange has three versions, selected by a “clarity” value computed from your water, your heat strain, and how many hours you’ve been dry. At full water, a thing is a thing. At 26% clarity, the same scene reads:

In the gap there were numbers, or there was a gap and you supplied the numbers. You have been awake a long time and the difference has stopped being available to you.

Nothing supernatural is ever confirmed or denied. Everything has an ordinary explanation available. You just stop being someone whose account would hold up.

The entire supernatural mechanic is made of dehydration, and I’m quite pleased about that.

Three things I got wrong, in public, repeatedly

1. Impossible dice. Three separate times I shipped a check that could never succeed. The disable option in Offline Protocol was DC 16 on a d10 — maximum possible total, 14. The parley was DC 15 on a d8. Buttons that sat there, inviting, and could not work.

I kept fixing the DC. The DC wasn’t the problem. The problem was that the modifier spread was wider than the die. If one character build sits at −2 on a stat and another sits at +5, that’s a range of seven on an eight-sided die, and some difficulty will inevitably land outside what the die can express.

So I wrote a standing audit — tools/audit-dice.js. It boots every game headlessly with jsdom, enumerates every character build, resolves every DC including per-run jitter, and flags four conditions:

โ”€โ”€ dice audit โ”€โ”€
4 module(s), 26 distinct check(s)

  โœ“ no impossible or auto-passing checks

  worth a look:
    [BRUTAL] adjusters-report.html / forensic โ€”
             Press: only a natural 8 passes at DC 8

IMPOSSIBLE and AUTOPASS are bugs and it exits non-zero on them. BRUTAL and CERTAIN are judgement calls it just tells you about. It has caught five real bugs so far, two of which were already live on the site, and it found one in the same session I wrote it.

2. Atmosphere where information was needed. I wrote “a carrier” about forty times without ever defining it. My friend — who is studying for his ham licence — said: “how we know what a carrier even is, it’s confusing... I never knew what to do with the frequency, or any numbers, or how it connected to the cairn.”

Devastating and completely correct. I’d written mood and forgotten to write meaning.

The fix was three things: explain jargon in plain words the first time it appears; a notes panel that records every thread in your own handwriting with what it implies; and a persistent “Following up” banner on every screen so you always know what you’re chasing.

The rule I now believe: atmosphere is only for things the player already understands. Anything they have to act on gets said plainly, at least once.

3. Invisible death clocks. Running out of water doesn’t kill you instantly — you get roughly nine effective hours, spent faster in heat and faster while working. Correct physiology. But there was no way to see that, so dying felt arbitrary rather than earned.

Now the status bar switches from litres to a countdown the moment you go dry: NO WATER โ€” about 4 h left. And the repair button tells you the arithmetic rather than letting you spend yourself into a hole:

FIX IT ยท 2 h ยท attempt 4
two flats. At roughly 10% a go, this has already cost
you 6 hours and about 3.6 litres.

A game can be as ambiguous as it likes about what’s buried under the playa. It cannot be ambiguous about how long you have to live or what a button costs.

For the contract enjoyers

Adjuster’s Report now ships with the actual policy. You can re-read it any time, and it is the whole game:

7.2 — Exclusion: Act of a Covered Party
No indemnity is payable where the death arises, directly or indirectly, wholly or partly, from the deliberate act of any Covered Party, whether or not such act is the subject of criminal proceedings and whether or not any Covered Party is charged, tried or convicted.

And the asymmetry that decides everything, buried in clause 14.3: a finding of misadventure requires you to evidence nothing. A finding against a Covered Party requires you to show your working, in writing, to people whose job is to take it apart, and it has to survive ninety days.

Nobody wrote that asymmetry maliciously. It’s an accumulation of small reasonable drafting decisions made by people who were never going to be standing in an annex on Corvid-9.

Where this goes

Honestly? It’s not finished, and I like that.

The immediate list: the bottle chamber in the mine and the underground gallery are each one paragraph, and they should be places you move through.

The open question I can’t answer without more play: you can now reach the bottom of the mystery and still die on the walk home. Is that the right ending — you found it, nobody will ever know, your notebook ends up next to his — or is it a punishment for engaging? I genuinely don’t know.

The bigger idea: the engine now makes a new game mostly a writing job. That’s dangerous. I have a physical Nevada Trivia board game that wants digitizing. I have opinions about Great Basin ungulate migration that could probably be a game. The barrier has moved from “can I build this” to “what’s worth building,” which is a much better problem.

The takeaway, if there is one

The thing I keep coming back to: almost every good decision in this project came from someone playing it and telling me something I couldn’t see from inside.

The title that answered its own question. The story that never connected. The jargon nobody outside ham radio would parse. The death clock you couldn’t see. I tested all of this extensively — headless playthroughs, hundreds of automated runs, statistical outcome matrices — and my tests never once had to understand anything. They just clicked buttons and checked that numbers went down.

Automated testing catches bugs. It cannot catch confusion.

Anyway. Go get stranded in Nevada. There’s a lid.


🌲 All four games are original mechanics — nothing is reproduced from any published rulebook. Coordinates in Railroad Valley are real; the two-track and the breakdown point are fiction. It’s a game, not a route guide.