Jaconir

Procedural Level Generation: How to Build Infinite 2D Game Worlds

March 13, 2026
9 min read

Procedural level generation is the technique of creating game levels algorithmically rather than by hand. Every run of Spelunky, The Binding of Isaac, or Dead Cells produces a different layout because the levels are generated at runtime from a set of rules, not loaded from a fixed file. The result is virtually unlimited replayability from a relatively small codebase. This guide covers the core algorithms — BSP dungeon generation, cellular automata caves, and Perlin noise terrain — and how to prototype them instantly with a free browser tool.

Generate 2D levels in your browser with Jaconir 2D Procedural Level Generator — configure the algorithm, size, and parameters, and export to a tile array ready to use in your game engine.

Why Use Procedural Generation?

  • Infinite replayability: Each run produces a unique layout
  • Reduced content creation time: One algorithm replaces dozens of hand-made maps
  • Scalable content: Change parameters to produce easy, medium, or hard layouts
  • Surprise and discovery: Neither the player nor designer knows what each run contains

The tradeoff is control — handcrafted levels offer precise pacing and storytelling that procedural levels cannot. Most games that use procgen combine it with curated setpieces, fixed boss arenas, or hand-designed starting areas.

Algorithm 1: BSP Dungeon Generation

Binary Space Partitioning (BSP) is the most common algorithm for dungeon generators. It produces room-based layouts with reliable connectivity — every room is reachable.

How it works:

  1. Start with the full map area as a single rectangle
  2. Split it in half (randomly horizontal or vertical)
  3. Recursively split each half until regions are small enough for a single room
  4. Place a room inside each leaf region (with random padding)
  5. Connect sibling rooms with corridors, working back up the BSP tree

Result: Clean rectangular rooms connected by corridors. Predictable but feels natural. Best for dungeon crawlers, roguelikes with loot rooms, and any game where room identity matters.

// Simplified BSP split
function splitNode(node, minSize) {
  const splitHorizontal = Math.random() > 0.5;
  const splitPos = splitHorizontal
    ? Math.floor(node.y + minSize + Math.random() * (node.height - minSize * 2))
    : Math.floor(node.x + minSize + Math.random() * (node.width - minSize * 2));

  if (splitHorizontal) {
    node.left  = { x: node.x, y: node.y, width: node.width, height: splitPos - node.y };
    node.right = { x: node.x, y: splitPos, width: node.width, height: node.y + node.height - splitPos };
  } else {
    node.left  = { x: node.x, y: node.y, width: splitPos - node.x, height: node.height };
    node.right = { x: splitPos, y: node.y, width: node.x + node.width - splitPos, height: node.height };
  }
}

Algorithm 2: Cellular Automata Caves

Cellular automata produces organic cave-like spaces that feel natural and irregular — the opposite of BSP's clean rectangles. Used in games like Caves of Qud and many cave-themed roguelikes.

How it works:

  1. Fill the map randomly — each cell is wall (1) or floor (0) with a set probability (typically 45% floor)
  2. Apply the automata rule repeatedly (4–6 iterations): if a cell has 4 or more wall neighbours, it becomes a wall; otherwise it becomes a floor
  3. The random noise resolves into smooth, organic cave shapes
  4. Remove isolated regions to ensure connectivity
function cellularStep(grid, width, height) {
  const next = grid.map((row, y) =>
    row.map((cell, x) => {
      let wallCount = 0;
      for (let dy = -1; dy <= 1; dy++) {
        for (let dx = -1; dx <= 1; dx++) {
          if (dx === 0 && dy === 0) continue;
          const nx = x + dx, ny = y + dy;
          if (nx < 0 || nx >= width || ny < 0 || ny >= height) wallCount++;
          else if (grid[ny][nx] === 1) wallCount++;
        }
      }
      return wallCount >= 5 ? 1 : 0;
    })
  );
  return next;
}

Algorithm 3: Perlin Noise Terrain

Perlin noise generates smooth, continuous random values that produce natural-looking terrain — rolling hills, gradual elevation changes, coherent biome shapes. Used in Minecraft, Terraria, and virtually every open-world game.

How it works: Perlin noise produces a value between -1 and 1 for any (x, y) coordinate. Values above a threshold = solid ground, below = open space. Layering multiple noise functions at different scales (octaves) produces terrain with both large features and fine detail.

// Using a noise library (simplex-noise)
import { createNoise2D } from 'simplex-noise';
const noise2D = createNoise2D();

function generateTerrain(width, height) {
  return Array.from({ length: height }, (_, y) =>
    Array.from({ length: width }, (_, x) => {
      // Layer multiple octaves
      const n = noise2D(x * 0.05, y * 0.05) * 0.6
              + noise2D(x * 0.1,  y * 0.1)  * 0.3
              + noise2D(x * 0.2,  y * 0.2)  * 0.1;
      return n > 0.1 ? 1 : 0; // 1 = solid, 0 = air
    })
  );
}

Ensuring Connectivity

The most common problem with procedural levels is generating unreachable areas. After generating, always run a flood fill from the player start position and check that all required areas are reachable. If not, regenerate or connect isolated regions with a corridor.

function floodFill(grid, startX, startY) {
  const visited = new Set();
  const queue = [[startX, startY]];
  while (queue.length) {
    const [x, y] = queue.shift();
    const key = `${ x }, ${ y }`;
    if (visited.has(key) || grid[y]?.[x] !== 0) continue;
    visited.add(key);
    queue.push([x+1,y],[x-1,y],[x,y+1],[x,y-1]);
  }
  return visited;
}

Using the Procedural Level Generator

Open Jaconir 2D Procedural Level Generator, select your algorithm, configure the parameters (map size, room count, fill probability), and generate. The tool outputs a 2D tile array you can paste directly into your game engine. Regenerate until you get a layout that fits your game's needs, then export.

FAQ

Which algorithm should I use for my game?

BSP for dungeon crawlers with distinct rooms and loot placement. Cellular automata for cave exploration games with organic layouts. Perlin noise for open-world or Terraria-style terrain. Most games benefit from combining algorithms — use BSP for room layouts and cellular automata for cave sections.

How do I place enemies and items in procedurally generated levels?

After generating the tile map, identify valid placement zones (floor tiles away from the player start, dead-end rooms, etc.) and randomly place content within those zones. Weight placements by distance from start for difficulty scaling.

Can I seed procedural generation for reproducible levels?

Yes — all major random number generators accept a seed value. Using the same seed always produces the same level, enabling level sharing via seed codes (like Minecraft seeds).

Conclusion

Procedural generation turns a single algorithm into effectively unlimited content. BSP gives you reliable dungeon layouts, cellular automata gives you organic caves, and Perlin noise gives you infinite terrain. Combining them gives you a complete world generation system. Start simple with one algorithm and expand from there.

Generate your first level: Jaconir 2D Procedural Level Generator →