# World map generation: comparison Three generators, one JSON shape, five shared styles. Open `index.html`. | | 1. Noise heightmap | 2. Voronoi polygons | 3. Wave function collapse | |---|---|---|---| | Geography | continents, ridged mountain chains, real watersheds | similar, blob-shaped islands, blocky biomes | patchwork; no continents or chains | | Rivers | flow accumulation, source to sea, lakes from depression fill | same idea on the polygon graph | only via the shared heightfield pipeline; many short ones | | Cities / roads | scored placement, A* roads that merge, bridges/fords, sea routes | same, on the graph (fast) | shared pipeline | | Constraints ("mountains in the north") | bias the elevation field | place blobs / cone chains | pin tiles (most direct, but nothing grows from a pin) | | Code | ~350 lines + shared | ~200 lines + shared, incl. Delaunay | ~100 lines + shared | | Generate time (browser) | ~0.6 s | ~0.35 s | ~0.4-0.9 s | Styles, all reading the same heightfield + places + edges: **parchment** (sepia, ink coastline with ripple lines, contour lines, mountain/tree/swamp glyphs, serif labels, compass, scale bar), **painted** (biome colours with hillshading), **hex** (majority biome per hex, flat colours and icons), **iso** (2D canvas columns), **3d** (three.js terrain, rendered once into the canvas with projected labels). Voronoi adds **polygons**, WFC adds **tiles**. ## Data shape (all three) - World row: `representation: "world_map"`, `gen_state: "generated"`, `representation_data`: `{kind:"heightfield", generator, seed, w:240, h:160, cell_km:4, sea_level:0, elevation:{encoding:"u8-base64", decode:"e = byte/127.5 - 1", data}, biome:{encoding:"u8-base64", legend:[...], data}, rivers:[{name, flow_max, pts:[[x,y],...]}], crossings:[{x,y,kind:"bridge"|"ford"}]}` (about 100 KB raw; 51 KB of it base64 per layer). - Children: cities, towns, ruins, dungeons and natural features (mountains, forest, lake, desert, swamp, hills) as `narrative`/`stub` rows with `map_x/map_y` in heightfield cells, `danger_level`, a placeholder `description`. - `location_edges`: `path_kind` road | trail | river | sea, `travel_cost` in **hours** (on foot; boat for river/sea, in `travel_unit`), `bidirectional`, `curve` = polyline in cells. Slugs instead of ids in the samples. ## Recommendation **Use approach 1 (noise heightmap) for the world map**, run in the browser on the world-builder page and post the chosen result as JSON to Laravel (1-2 evenings to wire up, no PHP port needed unless the AI must generate worlds unattended). It gives the most believable geography, every travel number the game needs, and the heightfield makes any visual style a pure renderer. Parchment fits the hand-drawn aesthetic the design doc asks for; hex is there for players who want the classic look; 3d is a nice extra. Let the AI work on top of it: the generator places, the AI names and describes the stubs from their context (coast, river, biome, roads, distances) and later promotes them to site maps; for "a mountain range in the north, a port in the south-east", add constraint terms to the elevation field and biases for settlement placement. The noise page has a working demo: "AI constraint: mountain range" (north/south/east/west/center adds a ridge band to the elevation) and "port city" (a big score bonus for coastal cells in that corner), e.g. `noise/index.html?seed=7&mountains=north&port=se`. A full constraint language (several ranges, named regions, forests, a river from A to B) is about 1-2 evenings. Voronoi is a valid alternative with a nice polygon style, but costs more code for the same result. WFC is the wrong tool for a world map (local consistency, no global structure); keep it in mind for site maps, dungeon levels and tactical grids where local rules matter. ## Known gaps - AI constraints: only two demo controls on the noise page (mountain range region, port city region) and the WFC pins. - Label placement is a simple collision check; crowded seeds can still overlap a glyph. - The voronoi island shape is dominated by its radial falloff; WFC produces many small lakes. - Hex style samples the heightfield; it is a view, not hex game data. - `river` edges (boat travel between settlements on the same river) only appear when two settlements sit within 2.5 cells of the same traced river; on many seeds there are none. - Travel hours assume 4.8 km/h walking without rest; days of travel need a rule (e.g. 8 h per day) in the game.