Worlds and levels
How the study’s sources make terrain, levels, tile dressing, scatter and settlements, and how they keep the results good. The best-documented generators are hybrids in which each step is small: noise and climate tables make terrain, a graph comes first for a level and templates fill it, wave function collapse (WFC) works on small regions with designer cells fixed before it starts, a dual-grid autotiler dresses the result, Poisson-disk scatter decorates it, and a sweep over many seeds proves it. Every shipped generator’s authored feel comes from three layers: hand-made structure on top, hand-made pieces at the bottom, and generate-and-test in between.
Proposed: none of this is in Tycho yet. The demos run here in the page, written in plain JS with the study’s own kit (demos/kit.js), not Tycho; each says how it would run in Tycho: per frame (the GPU stand-in’s calls), pre-bake (painted once offscreen), or shader (per-pixel work every frame). What would move into Tycho, and when, is in the roadmap.
Text marked (inference) is reasoning from the sources, not a sourced fact.
- Terrain from noise and climate tables
- Levels: a graph first, then templates
- Wave function collapse in small regions
- Autotiling on a dual grid
- Scatter
- Places with people
- Generate, then test
- Sources
Terrain from noise and climate tables
Red Blob Games documents the standard terrain pipeline (terrain from noise):
| Step | How |
|---|---|
| Octaves | Sum noise octaves with halving amplitudes, and divide by the total |
| Reshape | pow(e·fudge, exponent) flattens the valleys |
| Island | Mix in a falloff toward the edges, if the map is an island |
| Ridges | 2·(0.5 − abs(0.5 − n)), each octave weighted by the ones before it, so only mountains get detail |
| Terraces | round(e·n)/n |
| Biomes | A second noise channel gives moisture; an elevation-by-moisture table names the biome, from ocean to tropical rain forest |
Minecraft generalizes the table. Each biome is a “noise hypercube” in a space of temperature, humidity, continentalness, erosion and weirdness, and the biome at a point is the closest hypercube (Fabric Yarn docs). Storing biomes as points means adding one never rewrites a chain of thresholds (inference).
Domain warping, fbm(p + 4·q) with q itself an fBm, makes coastlines look authored rather than blobby (Inigo Quilez, via search excerpt). Droplet erosion carves believable valleys for tens of milliseconds of work (xarray-spatial). On tiny maps, rivers that run by steepest descent from high ground to water are cheaper and fully deterministic, in the style of Dwarf Fortress (DF Wiki).
fbm(p + 4q)) so coasts look drawn, and an elevation-by-moisture table that names the biome, after Red Blob Games. Rivers run downhill from high ground. Minecraft generalizes the table to "the nearest point in climate space", which lets a game add a biome without rewriting thresholds.Two of the games already do this:
- Merryfolk runs the most complete local version: fBm with ridges and knolls quantized to four terraces, then Priority-Flood depression filling, D8 flow accumulation and a wetness index (Merryfolk terrain.js).
- Lodestar lays its climes as a Voronoi field on a jittered grid with noise-warped borders, blending across them (Lodestar regions.js).
For Elsewhere, two details matter. The land must run off every edge, so unshaped noise beats island masks. And terraces of four to six steps map straight onto the cliff faces a 2:1 isometric grid can show, which suits a moor of low rises (inference).
Erosion, rivers and settlements done physically are in Real geography.
Levels: a graph first, then templates
The best-documented level generators are hybrids, and each step is small.
| Game | Structure | The numbers |
|---|---|---|
| Spelunky | A 4×4 grid of rooms; a walk lays the solution path, and each room is a 10×8 template whose glyphs are themselves chances | The walk moves left or right 40% of the time each and down 20%, which guarantees a solution; glyph “2” is 50% solid, “7” is 33% spike (Kazemi pt.1; Kazemi pt.2) |
| The Binding of Isaac | Rooms grown by breadth-first search; the boss in the farthest dead end | A 9×8 grid; restarts when the room count is wrong (Boris the Brave) |
| Brogue | Accreted rooms; a loop added only where the two sides of a wall are far apart by path | Lakes grown from 55% fill with five passes of a B5678/S45678 automaton; any lake that breaks passability is rejected (brogue.wiki) |
| Cellular-automaton caves | Random walls smoothed by the 4-5 rule, then a flood fill keeps the connected area | 40 to 45% walls to start (RogueBasin) |
| Unexplored | Cycles on a fixed 5×5 node grid, rewritten (lock-and-key, hidden shortcuts), each node expanded into a 5×5 block of tiles | 24 major cycle types and about 5,000 graph rewrite rules (Boris the Brave) |
| Dead Cells | A fixed island framework; each biome a concept graph filled with handmade room tiles | Monsters budgeted, for example one per five combat tiles (Deepnight) |
Neo already uses this shape: a random walk on a 7×7 grid that leans north, hand-drawn room templates mirrored at random, and flood-fill checks, pinned by golden hashes over 2,500 floors (Neo dungeon.js). Lodestar’s generateFloor mixes ellipse caverns whose radius ripples by sin(3a) and sin(5a), drifting tunnels with loops, one automaton smoothing pass, a flood-fill prune and random-walk ore veins (Lodestar floor.js). Elsewhere’s plan (its PLAN.md) names exactly this code as the source of “gen in Tycho’s world layer … for the moor and the dig”.
A quest-sized recipe follows (inference):
- Lay a 4×4 or 5×5 node graph with a start, a goal and one cycle.
- Optionally add a lock and key, with the key on the side reachable without the lock.
- Fill each node from probabilistic templates written as strings inside the quest file, which keeps the quest one closure.
Wave function collapse in small regions
WFC is Paul Merrell’s 2007 model synthesis reinvented for bitmaps. It observes the cell with the lowest entropy, collapses it by weighted frequency and propagates constraints. The simple tiled model, with adjacency lists and symmetry classes, is the practical one for a drawn tileset (mxgmn/WaveFunctionCollapse; Merrell). The problem is NP-hard. Contradictions are rare but real, and Karth and Smith found that global restarts rarely succeed under global constraints, which favors local backtracking (Karth slides).
On a phone, WFC belongs in small regions: a shopfront, a room’s furniture, a village block. It should run with designer cells (doors, a path, a landmark) collapsed before it starts, and retry deterministically on a contradiction with name + ':' + attempt (inference). The White Dragon’s facades and an Elsewhere tram carriage are natural targets.
Autotiling on a dual grid
Autotiling has a clear best answer for a small hand-drawn set (Classification of Tilesets; Quarter-Tile Autotiling):
| Set | Tiles for two terrains | How a tile is chosen |
|---|---|---|
| Blob | 47 (the “48-tile blob”) | By the eight neighbors of a cell |
| Corner (marching squares) | 16, or 6 with rotation and mirroring | By the terrain at its four corners |
| Dual grid | 16 | Terrain sits on cell centers, and tiles are drawn at a half-cell offset, each chosen by the four terrains at its corners |
Boris the Brave calls the dual grid “a substantial improvement” over the 48-tile blob. LDtk’s auto-layer rules, small grid patterns that paint a tile when they match, are a good plain-data format for a game’s own decoration rules (LDtk docs).
No source covered the dual grid on an isometric diamond grid. It should carry over directly, because a 2:1 iso grid is a square grid seen at an angle. Lit faces break rotational symmetry, so budget for all 16 tiles per terrain, and layer terrains in priority order rather than drawing every pairwise transition (inference). Today, Neo’s only autotile rule is “draw a wall face if the tile below is not wall”, and Merryfolk rounds edges by a noise-warped Gaussian vote of tile kinds instead of picking tiles (Neo render.js; Merryfolk world.js).
Scatter
Bridson’s algorithm places decoration by Poisson-disk sampling in O(N), with k = 30 tries per point by default (Bridson 2007). Varying the minimum distance by noise varies the density (devmag). For chunked worlds, one seeded point per global grid cell (a jittered grid) is seamless across chunk borders and needs no neighbor lookups (inference). Elsewhere’s lily pads already use rejection sampling with a minimum distance of 34 (its quests/frogs/frogs.js).
Places with people
Settlement generators are mostly geometry. Watabou says the Voronoi diagram is the only special piece of his city generator and “not really necessary” (itch.io comment). Parish and Müller grew roads as L-systems steered by density and terrain, snapping to existing roads to close loops (SIGGRAPH archive). Watabou’s hardest problem was coherent text: “Narrative stuff is hard” (RandRoll interview). Wildermyth’s team built generation around characters, not plot, for the same reason (Turn Based Lovers). Caves of Qud keeps its history legible with five fixed periods of sultan rule whose contents are generated and tied to sites in the world (Qud wiki).
For a game whose people are Tyrell minds, as Elsewhere’s are, the transferable loop runs in four steps, all under one named stream such as ctx.rng('history') (inference):
- Generate a few people, each with a need and a relationship.
- Write three to five events that link people to places.
- Lay out the place so each event leaves something the player can find.
- Feed the events to the minds as memories.
Generate, then test
The authored feel of every shipped generator comes from the same three layers: hand-made structure on top, hand-made pieces at the bottom, and generate-and-test in between. Isaac restarts floors, Brogue rejects lakes, Dwarf Fortress rejects worlds, and RogueBasin regenerates caves that are too closed (Boris the Brave; brogue.wiki; DF Wiki). Smith and Whitehead’s expressive range analysis judges the generator as a whole: it scores many outputs on two metrics and plots them as a heatmap (arXiv 2004.10808).
The games already pin generation with golden hashes, bots and smoke tests (Neo checks 2,500 floors; Elsewhere has bots, smoke tests and golden frames). The natural addition is a sweep over a thousand seeds in Node that checks invariants: the goal is reachable, every person has a reachable home, no frame uses more than eight inks. At runtime, a bounded retry by sub-seed keeps generation deterministic, and a short list of curated seeds can guarantee a good first visit (inference).
Sources
- Red Blob Games, terrain from noise
- Fabric Yarn docs, Minecraft’s noise hypercube
- Inigo Quilez, domain warping
- xarray-spatial, droplet erosion
- Dwarf Fortress Wiki, world generation
- Darius Kazemi, Spelunky’s generator, part 1 and part 2
- Boris the Brave, dungeon generation in The Binding of Isaac
- brogue.wiki, level generation
- RogueBasin, cellular automata caves
- Boris the Brave, dungeon generation in Unexplored
- Deepnight, the level design of Dead Cells
- mxgmn, WaveFunctionCollapse and Paul Merrell, model synthesis
- Isaac Karth, WFC slides
- Boris the Brave, classification of tilesets and quarter-tile autotiling
- LDtk, auto-layer rules
- Robert Bridson, fast Poisson-disk sampling (2007) and devmag, Poisson-disk sampling
- Watabou, on his city generator and the RandRoll interview
- Parish and Müller, procedural modeling of cities
- Turn Based Lovers, interview with Wildermyth’s developer
- Caves of Qud wiki, world generation
- On expressive range analysis (arXiv 2004.10808)
- The games: Merryfolk terrain.js and world.js, Lodestar regions.js and floor.js, Neo dungeon.js and render.js
The full research is in the notes on world generation and on settlements, paths and vegetation.