Hammerite's subtractive workflow and compiler

For most of its life Hammerite built levels the way most editors do: you placed solid blocks in empty space. That meant the sound for every room had to be wired up by hand. In August 2026 I switched it to a subtractive workflow. Now solid is the default and you carve out the air, and the editor works out the rooms and the doorways between them by itself.

Hammerite started as a brush editor like Valve's Hammer and the Quake editors: the level is empty space, and you add solid blocks to it until there is something to stand on. (How it got from there to here is a story of its own.) That worked well enough until City of Thieves, the stealth game I am making with it, needed sound.

A stealth game needs sound to work properly. You should hear footsteps through a doorway, and a guard should hear you in the next room but not through a metre of stone. In November 2025 I gave City of Thieves an audio system inspired by the Thief games, where sound travels from room to room through the openings between them. For that the game has to know what the rooms are and where the doorways are.

The problem with additive levels

In an additive world the editor does not know any of that. "Solid" just means "inside some brush". Walls are slabs placed side by side, floors are slabs, and the faces where two slabs touch are hidden by checking which ones lie flat against each other. There is no room anywhere in that description. A room is just the space that is left over between the slabs.

A test room in the August 2026 Hammerite editor, made of four separate wall blocks standing around a floor
August 2026, a week before the refactor: a room as four wall blocks around a floor. Nothing in the editor knows there is a room.

My first attempt tried to find the rooms automatically, by filling the level with voxels and grouping them into zones. I deleted it the next day. What replaced it was the manual version: you placed an audio zone by hand in every room, and a portal in every doorway, a quad with a position, a normal, a width and a height. The graph builder then cast rays out from each portal to guess which zones it connected.

It worked, but it needed care. Every change to a level meant checking the markers again. Moving a wall meant moving the portal in it, and a new corridor needed its own zone. Or as the commit that finally retired the system put it:

A designer could also simply forget a room.

The tool for placing all of this was over a thousand lines of code, and nothing it produced said anything that was not already in the level's geometry. It just made a person say it a second time.

The November 2025 Hammerite editor with the Acoustic Graph Builder open: a 3D view of the level as a closed shell of blocks, and three plan views with hand-placed zone markers and the graph between them
November 2025: the Acoustic Graph Builder. The dots in the plan views are audio zones placed by hand, and the green lines are the graph built between them.

The subtractive workflow

The idea is a lot older than Hammerite. Dromed, Looking Glass's editor for the Thief games, starts every level as solid rock. You don't build a room there, you dig it. And a dug room is exactly what an audio system wants: a volume of air, with openings to its neighbours where two dug spaces meet.

So in August 2026 I wrote a design document and in the span of 188 commits, turned Hammerite into a subtractive editor. The document was clear that this was not a new tool mode:

It is baked into the definition of solidity itself.

Solid became the default. Air brushes carve rooms out of it, and solid brushes put rock back. Every room, every opening and every visible wall is derived: recompiled from the brushes on each edit and never saved. The goal was a world that always knows its own rooms and keeps that up to date while you work. In the document's words, "the compiler's output has a consumer waiting". That consumer was the audio system, which had been fed by hand until then.

The additive editor had a subtract tool too, which cut pieces out of solid brushes. But cutting holes in slabs still leaves you with slabs. What changed was what the editor thinks the world is made of.

A single room carved out of solid rock in the Hammerite editor
One air brush, one room. Everything around it is rock.

How the compiler works

Every time a brush changes, the compiler runs the level through six steps:

The compiler's six stages, from the brush program to the walls Program Solids Cells Portals Faces Walls brushes in order convex rock convex air → rooms the openings what faces air holes cut
  1. The program. The structural brushes are put in order: air carves, solid puts rock back, and a later brush wins over an earlier one where they overlap. Detail brushes, such as furniture made of brushes, take no part. The order is cached and only worked out again when something that affects it changes.
  2. Solids. Running the program as constructive solid geometry gives the rock as a set of convex pieces.
  3. Cells. The air comes out the same way, as convex cells. Connected cells are grouped into a region, which is a room as a player would see it: a pillar splits a hall into four cells, but it is still one hall.
  4. Portals. Wherever two rooms meet there is a portal. Rooms that abut, two air brushes touching on a shared wall, get an aperture: a real opening polygon, a doorway. Rooms that overlap flow into each other with no wall between them, and become one continuous space. That gives the one rule an author has to learn: overlap to extend a space, abut to divide one.
  5. Faces. Of all the brushes' faces, only the ones that face into air are kept. A face points out of its own brush, so a room's floor is the face of its air brush that points down, into the rock.
  6. Walls. The openings are cut out of the kept faces, which leaves the walls that are actually drawn, lit and heard.
Two pairs of rooms from above: on the left two overlapping air brushes that make one continuous space, on the right two abutting ones that meet at an opening
Overlap to extend a space, abut to divide one.

None of this is saved. A map stores only what an author made: brushes, faces and entities. Anything attached to a derived thing has to live on something authored. A doorway's name, for example, is stored on the faces it was cut from, so it survives the doorway being recompiled from scratch.

Recompiling everything on every edit would be slow on a big level, so it doesn't. An edit recompiles only what the changed brush could have reached: where it was, and where it is now. The work is spread over every core, and since Hammerite 2.0 all of it is native code. On a 256-room test level a one-brush edit recompiles in 25 milliseconds.

What it gives for free

Once the world knows its rooms, everything that needs rooms can just ask.

The audio tool in the Hammerite editor showing four rooms and a courtyard, a marker in each room and the openings between them outlined
The audio graph today. Nobody placed any of it.

Prior art

None of these ideas are new. Hammerite owes most of them to a handful of editors and one paper.

What next

The audio system that started all this now gets its rooms for free, and so does everything built since. If you want to try carving a few rooms yourself, the Hammerite docs start with exactly that.

- Elli