Announcing Citadel: My Latest Native Mac Game

The title screen of Citadel, my macOS first-person shooter

Citadel — the boot-up terminal, and the logo of a company you are not yet supposed to be suspicious of

Citadel is out.

It is a first-person shooter for the Mac, in the Doom idiom, and it is the ground war of the story that started with Strataris. That game was the air war — you flew low over six colony worlds and held the sky against a marauder fleet for as long as you could. You did not hold it long enough. This is what happened next.

The swarm landed. The colonies of Demeter, Tantalus, Boreas, Pandora, Vulcan and Vesper went dark, one after another. Everyone who could get underground got underground, and then something followed them down. You spent all of it in a medbay bunk with a head injury, which is the only reason you’re alive and the reason you remember none of it — and it leaves you, when you finally stand up, as the only trained soldier still standing down there.

So you go down there on foot. Forty-eight floors. Six citadels, eight levels each, all the way to the bottom of every one of them.

It’s free, like everything I make. It’s public domain, source and all. And I am, if I’m honest, prouder of it than of anything else I’ve built.

The rule that changes everything

Here is the single design decision the whole game hangs off, and it took me an embarrassingly long time to realise it was the good one.

Every floor is held by a Queen — a rooted, enormous brood-mother who births fresh drones for as long as she’s alive, hates your headlamp, and sits between you and the freight elevator. Only the plasma rifle wounds her. Fine. That’s a boss fight; you’ve had a hundred of those.

Except when she goes down, she isn’t dead. She’s down. And if you walk away, she gets back up, and the floor never ends.

To finish her, you have to walk up to the body and burn it. Flamethrower. Close range. Standing over the thing you just killed while its drones are still coming, holding a trigger, watching a fuel gauge that only tops up at a drum somewhere else on the floor.

That one rule reorganises the entire game underneath it. Fuel stops being a weapon and starts being a budget — every gout you spend on a drone in a corridor is fuel you won’t have for the thing that actually matters. The plasma rifle and the flamethrower stop being alternatives and become two halves of one job. And the fight has a coda: there’s no clean moment of victory where the music swells and you walk out. There’s a body, and a chore, and it has to be done properly.

I didn’t design that from first principles. I stumbled into it while trying to solve a completely different problem, played it once, and knew immediately not to touch it again.

The flamethrower firing in Citadel, a drone caught in the stream of burning fuel

The flamethrower is a genuine volume of burning fuel — it blooms, it rolls, it goes sooty, and it lights the room as it goes

Two castes, three weapons, and a lot of arithmetic

The colony holds one organism in two forms. The drone is a slick green-black melee hunter — slow, but it is not stupid. It comes in numbers, it comes around corners, and it will happily let you commit to the one in front while two more work their way down the flank. It has to reach you to hurt you, which sounds generous until three of them have you in a doorway. And the Queen sits at the heart of the floor making more of them for as long as you leave her alive.

Against that you carry the plasma rifle and the flamethrower permanently, and you’ll find a rocket launcher out in the field. The rifle is the workhorse and the only thing that wounds a Queen; it will nudge a shot onto a nearby target for you, but the cone is narrow and deliberately unhelpful — it is an assist, not an autopilot. The rockets hit hard enough that standing too close to your own blast is a real and recurring way to die. And you carry proximity mines, which you can walk over and the swarm cannot, which is the entire point of a mine.

Everything is finite. Every plasma cell, every litre of fuel, every rocket you’re carrying. What keeps it from being miserable is that the colony itself is the supply line: shoot a fuel drum and it ruptures into a bomb, or stand beside it and it refills your flamethrower. Plug into a wall-mounted recharge socket and it tops up your cells — and sockets slowly rebuild their own reserve, so a floor you’ve stripped bare will have a little something for you if you come back through it later. You are never permanently starved. You are, permanently, doing sums.

Combat in Citadel: a drone approaching past a fuel drum, seen through the helmet visor HUD

A drone comes over the fuel drum. Shoot the drum, or shoot the drone.

All light is man-made

You are underground for the entire game. There is no daylight, no skybox, no ambient glow from nowhere in particular. Every single photon in Citadel comes from something you could point at: a bulkhead lamp, a flickering terminal, the sick green self-light of a nukage pool, the fire you just started, and the lamp on your own helmet.

That sounds like a technical note. It is actually the whole atmosphere. The upper floors of a citadel run bright — the fixtures still work up there, mostly. The deeper you go, the more of them are out, until by the bottom of a building you are essentially carrying the only light in the world and the corners are genuinely, unhelpfully black. The lowest floors are flooded, so you wade, and you can hear yourself doing it.

There is no status bar. I tried one; it made the game feel like a spreadsheet with monsters. So the 3-D view fills the entire screen and every readout is projected onto the inside of your helmet visor instead — vitals, weapon pods, a live cells/fuel/mines telemetry strip, and an Aliens-style motion tracker with an objective caret riding on its rim. The caret points at the living Queen. Once she’s ash, it swings around and points at the exit. You never need to open a menu to know what the floor still wants from you.

I will not pretend the debt to Ridley Scott isn’t enormous. Wet corridors, a crew that didn’t make it, a corporation whose logo is on everything and whose intentions you should probably examine, and a thing in the dark that is better at this than you are. Alien is the reason I find industrial corridors frightening, and Aliens is the reason I find a chirping motion tracker frightening, and I have taken both entirely without shame.

I told you it was all equations. I was wrong.

In July I wrote a post explaining, at some length and with obvious pleasure, that this game had no models in it. Not one. The world was a signed distance field — every wall, every pipe, every rusted surface and every monster described as a mathematical function, sphere-traced on the GPU, a few hundred thousand times a frame. A corridor is an equation. I was thrilled with myself.

Reader, I tore it out (I know, it’s becoming a habit).

It was about seventeen hundred lines of Metal compute kernel, it was the cleverest code in the project, and by the middle of July it had lost an argument to a boring old triangle rasteriser on both counts that matter: the raster path looked better and it cost less. Not one or the other. Both. Raymarching a distance field is gorgeous for organic, grown-looking things and quietly miserable at sharp machined edges — and it turns out a colony built by an industrial mining concern is mostly sharp machined edges. Meanwhile every additional creature on screen was more maths per pixel per frame, and the frame budget on a real-time renderer is 16.7 milliseconds and it does not negotiate.

So the kernel is gone. Deleted. The level is built into vertex buffers once when it loads, materials are still shaded procedurally in code, and the whole thing is lit in HDR, bloomed and tonemapped on the way out. The only trace of the Raymarcher that remains is a file called GPURaymarch.swift, which no longer raymarches anything and survives purely as the home of some shared types I couldn’t be bothered to rehouse. It sits there like a pub that kept its name after the brewery closed.

I mention this partly because it’s honest, and partly because it’s the second time in two games I’ve deleted a renderer I loved. There may be a pattern. I am choosing not to examine it.

The four things I let in

Strataris shipped with no asset files at all — no textures, no audio, no fonts, no models, the entire game generated in code and small enough to fit on a floppy disk. It remains the constraint I’m proudest of.

Citadel breaks those constraints in exactly four places, and I want to be straight about all of them, because I’ve been loudly pure about this before and it would be pretty cheap to go quiet now.

The bodies. The drone and the Queen ship as 3-D meshes with baked colour maps. Organic, ridged, biomechanical anatomy reads better sculpted than generated, and after weeks of trying I couldn’t make maths produce something that looked like it had grown. So yes — this game ships textures. Two of them are monsters.

Three hero plates. Cinematic images behind the front-end screens, the title among them.

Five imported models, geometry only. A dormitory bunk and four pieces of plant machinery, downloaded, decimated to budget, and then stripped of every material they arrived with and re-surfaced in code. The shapes are borrowed. The surfaces are mine.

Audio. This one I’ve already confessed to at length. You can synthesise a gun. You cannot synthesise a living thing, and a game like this lives or dies on the noise something makes when it notices you. So Citadel ships a small, curated set of CC0 and CC-BY samples — all properly credited, all free for me to give away and for you to have. But the code still does most of the work: the Queen’s snarls are pitched down because she’s enormous and randomly nudged each time so she never repeats herself, and a drone two rooms away comes to you muffled and drowned in reverb, as though it’s carrying through a hundred metres of steel. There’s no soundtrack either — just a stack of layers and a live signal measuring how much trouble you’re in, thickening as things close and thinning when you’re safe.

And the synthesiser I built for Strataris? Still in the binary. It got demoted to the safety net: if a sample is ever missing, it quietly generates a stand-in so the game never falls silent. The old religion is on night shift.

Forty-eight floors, and every one of them proven

Levels are generated fresh every time you play — rooms, corridors, doors, coloured keycards, hidden secrets, hazard-walled fuel stores, an exit you have to earn. Play it twice, you’ll never see the same building twice.

Which raises the question that will keep you awake: what if it builds one you physically cannot finish? Random doesn’t care about you. Give it enough rolls and it will happily lock the red key inside the room that needs the red key, hand it to you with a straight face, and let you conclude I shipped a broken game.

So the generator doesn’t get the final say. Before you ever set foot on it, a solver floods the floor from your starting position — reach, collect a key, unlock what that key opens, reach further — and if it can’t touch the exit, the whole level goes in the bin and it tries again. I wrote about this in July, back when I’d only just discovered that the furniture can quietly ruin a certified-solvable floor by parking an oil drum in a doorway like a cork in a bottle. That’s covered now too. You will die on these floors. You will never be trapped on one.

Clearing a floor has a small ritual attached, and I’m fond of it. You call the freight elevator, the leaves part, and you step into the car — and there’s a panel in there that totals up what you did on the floor you’re leaving: kills, secrets, score. Then it takes you down. Eight of those and the building is yours, at which point you teleport to the next planet and start again at the top of a fresh one, brighter at the surface, worse further down, with the difficulty scaled to how deep you are rather than how long you’ve been playing.

You can save whenever you like, into any of ten named slots. A save is about three hundred bytes, because it stores the checkpoint — the state you arrived on this floor with — and nothing else. The map isn’t written down; it’s regenerated from the run’s seed when you load, and the lift rides you back down to it. You always resume on a clean floor start, never stranded half way through a fight you were losing.

A dark corridor in Citadel, lit only by a bulkhead lamp and the marine's helmet lamp

The deeper you go, the fewer fixtures still work

The quiet things

The parts I like best are the ones the game never mentions.

A sick bay always holds a med-kit, and standing in one slowly closes your wounds — ten health every thirty seconds you stay. A room the nukage has reached does exactly the reverse at exactly the same rate, pool or no pool, because the air in there is the hazard. Neither is announced. There’s no icon, no chime, no tutorial pop-up. The only tell is your own health quietly moving, and working that out for yourself is the whole point.

Use a computer desk and the game zooms into an amber CRT. Most of them are jokes. Three of them aren’t: three interactive, paged documents that tell the same slow catastrophe from three different angles — a Director’s log, a stack of corporate memos, and a young scientist’s emails home to her mum. Read all three and you’ll know considerably more about why this happened than the marine does. Nobody makes you read any of it. There’s also a fully playable Space Invaders on one of those terminals, with its own persistent high-score table, because of course there is.

And somewhere in the run there are seven bodies. Colonists who sealed themselves into rooms when it all went wrong, and have been lying there a very long time. One pool of seven, dealt out across the six citadels, never more than two to a building — so a full campaign is the only way to find them all. The game does not tell you they exist, does not mark them, and does not congratulate you when you find one. The only thing you can do for them is the flamethrower, and it’s worth a thousand points a body and fifty thousand for all seven, awarded in complete silence.

I thought about putting a notification on that. I’m glad I didn’t.

What it cost

Strataris took five months. Citadel took six weeks (give or take) — first commit on the twenty-second of June, released today. A hundred and ninety commits, thirty thousand lines of Swift, one renderer deleted, one rule about pure code broken in four places, and one stretch in late July where the same two test frames kept coming out differently on every run and I genuinely began to doubt my own arithmetic. It was Swift seeding its dictionary hashing per process, so two tied walls kept swapping places. I found it by fingerprinting every field of the generator and bisecting, after two days of reasoning about it got me (and even the AI) precisely nowhere. Measure, don’t reason. I keep having to relearn this.

It runs on Apple silicon only, and that’s deliberate rather than lazy: it’s a real-time Metal renderer tuned to a 16.7 ms frame, every measurement behind that tuning was taken on an M-series Mac, and an Intel slice would have shipped without ever once running on the hardware it claimed to support. I’d rather say no than ship a maybe.

The Hall of the Fallen — Citadel's persistent high-score table, listing name, score, depth and colony

The Hall of the Fallen — name, score, how deep you got, and which colony took you

Go and get them out

Citadel is out now. It’s free — properly free, public domain, no catch, no telemetry, no account, no launcher. I’ve written before about why everything I make is free so regular readers know the drill by noe, except to say that I built this because I wanted it to exist and now it does, and you should have it.

You’ll need an Apple silicon Mac running macOS 14 or later. There’s an installer and a zip, both signed and notarised, and the source is on GitHub if you’d like to see how any of it works or take it apart for parts.

Take the plasma rifle to the Queen. Take the flamethrower to what’s left of her. Get your name into the Hall of the Fallen.

And keep an eye on the light on your helmet. It’s the only one down there that’s definitely still working.

P.S: It plays best with a gamepad, it’s damn hard with just the keyboard.