03 — Generating a Level

From noise to a floor plan

WFC hands us a legal field of floor blobs. A real dungeon needs more: a clean outer wall, no marooned islands, and enough resolution to walk around in. Four small steps get us there.

Step 1 — Coarse WFC, with a border and seeds

We run the solver on a small coarse grid — think of each coarse cell as a future room-sized chunk. Two hard constraints are bolted on before solving:

Step 2 — Connect the islands

WFC can leave the floor in several disconnected blobs. We find the connected components, then repeatedly carve an L-shaped corridor between the two nearest cells of the biggest blob and the next, until everything is one walkable space. Carved cells are tagged as corridor, not room — that distinction matters later.

Step 3 — Upsample

Each coarse cell is blown up into a K×K block of fine cells. A 2× or 3× upsample turns chunky blobs into rooms with room to move, while preserving the exact shape the solver chose.

Step 4 — Derive the walls

Finally we run the marching-squares deriveMasks() from Chapter 1 over the fine grid: every floor cell facing void grows a wall. The floor plan is done.

Step through the whole pipeline below — same seed, same code as the generator.

We now have a connected floor with a clean perimeter — but it’s still one big undivided space with corridors. Next we carve it into named rooms joined by doors: Rooms & Doors.