MGGet in touch
All posts
GUIGuides

Designing for Constraint: A Practical Intro to Wave Function Collapse

How constraint-based procedural generation actually works, and a minimal implementation you can drop into a Unity project this weekend.

MGMichael GiftJune 2, 2026 9 min read Open in editor

Most procedural generation tutorials start with noise functions and stop there. Wave Function Collapse (WFC) is a different way in: instead of sampling randomness directly, you describe local adjacency rules — which tile can sit next to which — and let the algorithm propagate constraints until every cell in the grid is resolved.

The core loop

WFC treats each cell in your output grid as a superposition of every tile that hasn't been ruled out yet. The loop is simple:

  • Pick the cell with the lowest entropy — the fewest remaining possibilities.
  • Collapse it to a single tile, weighted by your input frequencies.
  • Propagate that choice outward, removing now-invalid options from neighboring cells.
  • Repeat until every cell has collapsed, or you hit a contradiction and backtrack.

That's the whole algorithm. The interesting engineering work is in step two and three: how you represent adjacency rules, and how efficiently you propagate.

A minimal entropy picker

The engine-agnostic core is plain data manipulation — no MonoBehaviours, nothing Unity-specific. That makes it unit-testable outside the editor:

javascript
function lowestEntropyCell(grid) {
return grid.cells
.filter((c) => !c.collapsed)
.reduce((min, c) =>
c.options.length < min.options.length ? c : min
);
}

function collapse(cell, weights) {
cell.value = weightedPick(cell.options, weights);
cell.collapsed = true;
return cell;
}

Where it earns its keep

WFC shines when your content has implicit grammar — dungeon layouts, circuit-like level geometry, tile-based terrain — anything where "this piece touches that piece" is a real constraint, not just texture. It's a poor fit for content that's genuinely continuous, like terrain heightmaps, where noise-based approaches are simpler and cheaper.

Treat the solver as a pure function of constraints in, grid out — the moment it knows about Unity, you've lost the ability to test it in isolation.

The full toolkit, including the in-editor authoring workflow, is linked in the portfolio section above.