↤ mappa

mappa — a procedural world engine

A deterministic planet generator that runs entirely on the sphere: plate tectonics with real Euler-pole motion, hydraulic erosion, a water-volume ocean, latitude-and-altitude climate, Whittaker biomes, and a political atlas — all from a single seed and a handful of genes. Open, dependency-free, and pullable as an API.

00What it is

Every world is generated from an integer seed plus an optional genome — about six global scalars and a set of tectonic plates. The plates are the spine: ~90% of a world's identity lives in their positions and motions; the rest is a few knobs. The same seed and genome always produce the same planet, on any machine.

Nothing is hand-painted. The terrain, coastlines, mountain belts, rivers, climate zones, and biomes are all emergent from a physical-ish simulation. The mino.mobi “atlas” (civilizations, countries, cities, roads) is a separate projection laid on top of whatever world the engine produced.

01The genome

Each gene can be left to derive from the seed or pinned to a value (in the ⚙ genome panel, or via the API). Genes are orthogonal: the RNG stream always draws the seed-derived value first, so changing one gene leaves the others — and the seed's character — intact.

GeneRangeWhat it does
planetRadius0.3 – 3.0 R⊕Two coupled effects: plate count ∝ area (r1.3) and relief ∝ 1/gravity (r−0.55). A small world has few plates but dramatic, tall terrain (Olympus Mons); a big world has many plates but flat terrain (gravity caps mountains).
age1 – 20 epochsGeological time. Plates drift about their Euler poles by speed × age; a multi-epoch pass keeps the strongest convergence each cell ever saw, so orogenic belts widen and develop with age. Older worlds have continents far from their origin.
plateCount3 – 60Number of tectonic plates. More plates → more boundaries → more fragmented, complex coastlines.
oceanFraction0.20 – 0.90Fraction of plates that are oceanic crust (deep basins) vs continental. Shapes where the deep ocean basins are.
waterFrac0.02 – 0.40The volume of water poured over the topography. Sea level is solved so the water settles into the basins — coverage is emergent, not imposed.
axialTilt0° – 45°Obliquity → seasonality. Drives the depth of winter by latitude and continentality, which feeds the biome classifier (more tilt → bigger ice/taiga belts).
rotationRate−2.5 – 2.5 ×Ω⊕Planetary spin, signed. |Ω| sets how many atmospheric circulation cells fit per hemisphere (slow → 1–2 giant cells, Earth → 3, fast → up to 6 narrow jets) and how zonal the winds are; it also sets day length (1/|Ω|). The sign is the spin direction — negative is retrograde, which flips the Coriolis deflection and reverses every prevailing wind.
solar0.5 – 1.8 ×Stellar luminosity. Shifts the whole temperature field → an ice world (dim) ↔ a desert world (bright).

02The generation pipeline

Everything happens on the unit sphere — no map projection during generation, so there's no distortion or seam in the physics.

Adaptive spherical mesh. Points are Fibonacci-sampled, then rejection-sampled so density concentrates on continents and along plate boundaries (coasts, ranges, trenches) and thins in deep ocean — resolution where it counts. The dual of a Delaunay triangulation (computed via stereographic projection + a ghost north-pole vertex, Euler-verified) gives the spherical Voronoi cells.
Plates as Euler rotors. Random plates, each with a centre, a rotation axis (Euler pole), an angular speed, and a continental/oceanic type. Surface velocity is v = ω × p. Boundaries are domain-warped by 3-D noise so they're fractal and jagged, not smooth Voronoi arcs.
Tectonic history. Over age epochs the plates drift; convergence at the moving boundaries accumulates as orogeny — continent–continent collisions raise ranges, continent–ocean subduction raises coastal arcs + offshore trenches, ocean–ocean divergence makes mid-ocean ridges, and rifts pull apart. Belts widen as boundaries sweep.
Elevation. Continental cratons + accumulated orogeny + plate-type base + 3-D noise. Oceanic crust uses seafloor-age bathymetry: crust is born at the mid-ocean ridges and its age (a BFS hop-distance from the ridges over ocean cells) sets depth ∝ √age via half-space cooling — ridges run shallow, abyssal plains deep. Relief is scaled by gravity (from planetRadius) and compressed through an Earth-like hypsometry so most land is lowland and mountains are the exception.
Sea level by volume. A fixed volume of water is poured over the real topography and settles — solving Σ areaᵢ · max(0, h − elevᵢ) = V for the level h, weighted by true spherical cell area. Deep basins hold water at depth, so continents stay dry instead of flooding to a quota.
Hydraulic erosion. Drainage-area valley carving + hillslope diffusion over several iterations. Produces dendritic drainage networks (the “texture”), sharp continental divides (rivers sit in carved valleys and never cross ridges), and eroded coastlines.
Winds & climate. Rotation sets the prevailing surface winds via a banded circulation model — trade easterlies, westerlies and polar easterlies, with the cell count and zonality driven by rotationRate and the deflection sign by its sign (retrograde reverses them). Temperature comes from latitude + altitude lapse + solar. Moisture is then advected: ocean humidity is carried downwind and rains out, so windward coasts are wet and lee sides / deep interiors fall into rain shadow; this is layered over the circulation's wet (rising) and dry (sinking, subtropical) bands. Seasonality from axial tilt × latitude × continentality.
Biomes & cryosphere. A Whittaker classification (temperature × a growing-season-limited moisture) → tundra, taiga, steppe, temperate & tropical forests, savanna, hot & cold deserts, ice, alpine, snow. The coldest land grows glaciers / ice caps and ocean below seawater freezing (~−2 °C) freezes into sea ice, so dim-sun / high-tilt worlds wear real polar caps.
Volcanoes. Derived from the tectonics already computed: continental subduction arcs, ocean–ocean island arcs, and a sparse intraplate hotspot field. Surfaced and named on the Relief view.
Rivers & lakes. Priority-flood depression filling + downhill flow accumulation on the mesh graph; channels above a flow threshold become rivers, filled basins become lakes.

03Views

The mode bar separates projection (Orb / Mercator) from the content layer, so the layers below ride on either the globe or the map:

Civ and Tectonic are map-designed, so selecting them snaps to Mercator. Fossils and Paleo ride on either the globe or the map.

The atlas projection

The mino.mobi sites are not part of the engine — they are projected onto whatever world was generated. Land is scored for habitability (biome + elevation); spherical k-means partitions the habitable land into nine civilizations (the theme-wings), each matched to a region; every civilization is then subdivided into sovereign countries by clustering its cities (most hold one city, the largest two or three); cities place by habitability + spacing + founding age; and a road network is the least-cost path from each country's capital over land.

Names & toponymy

The map carries two kinds of name. City names come from the atlas — they are the real mino.mobi sites, projected on. Every geological feature (the highest peak, the deepest trough, the volcanoes, the ore deposits, the dig sites) is named by the engine, deterministically from the world seed — same world, same names, for ever.

A feature name is a specific root + a generic term that fits the feature — Mount Kruth, Thauld Deep, Dambra Caldera, Naish Lode, Vaelele Bonebeds. The root is built from syllables — an onset, a nucleus (vowel), and an optional coda — and the generic is drawn from a per-kind set:

FeatureGeneric terms
PeakMount · Pike of · Cairn · … Tor / Horn / Fell / Crag / Scaur / Spire
Trough… Deep / Trench / Abyss / Trough / Fault / Sink / Gulf
VolcanoMount … · … Fell / Caldera / Pyre / Forge / Smokes / Ashmount
Ore deposit… Lode / Field / Diggings / Reach / Vein / Workings / Mine / Strike
Dig site… Beds / Quarry / Pits / Bonebeds / Marl / Hollow / Cutting

The point of the system is linguistic coherence: the syllable palette is one of several language families (Varn — harsh, northern; Lyr — liquid, upland; Mor — round, lowland; Kael — bright, southern; Esh — sibilant, coastal), and the family is chosen per tectonic plate. So every feature on one landmass shares a tongue — a mountain and a mine on the same continent rhyme — and the language borders fall along the plate sutures, exactly where Earth's real linguistic divides tend to sit (the Caucasus, the Himalaya, the Alps). Names aren't decoration here; they're another reading of the tectonics.

04World API

Pull a complete, deterministic world as JSON. CORS-open, edge-cached, no key. The same (seed + parameters + n) always returns the same world.

GET https://mino.mobi/api/world?seed=7&n=1800&radius=0.7&age=8&solar=1.1

Query parameters

ParamDefaultMeaning
seed1Integer world seed.
n1500Target cell count (500–2200). The browser engine runs far higher; the API is capped by server CPU.
radius—Planet radius in R⊕ (0.3–3.0). Omit to derive.
age—Geological epochs (1–20).
plates—Plate count (3–60).
ocean—Oceanic-crust % (20–90).
water—Water-volume % (2–40).
tilt—Axial tilt in degrees (0–45).
rotation—Planetary spin, signed (−2.5–2.5 ×Ω⊕; negative = retrograde).
solar—Stellar luminosity (0.5–1.8).

Response

{
  "api": "mappa.world/v1",
  "meta": { "seed": 7, "n": 1468, "plateCount": 20, "oceanFraction": 0.58,
            "waterFrac": 0.24, "seaCoverage": 0.55, "axialTiltDeg": 9,
            "solar": 1.15, "planetRadius": 0.6, "age": 9, "ageSpan": 0.9 },
  "biomes": [ { "id": "tundra", "name": "tundra", "color": [150,12,60] }, … ],
  "n": 1468,
  "points": [ [lon, lat], … ],          // degrees, one per cell
  "elev":   [ … ],                      // shore = 0, + land / − sea
  "water":  [ … ],                      // 0 land · 1 ocean · 2 lake
  "biome":  [ … ],                      // index into `biomes`
  "rivers": [ [lon,lat, lon,lat, flow], … ],   // downstream segments
  "plates": [ { "lon","lat","oceanic","speed" }, … ]
}

The arrays are parallel and one entry per cell. biome[i] indexes the biomes legend; each colour is [hue, saturation%, lightness%]. To render: place each cell at its points[i] and colour by biome, or feed the points to your own Voronoi/triangulation for a polygon map.

Examples

# a small, dramatic, ancient dwarf planet
/api/world?seed=42&radius=0.5&age=12

# a bright, drowned ocean world
/api/world?seed=99&solar=1.3&water=30&ocean=80

# fetch + read the genome
curl -s "https://mino.mobi/api/world?seed=7" | jq .meta

Note: the API runs the reference (JavaScript) engine; the browser viewer runs the Rust/WASM engine at higher resolution. Both are internally deterministic, but a given seed renders at a different cell count between them, so they are not pixel-identical — the API is its own self-consistent world source.

05Sharing & interestingness

A world is a pure function of its config — { seed, genome, n } — so the config is the world: a few hundred bytes that regenerate the whole planet, deterministically, anywhere. That makes a world a first-class shareable artifact.

Two transports

Opening a published world

Loading closes the loop. A record's canonical link — /mappa/?at=<at-uri> (or ?did=&rkey=) — opens that exact world straight from its PDS, no token needed; the share panel also takes an at:// URI directly, or a @handle to browse that person's published worlds (a small gallery of name · ★score · descriptor, click to open). Reads are public and unauthenticated (com.atproto.repo.getRecord / listRecords), and an ?at= link unfurls into the same rich card. The world still regenerates from the config — the stored interestingness is just the publisher's snapshot — so a loaded world is live and re-shareable, and any note the publisher attached rides along. (This is the discovery primitive a "best worlds" feed would sit on.)

Rich link cards

The share link unfurls. Two Pages Functions render the card server-side (crawlers can't run the viewer): /mappa/card serves per-world Open Graph / Twitter meta — the world's name (its largest landmass, in that landmass's language) and its interestingness descriptor (★ 88/100 · A temperate cluster of four continents with a great inland sea, 63% ocean) — and bounces a human to the live viewer; /mappa/og draws the planet to a PNG — an equirectangular biome map of that exact world, with no image library (nearest-cell sampling + the platform's CompressionStream for the PNG deflate). Both are deterministic and content-addressed by the config, so they edge-cache forever after the first render.

What makes a world interesting?

A board game has a free answer to "is this good?" — you play it, and skill-beats-chance / it-ends / it's-fair are ground truth. A world has no objective to play, so "interesting" isn't a normative, simulatable property. It's variety, contrast, structure and story-potential — and the opposite, a featureless monotone, is the degeneracy to screen out. lib/world-signals.js is a hand-authored signal battery: a weighted set of measurements over the engine's own fields, each 0–1, summed to a 0–100 score with degeneracy flags and an evocative one-line descriptor.

SignalWhat it measuresWeight
structurecontinents vs. one Pangaea vs. archipelago — reward several substantial landmasses, no single dominant blob22
climatebiome (Whittaker) Shannon-entropy + whether it spans tropics→temperate→poles22
reliefreal high ground, a lively plate count, a mountainous fraction16
habitabilityarable land — not barren, not wall-to-wall jungle — split into several separated homelands (the geopolitics proxy)16
sealand/sea balance, a goldilocks band around ~60% ocean12
hydrologyriver density, lakes, and the rare enclosed inland sea (a Mediterranean — story gold)12

Degeneracy flags — waterworld, iceball, desert-world, monobiome, one-supercontinent, all-archipelago, flat-world — both lower the relevant signal and dock the score, so the monotone extremes rank clearly below the gems. Positive highlights (inland sea, high mountains, full climate range, great rivers) feed the descriptor, e.g. "A verdant cluster of three continents with a great inland sea, 73% ocean."

The honest posture. This is a designed aesthetic, not a discovered one, and the score is for ranking — surfacing the gems out of a seed line — not for claiming a world is objectively good. The closest thing a world has to a self-labeling "playtest" is the civilization projection (does the atlas k-means produce many distinct, contested, well-separated cultures?); folding that in — and training a tiny critic on the battery so millions of seeds can be screened in microseconds for the genuinely interesting ones — is the next rung. (See the Ludographer at games/gen/ for the same ladder applied where playtesting is free.)

06Architecture

Roadmap

07Sources & further reading

mappa is a stylized model, not a research simulator — each mechanic is a deliberately simplified take on a real body of work. These are the ideas it draws on, if you want to dig past the cartoon.