Wave Function Collapse Tutorial: Build Infinite Procedural Worlds for Your Game

Wave Function Collapse Tutorial: Build Infinite Procedural Worlds for Your Game

After implementing procedural generation in over a dozen game projects, I can tell you that Wave Function Collapse (WFC) is the most underrated algorithm in an indie developer’s toolkit. While most tutorials drown you in quantum mechanics metaphors, this guide cuts straight to what actually matters: building something that works.

Table of Contents

Quick Answer

  • What it is: An algorithm that generates content by collapsing possibilities based on neighbor constraints
  • Best for: Tilemaps, dungeons, cityscapes, texture synthesis, and any grid-based content
  • Core concept: Each cell starts with all possibilities, then collapses to one based on what neighbors allow
  • Time to implement: 2-4 hours for a basic version, 1-2 days for production-ready
  • Works in: Unity, Godot, Unreal Engine, or any language/engine with 2D arrays

What Is Wave Function Collapse?

Wave Function Collapse is a procedural generation algorithm that creates coherent, constraint-based content from a set of tiles and rules. Unlike purely random generation, WFC ensures that every piece fits logically with its neighbors—producing results that feel designed rather than chaotic.

The algorithm was created by Maxim Gumin in 2016 and quickly gained popularity for its ability to generate everything from 2D tilemaps to 3D voxel structures. Games like Caves of Qud, Bad North, and Townscaper use variations of WFC for their procedural content.

The name comes from quantum mechanics, but don’t let that intimidate you. In practice, WFC is just a clever constraint satisfaction algorithm. Think of it like solving a Sudoku puzzle: each cell has multiple possibilities until you narrow it down based on rules.

How the Algorithm Works

WFC follows a simple loop that repeats until the entire grid is filled:

Step 1: Initialize the Grid

Every cell in your grid starts in a “superposition” state—meaning it could become any tile. If you have 10 different tile types, each cell has 10 possibilities.

Step 2: Find the Cell with Lowest Entropy

Entropy here means “number of remaining possibilities.” Find the cell with the fewest valid options remaining. If multiple cells tie, pick one randomly.

Step 3: Collapse That Cell

Randomly select one tile from the remaining possibilities and assign it to that cell. That cell is now “collapsed” and fixed.

Step 4: Propagate Constraints

This is the key step. Look at all neighbors of the collapsed cell and remove any tile possibilities that would violate your rules. If a neighbor’s possibilities change, propagate those changes to its neighbors, and so on.

Step 5: Repeat or Backtrack

Return to Step 2. If you ever reach a cell with zero possibilities (a contradiction), you need to backtrack—undo recent collapses and try different choices.

Step-by-Step Implementation

Here’s a practical implementation approach that works in any language:

Define Your Tiles and Adjacency Rules

Start simple. For a basic terrain generator, you might have:

  • Water — Can only be next to water or sand
  • Sand — Can be next to water, sand, or grass
  • Grass — Can be next to sand, grass, or forest
  • Forest — Can only be next to grass or forest

Store these rules as adjacency lists. For each tile type, maintain a set of valid neighbors for each direction (up, down, left, right).

Build the Core Data Structure

Each cell needs to track its remaining possibilities. A common approach:

Cell {
    possibleTiles: Set<TileType>
    collapsed: boolean
    finalTile: TileType | null
}

Implement the Propagation Function

When a cell collapses, propagation is crucial. Use a stack or queue:

  1. Add the collapsed cell to a “to propagate” stack
  2. Pop a cell from the stack
  3. For each neighbor, filter out tiles that can’t be adjacent to the current cell’s possibilities
  4. If a neighbor’s possibilities changed, add it to the stack
  5. Repeat until stack is empty

This constraint propagation is what makes WFC powerful. One collapse can cascade through the entire grid, dramatically reducing possibilities everywhere.

Handle Contradictions

Sometimes you’ll paint yourself into a corner—a cell ends up with no valid possibilities. Options for handling this:

  • Full restart: Clear everything and try again (simple but wasteful)
  • Local restart: Reset a region around the contradiction
  • Backtracking: Track your collapse history and undo recent decisions

For games, local restart often works well and is simpler to implement than full backtracking.

Common Use Cases and Patterns

2D Tilemaps

The most common use case. WFC excels at generating coherent terrain, dungeon layouts, or cityscapes from small tile sets. The key is designing tiles with matching edges—what’s often called “Wang tiles.”

3D Voxel Structures

Extend the algorithm to six directions (up, down, left, right, forward, back). Townscaper uses this approach to generate charming procedural buildings.

Texture Synthesis

WFC can analyze a sample image and generate infinite variations. This “overlapping model” variant looks at NxN pixel patterns rather than discrete tiles.

Dungeon Generation

Define room tiles, corridor tiles, and connection rules. WFC naturally creates branching layouts that feel hand-designed.

Pro Tips

  • Start with weighted randomness: Assign probabilities to tiles when collapsing. Want more grass than forest? Make grass 3x more likely to be chosen.
  • Design tiles with symmetry: Tiles that work in multiple rotations reduce the number of unique assets you need.
  • Seed the edges: Pre-collapse border cells to control the overall shape. Want water around the edges? Force it.
  • Cache propagation: If performance matters, pre-compute which tiles can be adjacent. Don’t recalculate rules every propagation step.
  • Visualize the process: Watching WFC collapse in real-time helps you debug rule issues and creates impressive dev content for social media.
  • Layer multiple passes: Generate terrain first, then run a second WFC pass for decorations. Each layer can have different rules.
  • Test your rules exhaustively: A single bad adjacency rule can cause cascading contradictions. Build a rule validator that tests every possible neighbor combination.

FAQ

Is WFC better than Perlin noise?

They solve different problems. Perlin noise generates smooth, continuous values—great for heightmaps and gradients. WFC generates discrete, rule-following content—perfect for tiles and structures. Many games use both: Perlin noise for terrain elevation, WFC for tile placement.

How do I make WFC faster?

Three optimizations matter most: Use arc consistency (AC-3) for smarter propagation, implement constraint propagation with bitsets for fast set operations, and generate chunks asynchronously if you need real-time infinite worlds.

Can WFC guarantee a valid output?

Not always. Some rule sets are unsatisfiable or have very few solutions. Design your tiles to be “flexible”—each tile should be able to connect to multiple others. If you’re seeing frequent contradictions, your rules are too restrictive.

What’s the difference between the tile model and overlapping model?

The tile model uses discrete, predefined tiles with explicit adjacency rules. The overlapping model extracts patterns from a sample image automatically. Tile model is easier to control; overlapping model requires less manual setup but can produce unexpected results.

Should I use an existing WFC library or write my own?

For learning, write your own—it’s only a few hundred lines of code. For production, consider existing implementations like the original mxgmn repository, unity-wave-function-collapse, or Godot-WFC plugins. They handle edge cases you’ll otherwise spend weeks discovering.

Summary

Wave Function Collapse is a powerful procedural generation algorithm that creates coherent, constraint-based content from simple rules. By iteratively collapsing cells from highest uncertainty to lowest while propagating constraints, WFC produces results that feel designed rather than random.

Start with a small tile set and simple adjacency rules, get the core loop working, then expand from there. The algorithm scales from basic 2D tilemaps to complex 3D structures—and once you understand it, you’ll find applications everywhere in game development.

The best way to learn WFC is to implement it yourself. Set aside an afternoon, pick your favorite engine, and build a basic terrain generator. You’ll have procedural worlds generating within hours.

Related posts