Software

Derelict Ark: A Retro Sci-Fi Dungeon Crawler Where Every Bug Report Replays as a Test

I’m excited to share something well outside my usual territory: Derelict Ark, a turn-based party dungeon crawler in the style of the 1980s first-person grid crawlers, set aboard humanity’s last colony ship. It’s playable in a browser right now — no install, no account, no sign-up:

https://ark.k5n.us/

That browser version is the only one I’m handing out at the moment, and it’s the whole game, not a slice of it. It’s also unfinished — which is the point of this post. I’m looking for a handful of early testers, and I’d rather be straight about the state of it than oversell it.

Derelict Ark boot screen: an ASCII colony ship, the premise text, and an ARK OS cold-boot log ending in SCANNING FOR SURVIVORS ... NONE FOUND
The cold boot. The Ark has been drifting for centuries, the AI went silent, and something got aboard.

Table of Contents

  • What You Actually Play
  • Every Bug Report Replays
  • The Engine Doesn’t Know What Game It’s Running
  • Three Clients, One Set of Rules
  • What I’d Like to Know
  • What’s Rough
  • Built with AI Assistance
  • Testing & Code Quality

What You Actually Play

You assemble a five-person crew from the battered Command Ring, then delve into darkened decks a square at a time — turn, strafe, search, unlock, camp — with an oxygen-and-power clock ticking against you the whole way. If you’ve played Wizardry or Dungeon Master, the grammar will feel familiar immediately.

First-person grid view of a darkened deck, with the party roster, the resource clock, and the movement and action commands
Deck 1, lights out. The status line across the top — clock, O2, power, ammo, meds, salvage — is the whole game’s pressure in one row.

Combat is turn-based, with front and back ranks and a party that has to be positioned rather than just pointed at things. You don’t get told what you’re fighting, either — an unidentified bio-form stays unidentified until someone scans it.

Combat screen showing an unidentified bio-form silhouette, the contact panel, turn order, and the party split into front and back ranks
Contact. Three of something, no idea what — scan to identify it, or find out the hard way.

Mapping is automatic, which is the one concession I made to the era: the decks draw themselves as you walk them, so you’re not sitting there with graph paper unless you want to be.

Wireframe automap of Deck 1 Habitation showing explored corridors and the party marker
The automap fills in as you explore. Toggle it with the same key you use for the forward view.

And there is more than one way to finish. Back at the hub you’re juggling three competing objectives — escape by shuttle, reboot the ship’s AI, or purge the nest — against the same finite pile of salvage and power. Committing to one is largely committing away from the others.

The Command Ring hub screen listing the five-person crew and three competing objectives with their progress
The Command Ring: rest, treat, train, craft, reverse-engineer salvage — and pick which ending you’re actually chasing.

Every Bug Report Replays

This is the part I think is worth twenty minutes of your time even if dungeon crawlers aren’t your thing.

Press F8 anywhere in the game and it files a report. What gets attached isn’t a screenshot and a description of what you think happened — it’s the seed and every command of your run. On my end that report goes through a verifier that re-simulates the whole run from a fresh session and puts me in the exact state you were looking at when it broke. Not an approximation of it: the same state, down to the die rolls. Then the seed goes into a regression test, and that bug can’t come back.

This works because the game engine is pure and deterministic by construction. No random module anywhere in it — the RNG is seeded and injected. No I/O, no globals, no clock. The same seed plus the same commands produces a byte-identical game, every time. The engine can also play a complete game headless from a scripted command sequence, which is how most of the test suite exercises it.

It’s a constraint that costs you something up front and pays for itself permanently. For anyone who has ever tried to reproduce “it crashed sometime on the third floor, I think I’d just used the thing” — this is the version of that where the report is the reproduction.

The Engine Doesn’t Know What Game It’s Running

The other rule I set early: no game content in Python. None.

Every role, enemy, item, map, recipe, trap, status effect, encounter table, and balance number lives in a versioned content pack — 244 TOML files that the engine loads at startup. The engine implements mechanics. It has no idea what a Xenobiologist is, what lives on deck four, or how many ways there are to win.

The shipped game is just the default pack. A different pack is a different game on the same engine — and that’s enforced by tests rather than by good intentions: there’s a check that fails if a content constant ever creeps into engine code.

Three Clients, One Set of Rules

The same separation runs through the UI. The engine never imports a UI package, and the UI contains no game rules — it renders state and sends commands. That’s what makes three clients off one engine practical: a terminal client built on Textual, a native desktop build, and the browser client. They’re the same game, and none of them can disagree about the rules, because none of them contains any.

The browser client is the one that’s public, and it’s what’s running at ark.k5n.us — a separate, independent session per visitor behind an anonymous cookie, with saves on disk, so closing the tab doesn’t cost you the run.

The terminal and desktop versions run on Linux and macOS, and I use them daily. I haven’t packaged them for general release, but if you’d rather play in a real terminal than a browser tab — and for this game, honestly, a real terminal is the better experience — say so and I’ll look at getting builds out. If a few people ask, I’ll do it.

What I’d Like to Know

I’m not looking for balance opinions yet. I’m looking for the embarrassing stuff. Three questions specifically:

  1. Are the first ten minutes legible? You wake up, you have a crew, you go through a door. Does the game explain itself, or do you bounce off it? This is the one I’m least able to judge, because I already know how it works.
  2. Does the clock feel like pressure or like punishment? There’s a resource squeeze underneath the whole thing. I want it to be tense. I don’t want it to be unfair.
  3. Did anything crash, hang, or render wrong? Especially on a browser or a screen size I don’t own. This one has an easy answer: F8.

Press F8 and it files directly into the tracker on this site. It takes a note, and it attaches your replay automatically. You don’t have to describe what happened — the replay says more than a description would.

What’s Rough

Being straight about it, since you’d find out in ten minutes anyway:

  • Nobody outside me has played this yet. You will find things I can’t see.
  • Balance is barely tuned. Some fights are probably unfair in both directions.
  • The browser client is the newest of the three and the least hardened.
  • There’s a PDF operator’s manual, written in the style of a boxed 1980s game manual, and it’s genuinely useful if you get stuck. It also deliberately refuses to tell you what’s aboard the ship.

And the question readers of this blog will reasonably ask first: it isn’t open source. The repository is private. I don’t know yet whether that changes — I may put it on Steam or somewhere similar, and I’d rather not promise either way while I’m still working out what this turns into. It’s a departure from how I normally publish things, and I’d rather say so plainly than be vague about it.

Built with AI Assistance

Like k5n-mcp-hub and my recent php-icalendar-core library, a good part of Derelict Ark was written with heavy AI assistance — Claude Code, mostly — with me driving the architecture, the review, and the design decisions. I mention it because I’d rather say it up front than have it come up later. The determinism and the test ratio aren’t incidental to working that way; they’re what makes it safe. When every change has to survive the full suite and a replayable bug report, you find out quickly whether the code does what someone claimed it does.

Testing & Code Quality

I hold my projects to a high bar, and a game is no exception. The codebase is roughly 30,000 lines of source against 49,000 lines of tests, with a 3,571-test suite behind it — a ratio that’s only sustainable because the tests can drive real games headlessly instead of mocking their way around one. On top of the usual unit and integration coverage, the suite includes the architectural checks described above: engine purity, no content constants in engine code, and no UI imports across the boundary.


Play it: ark.k5n.us — then press F8 and tell me what broke.

Leave a Reply

Your email address will not be published. Required fields are marked *