# World Orogen A browser-based procedural planet generator that creates realistic terrestrial planets with tectonic plate simulation, elevation modeling, and interactive editing. Uses native ES modules with no build step required. [![Live Site](https://img.shields.io/badge/Try_it-orogen.studio-brightgreen)](https://orogen.studio/) ![Three.js](https://img.shields.io/badge/Three.js-0.160.0-blue) ![No Build](https://img.shields.io/badge/build-none-green) ## Philosophy World Orogen is concept art for planets. It's built for the moment early in a project when you need a world that *looks* real — believable tectonics, organic coastlines, climate patterns that feel right — but you don't need a geophysical simulation to get there. The science isn't decoration: plate collision models inspired by real tectonics, pressure-driven wind patterns, and Köppen classification are what make the output feel convincing at a glance. If a climate scientist squints and finds inaccuracies, that's fine — but the scientific foundation is what earns the first glance. Plausibility, not precision. The core value is creative velocity. Generate a planet in seconds, tweak plates and terrain until it matches your vision, then export high-resolution maps into whatever comes next — Gaea, Wonderdraft, Photoshop, a game engine, a novel outline. Orogen is designed to be the fastest path from a blank page to a world worth building on — the first tool in your worldbuilding pipeline, not the last. ## Guiding Principles 1. **Artistic appeal** — Visually interesting, scientifically informed output. Aesthetics come first. 2. **Ease of use and efficiency** — Approachable interface, fast generation. Don't sacrifice usability for realism. 3. **Scientific plausibility** — Grounded in real planetary science. Believable, not necessarily physically accurate. All three are considered together; ties are broken in the order above. ## Features - **Fibonacci sphere meshing** with Voronoi cell tessellation via Delaunay triangulation - **Tectonic plate simulation** — farthest-point seed placement with top-3 jitter, round-robin flood fill with directional growth bias, growth-rate governor, compactness penalty to prevent spindly shapes, multi-pass boundary smoothing, and fragment reconnection - **Ocean/land assignment** — farthest-point continent seeding, round-robin growth with separation guarantees, trapped sea absorption, targeting ~30% land coverage - **Collision detection** — convergent, divergent, and transform boundary classification with density-based subduction modeling; dual-layer super plate system groups same-type plates into ~20 tectonic units for broad orogenic belts blended 50/50 with fine-grained individual plate orogeny - **Elevation generation** — three distance fields (mountain/ocean/coastline) combined via harmonic-mean formula, stress-driven uplift, asymmetric mountain profiles, continental shelf/slope/abyss profiles, foreland basins, plateau formation, and rift valleys with graben profiles - **Ocean floor features** — mid-ocean ridges at divergent boundaries, deep trenches at subduction zones, fracture zones at transform boundaries, back-arc basins behind subduction zones - **Island arcs** — volcanic island chains at ocean-ocean convergent boundaries with ridged noise shaping - **Hotspot volcanism** — dual-component mantle plume model (broad thermal swell + volcanic peak) with drift-trail island chains, domain-warped shape distortion, drift-direction elongation, summit calderas on active domes, radial rift-zone ridges, age-dependent volcanic texture, and per-hotspot variation in strength/decay/spacing - **Terrain post-processing** — noise-based domain warping (FBM simplex noise with greedy mesh walk) to deform the elevation field for organic coastlines and mountain ridges, independently controllable bilateral smoothing to blend harsh BFS distance-field boundaries, glacial erosion that carves fjords, U-shaped valleys, and lake basins at high latitudes and altitudes via latitude-driven ice flow with drainage accumulation, priority-flood pit resolution with canyon carving (Barnes et al. algorithm that ensures every land cell drains to the ocean, carving dramatic canyons through mountain saddle points rather than filling basins), iterative implicit stream power hydraulic erosion (Braun-Willett style) that carves self-reinforcing river valleys with automatic sediment deposition in flat receivers, thermal erosion that softens ridges via talus-angle material transport, ridge sharpening that accentuates mountain ridgelines, and always-on soil creep (Laplacian diffusion) that rounds off hillslopes - **Coastal roughening** — fractal noise with active/passive margin differentiation, domain warping for bays/headlands, and offshore island scattering - **3D globe rendering** with atmosphere rim shader, translucent water sphere, terrain displacement, and starfield - **Equirectangular map projection** with antimeridian wrapping - **Interactive editing** — Ctrl-click plates to mark them for reshaping (multi-select with visual tinting), then click Rebuild to apply all changes at once. Ctrl-click again to undo a pending selection. Press Escape to cancel all pending edits - **Seasonal wind simulation** — pressure-driven wind patterns with a longitude-varying ITCZ that tracks the thermal equator (~5° over ocean, up to 15-20° over continents), Gaussian pressure bands (subtropical highs, subpolar lows, polar highs), land/sea thermal contrast for monsoon-like pressure reversals, elevation barometric effects, and Coriolis-deflected geostrophic wind with natural cross-equatorial flow reversal. Computed for both summer and winter seasons. - **Ocean surface currents** — rule-based geographic gyre simulation driven by wind belts (trade winds, westerlies, polar easterlies) with a longitude-varying ITCZ equatorial countercurrent. Continental shelves are classified as western or eastern boundaries via coast-normal BFS, producing subtropical gyres (CW in NH, CCW in SH) with western boundary intensification (Gulf Stream, Kuroshio effect) and weaker eastern boundary return flow. Detects circumpolar channels for unobstructed eastward currents (Antarctic Circumpolar Current). Currents are colored by heat transport: red = warm poleward flow, blue = cold equatorward flow, black = zonal (neutral). Computed for both summer and winter seasons. - **Precipitation** — blended dual-model approach: a complex moisture advection simulation is combined 50-50 with a fast heuristic zonal model. The advection model simulates wind-driven moisture transport from coasts with six mechanisms: ITCZ convective uplift, frontal convergence, orographic rain/shadow, lee cyclogenesis, polar-front precipitation, and subtropical high suppression. The heuristic model provides smooth latitude-based patterns (ITCZ wet belt, subtropical dry belt, mid-latitude recovery, polar dryness) modulated by continentality and orographic effects. Blending the two reduces splotchiness while preserving terrain-informed detail and strengthening subtropical desert formation (~20–35°). Visualized on a brown (dry) → green (moderate) → blue (wet) color ramp. Computed for both summer and winter seasons. - **Map type switcher** — first-class Terrain / Satellite / Climate / Heightmap tabs with color legends for each view - **On-demand climate** — optional deferred climate computation; skip climate during generation for faster terrain iteration, compute it on demand when needed - **Detailed visualization** — twenty-six selectable inspection layers organized by category (Geology, Atmosphere, Ocean, Climate, Elevation) for viewing each component in isolation. Wind/pressure layers show directional wind arrows, ocean current layers show current arrows colored by heat transport, on both globe and map views. Precipitation layers use a brown→green→blue ramp showing dry to wet regions. - **Heightmap import** — bring your own equirectangular B&W heightmap (Earth, Mars, hand-drawn maps) onto a 3D globe. Black pixels become ocean, brighter pixels become higher land. The import page (`/import`) runs full climate simulation (wind, precipitation, temperature, Köppen) on your imported terrain, with optional terrain sculpting (smoothing, erosion, ridge sharpening). Supported formats: PNG, JPEG, WebP. - **Painted map import** — paint a flat map where every colour is a *class* (a rate of rock uplift and an erodibility, never a height) and a legend JSON says what the colours mean; the import page's **Painted Map** source solves the stream-power equation dh/dt = U − K·A^m·S on the sphere mesh (Braun-Willett implicit scheme, priority-flood drainage, hillslope diffusion) until the land is in balance with its uplift, so rivers, divides and valley hierarchy come out of the physics. Classes carry massif blocks (a plain with hill masses standing out of it, cut at a quantile of the whole planet), coastal-plain ramps, a planet-wide rock field that multiplies erodibility, and a regional swell; the drawn coastline is roughened with fractal noise before the solve. Six extra inspect layers and export types: class map, uplift rate, erodibility, drainage (rivers), slope and drainage basins. The legend format is shared with the Salty terrain generator's `terrain plan` / `terrain bake`. - **Map export** — download high-resolution equirectangular PNGs (color terrain, satellite biome, climate/Köppen, B&W heightmap, land-only heightmap, or B&W land mask) at configurable widths up to 65536px with tiled rendering. **Export All** downloads Satellite, Climate, Heightmap, and Land Mask in one click, auto-computing climate if needed. - **Unreal landscape export** — render a window of the planet straight into the tile set Unreal Engine's landscape importer wants: a 16-bit greyscale height per tile at 255·N+1 vertices (one Landscape actor each), an 8-bit weightmap per paint layer beside it, and a `Region.json` describing the grid. Unlike the map exports, this one carries a **scale**: you give the planet's circumference and the export records metres-per-pixel, the window in degrees, and the projection, so nothing downstream has to guess. Files are written into a folder you pick (Chrome/Edge, File System Access API). See [Unreal landscape export](#unreal-landscape-export) below. ## Quick Start Serve the project with any local HTTP server (required for ES modules): ```bash # Python python3 -m http.server 8000 # Or Node.js npx serve . ``` Then open **http://localhost:8000** in your browser. No dependencies to install, no build step. Click **Build New World** to create a new random planet. The button changes color and label based on what you've adjusted: - **Build New World** (blue) — generates a fresh planet with a new random seed - **Rebuild** (amber) — re-renders the current planet at a new detail/roughness level without changing continent shapes - **Regenerate** (red) — creates new tectonic plates when the Plates or Continents slider has changed ### Navigation A top navigation bar connects the two pages: - **Generate** (`/`) — procedural planet generation with tectonic plates, erosion, and climate - **Import** (`/import`) — two sources, switched at the top of the panel: - **Heightmap** — import your own equirectangular B&W heightmap, view it on a 3D globe, and run climate simulation. Black (0) = ocean, brighter = higher elevation. Supports PNG, JPEG, and WebP. - **Painted Map** — import a painting whose colours are legend classes plus the legend JSON (a built-in legend and a demo painting are included), edit the classes' uplift rates, depths and erodibilities in the table, and click **Solve Terrain**. The report says how many pixels matched no class and whether the left and right edges agree (they are the same meridian). Optionally add **Planet.json** (the Salty generator's manifest), an **Overlay** annotation layer, or load all of them from a running `terrain studio`. ### Painted Map controls | Control | Range | Default | Description | |---------|-------|---------|-------------| | Peak Height | 0.5 – 6 km | 4.5 km | The 99.5th percentile of the solved land is put at this height. The shape is the solve's; this is only the scale (for n = 1 the steady state is linear in uplift over erodibility) | | Ocean Depth | 0.25 – 5 km | 4 km | Depth of the deepest sea class; shallower classes (shelf, surf) scale with it, and every shore ramps down over a couple of cells | | Coast Detail | 0 – 1 | 0.35 | Fractal noise added to the signed distance from the painted waterline before the solve, up to three cells of shift. Islets keep at least a third of their width | | Uplift Variation | 0 – 0.6 | 0.30 | A regional swell over the painted rate, so a lowland painted in one colour has basins and rises of its own | | Solve Steps | 50 – 600 | 200 | How long the stream-power solve runs. About 12 s at 204K regions | | Painted world circumference | km | 100 | Distances in the legend (coastal plains, massif and rock sizes) are in the painted world's kilometres and are scaled to the Earth-sized globe by the ratio of circumferences | | Massif size | km | 7 | Block size of the planet's upland fabric — how big the hill masses standing out of a plain are | | Rock province size | km | 8 | Province size of the planet's rock field, which multiplies each class's erodibility | | Seed | integer | 7945 | Re-rolls what the painting does not fix: the massifs, the rock provinces, the swell and the coastline detail. **Re-roll** picks a new one | ### The class table's two angles Each land class shows the **typical** hillslope its uplift rate makes on the Salty generator's 8 m geology grid, and what that ground reads as — plain, rolling, hill country, mountain, alpine. Hovering a value gives the **divide** angle, the steepest ground the rate can make, and the P90. Read the typical column. Steady state is `S = U/(K·A^m)` and `A` is smallest at the top of a catchment, so the divide angle is the steepest place in a world and almost none of a map is divide; the median comes out at about a third of it in tangent. Reading the divide angle as the landscape is how a legend gets set two or three times too hot. A class whose divide is past the angle of repose is marked **clamped** — there the repose clamp shapes the ground rather than the rivers, and raising the rate makes the summits higher without making the ground steeper. The note under the table gives the rate at which that begins. The angles come from the bake's constants, which **Planet.json** carries: cell size, `K`, `m` and the angle of repose. Without it the defaults are the shipped planet's (8 m, 5e-5, 0.5, 35°). ### Planet.json The Salty generator's own manifest (`RawContent/World/Planet.json`). Loading it brings the planet block — circumference, massif and rock province sizes, uplift variation, seed — and the pipeline constants the angles above are about, so none of it has to be retyped. It outranks a legend's own `planet` block, because it is the file the two-hour bake actually reads. ### Overlay A second painting the same size as the template and registered to it, whose colours are **marks** rather than classes: forests, settlements, roads, and stretches of coast to leave alone. It answers a different question from the class template — every colour there is geology, and there is no uplift rate for a town — so it is a separate sheet with a legend of its own. Blank is decided by **alpha**, never by a colour: an unpainted pixel is transparent, so no colour is spent on emptiness and an export with a white matte behind it does not turn the world into whatever mark white is nearest. An opaque pixel further than `match_distance` from every mark is dropped and counted, which is the only way a colour the legend forgot ever shows. Exactly one mark property changes anything: **`coast_jitter`** scales how far the coast roughening may move the shore inside the mark. `0` pins a hand-drawn coastline exactly as painted while the rest of the world is still roughened; above 1 chews it harder, which is what makes a fjord coast. Everything else is inert — two solves with and without a forest are the same terrain. The sheet is drawn as a **texture**, not voted onto the mesh, because a road is a few pixels wide and a region here covers tens of kilometres. The **Overlay Sheet** toggle drapes it over whatever layer is shown, on the globe and on the map; the **Overlay** inspect layer and export type draw it over a dimmed class map, and hovering a marked region names the mark. The overlay legend JSON has a `marks` array; each mark has a `name`, an `rgb` triple, optionally `kind: "path"` with `width_m`, `coast_jitter`, `min_area_px` and a `note`. The file-level `match_distance` and `min_area_px` are the defaults. ### From terrain studio `terrain studio` (the Salty generator's painting tool) serves the painting it is holding, both legends and Planet.json read-only across origins. Enter its address and **Load from studio** brings the whole planet in one step, exactly as its next `terrain plan` would read it — including strokes made since the last save, because the studio holds the painting in memory. It needs a studio built on or after 2026-09-20. The studio only ever shares reads: nothing on this page can paint, save, plan or bake. The legend JSON has a `classes` array; each class has a `name`, an `rgb` triple and either `"sea": true` with `depth_m` or `uplift_mm_yr` and `k_mult`, optionally `massif: { floor_mm_yr, fraction }`, `coastal_plain_km` / `coastal_floor_mm_yr`, `lithology_mix`, `stroke: true` (an outline colour that dissolves into its neighbours, or becomes `edge_class` where it touches a pole) and `derived: true` (a class that is never painted). An optional `planet` block carries `circumference_km`, `massif_wavelength_km`, `lithology_wavelength_km`, `uplift_variation` and `lithology.k_multipliers`. See `assets/painted-legend.json`. **Download legend JSON** writes the table's edits back into the loaded file with every other key intact. ### Sharing Planets Every generated planet produces a **planet code** (shown below the Build button) that encodes the random seed, all slider values, and any plate edits. An unedited planet is 21 characters; plate edits (applied via Rebuild) extend the code to include the toggled plates. Older codes (13–18 characters) from previous versions are still supported — missing sliders default to their current default values. To share a planet: - **Copy** the code with the copy button and send it to someone - **Load** a code by pasting it into the planet code field and clicking Load (or pressing Enter). The Load button turns blue when a new code is ready to apply. - **URL sharing** — the code is also stored in the URL hash (e.g. `#a7f3kq9xp2b`), so you can share the full URL directly. Opening a URL with a valid hash auto-loads that planet, including any plate edits. ## Controls ### Shape Your World Core world parameters that control the planet's structure (changing these requires a full rebuild): | Control | Range | Default | Description | |---------|-------|---------|-------------| | Detail | 5,000 – 2,560,000 | 204,000 | Number of Voronoi cells on the sphere. Only affects rendering resolution — continent shapes are stable across detail levels (generated on a fixed ~20K reference grid) | | Irregularity | 0 – 1 | 0.75 | Randomization of Fibonacci point positions | | Plates | 4 – 120 | 80 | Number of tectonic plates | | Continents | 1 – 10 | 4 | Target number of separate landmasses | | Roughness | 0 – 0.5 | 0.40 | Fractal noise magnitude for terrain roughness | | Continent Size Variety | 0 – 1 | 0.35 | How much continent sizes vary — 0 keeps continents similar in size, 1 allows a mix of large and small landmasses | | Land Coverage | 0 – 1 | 0.3 | Percentage of the planet covered by land. Low values create ocean worlds, high values create desert worlds. Above 40% coverage, precipitation is progressively dampened to simulate reduced oceanic moisture | ### Terrain Sculpting Post-processing passes that refine the terrain (collapsed by default — the defaults produce good results). These do not require a full rebuild; adjusting any slider lights up the **Reapply** button at the bottom of this section — click it to reapply only the sculpting passes on the current planet. | Control | Range | Default | Description | |---------|-------|---------|-------------| | Terrain Warp | 0 – 1 | 0.75 | Domain warping — deforms the elevation field using noise to produce organic, squiggly coastlines and mountain ridges | | Smoothing | 0 – 1 | 0.10 | Blends harsh terrain boundaries from tectonic generation | | Glacial Erosion | 0 – 1 | 0.50 | Ice-age sculpting — carves fjords, U-shaped valleys, and lake basins at high latitudes and altitudes via latitude-driven ice flow | | Hydraulic Erosion | 0 – 1 | 0.50 | Iterative stream-power erosion — resolves endorheic basins via priority-flood canyon carving, then carves river valleys and dendritic drainage networks, with automatic sediment deposition in flat receivers | | Thermal Erosion | 0 – 1 | 0.10 | Slope-driven material transport — softens ridges and creates natural talus slopes | | Ridge Sharpening | 0 – 1 | 0.50 | Accentuates mountain ridgelines — pushes peaks further above their surroundings for more dramatic terrain | ### Climate Global climate offsets that adjust temperature and precipitation without a full rebuild. Changing these triggers a fast climate-only recompute. | Control | Range | Default | Description | |---------|-------|---------|-------------| | Temperature | -15 – 15 | 0 | Global temperature offset in °C — positive makes the planet warmer, negative colder. Climate zones shift accordingly | | Precipitation | -1 – 1 | 0 | Global precipitation scale — positive makes the planet wetter, negative drier. Affects desert and rainforest distribution | ### Auto Climate Climate simulation (wind, ocean currents, precipitation, temperature, Köppen classification) runs automatically during generation when detail is ≤ 300K regions. Above 300K, climate is skipped for faster terrain iteration and computed on demand when switching to a climate-dependent view. ### Visual Options - **Map Type** — segmented Terrain / Satellite / Climate / Heightmap tabs for quick switching between the four most common visualizations. Each tab shows a color legend: - **Terrain** — elevation color ramp from deep ocean through sea level to mountain peaks - **Satellite** — realistic biome colors based on Köppen climate classification and elevation (lush green rainforests, tan deserts, white ice caps, dark taiga, gray tundra), with ocean using the standard terrain palette. High elevations blend toward snow white based on climate-aware snow lines. - **Climate** — Köppen-Geiger classification with color swatches for all 30 climate types - **Heightmap** — black-to-white gradient on a fixed absolute scale (-5 km ocean floor to 6 km peaks), so the same physical height always maps to the same shade - **View** dropdown — switch between Globe and Map (equirectangular projection) - **Center Longitude** slider (map mode only) — shifts the map projection's central meridian to any longitude from 180°W to 180°E, scrolling the equirectangular projection so the chosen longitude is centered. Exports are unaffected (always centered on 0°). - **Wireframe** — toggle switch to show Voronoi cell edges as a wireframe overlay - **Show Plates** — toggle switch to color regions by plate (green shades = land, blue shades = ocean); also draws black super plate boundary lines showing tectonic super-groups - **Auto-Rotate** — toggle switch to spin the globe continuously - **Grid Lines** — toggle switch for latitude/longitude grid overlay on both globe and map views - **Grid Spacing** — choose the interval between grid lines: 30°, 15°, 10°, 5°, or 2.5° ### Inspect Dropdown The **Inspect** dropdown (in Visual Options, below the map tabs) selects a detailed visualization layer. On the import page a **Painted Map** group — Class Map, Uplift Rate, Erodibility, Drainage (Rivers), Slope, Drainage Basins — is enabled once a painted map is solved; the same six are export types, and **Export All** includes them. Options are organized into groups: - **Main views** (ungrouped at top) — Terrain, Satellite, Köppen Climate, Land Heightmap - **Geology** — Base, Tectonic, Noise, Interior, Coastal, Ocean Floor, Hotspot, Tectonic Activity, Margins, Back-Arc, Fold Ridge, Orogenic Power, Erosion Delta (blue = eroded, red = deposited) - **Atmosphere** — Pressure Summer/Winter (blue = low, red = high), Wind Speed Summer/Winter (with directional arrows on both globe and map) - **Ocean** — Currents Summer/Winter (red = warm poleward, blue = cold equatorward, black = zonal; with directional current arrows) - **Climate** — Precipitation Summer/Winter (brown = dry, green = moderate, blue = wet), Rain Shadow Summer/Winter (diverging blue = windward orographic boost, gray = neutral, red-brown = leeward rain shadow; leeward effects are seeded at downslope faces scaled by mountain height, then propagated ~1500 km downwind to show extended shadow zones like the foehn drying effect), Temperature Summer/Winter (purple-blue = cold, white = 0 C, green-yellow = warm, red = hot; fixed -45 to +45 C range), Continentality (blue = ocean, green = coast, yellow = moderate interior, orange/red = deep continental interior) - **Elevation** — Full Heightmap (full-range B&W) ### Export Click **Export Map** (below Visual Options) to open the export modal: - **Type** — Color Map (terrain colors), Satellite (biome colors from Köppen classification), Climate (Köppen classification colors), Heightmap (B&W full range on fixed -5 to 6 km absolute scale), Land Heightmap (B&W on fixed 0 to 6 km absolute scale, ocean is black), or Land Mask (pure B&W — white = land, black = ocean). Satellite and Climate options are disabled when climate hasn't been computed. - **Width** slider — 1024 to 65536 pixels (height is always width/2 for equirectangular). Large exports use tiled rendering to handle GPU texture limits. - **Export** — downloads the selected type as an equirectangular PNG with no grid overlay - **Export All** — downloads four maps (Satellite, Climate, Land Heightmap, Land Mask) sequentially. If climate hasn't been computed yet, it runs automatically before exporting. - A progress overlay shows rendering and PNG encoding status during export - **Unreal Landscape…** — opens the landscape tile exporter described below ### Unreal landscape export The map exports answer "draw the whole planet at width W". Unreal asks a different question, and the **Unreal Landscape…** button in the export modal answers it: *what is the ground, in metres, over this rectangle of the planet, at the sample spacing the game uses?* It writes one `_x_y_Height.png` (16-bit greyscale, `tiles.vertices` square) and three 8-bit weightmaps per tile, plus `Region.json`, into a folder you choose. Every field re-plans as you type, and the readout under them says what that setting bought. | Field | What it decides | | --- | --- | | Level | The tiles are named after its last segment | | Planet circumference | **The scale.** A sphere carries no metres; this is what turns the window's degrees into ground, and it decides how much land a window can hold | | Centre longitude / latitude | Where the window sits. Keep it near the equator | | Tiles across / down, Vertices a tile | The grid. `255·N+1` vertices gives each tile N×N components of 255 quads — the component count is what costs, not the vertex count | | Quad size | Metres between vertices, in centimetres. 200 is a 2 m quad | | Elevation floor / ceiling | What 0 and 65535 mean. Too narrow clips (reported); too wide only costs height precision (also reported) | | Sea scale | Multiplies everything below sea level, so a whole-planet abyss does not force an elevation range that costs the land its precision. Land is untouched | | Sample spacing | How finely the planet is rendered before the tiles are cut from it. The mesh resolves a couple of hundred metres, so anything under ~25 m is already lossless | Three things about it are worth knowing. **The window is sampled once, then cut.** The planet is rendered into a single float raster over the window and every tile is resampled out of that raster *by its global vertex position*, so a column two neighbours share is computed from the same source coordinates twice and comes out bit-identical. Nothing blends or stitches. Tiles carry a one-vertex margin while the paint layers are derived, because the layers read slope and a one-sided difference at a tile's edge is not what the neighbour computes there. **A small planet cannot hold a large flat window.** The projection is equirectangular, cosine-corrected at the centre latitude, which splits the east-west error between the two edges instead of leaving it all on one. The readout prints that cost, and the panel says so plainly when the window is too big for the sphere: 936 km² on a 100 km-circumference planet is 29% of the entire globe, and reads as a window 110° on a side stretched 74.7% at its edge. That is arithmetic, not a bug — raise the circumference or use fewer rows. **It does not invent detail.** The sphere mesh resolves a couple of hundred metres, so below that the ground is smooth no matter how finely it is sampled. What this export fixes is that the ground arrives in the shape Unreal wants with its scale attached; it does not make the ground finer. An existing `Region.json` is **never replaced** — a hand-written one is mostly commentary explaining why each number is what it is, and a generated file would throw that away. When one is already in the folder the new manifest is written as `Region.generated.json` instead and the status line says so; rename it over the old one when you have read the difference. The tiles themselves are always overwritten. Requires the File System Access API (Chrome or Edge on desktop); the panel says so if the browser lacks it. ### Sidebar & Loading The control panel can be collapsed and expanded with the **«** toggle button in the sidebar header. On small screens (≤ 768px) the sidebar becomes a bottom sheet with a drag handle — starts collapsed, showing only the handle and header. Drag up or tap the handle to expand. A fullscreen overlay with spinner, title, and progress bar appears during every generation — fully opaque on initial load, semi-transparent on subsequent builds so the previous planet is dimmed behind it. Stage labels (shaping, plates, oceans, mountains, painting) update as the pipeline progresses. ### Tutorial & Help A five-step tutorial modal introduces the tool on first visit (auto-shown via `localStorage`). It covers planet generation, slider controls, interactive editing, visualization, saving/sharing via planet codes, and map export. A **?** help button in the top-right corner reopens the tutorial at any time. The modal can be dismissed with the close button, backdrop click, Escape key, or the "Get Started" button on the final step. A **What's New** modal is shown once per release to returning users (those who have already dismissed the tutorial). It highlights new features, changes, and a heads-up that saved planet codes may produce different-looking worlds due to terrain/climate reworks. The modal uses a versioned `localStorage` flag (`wo-whatsnew-seen`) — bump the `VERSION` constant in `initWhatsNew()` to trigger it again on the next release. ### Interaction Navigation hints are shown in the sidebar panel and as a contextual tooltip when hovering the planet. | Action | Desktop | Mobile | |--------|---------|--------| | Rotate globe / pan map | Drag | Drag (one finger) | | Zoom | Scroll wheel | Pinch with two fingers | | Highlight plate + info card | Hover | — | | Mark plate for reshaping | Ctrl-click a plate (multi-select) | Tap the edit button (pencil), then tap plates | | Undo pending plate | Ctrl-click the same plate again | Tap the same plate again | | Apply pending edits | Click the Rebuild button | Tap the Rebuild button | | Cancel all pending edits | Press Escape | — | Hovering over a region shows an info card with plate type, elevation, coordinates, and (when climate has been computed) temperature, precipitation, and Köppen classification. Pending plates show a colored tint (green = ocean→land, blue = land→ocean) and hover text indicates "(pending)". ### Mobile Support World Orogen is fully usable on phones and tablets: - **Bottom-sheet sidebar** — on screens 768px or narrower, the sidebar becomes a bottom sheet with a drag handle. Drag or tap the handle to expand/collapse. The globe stays visible above. - **Pinch-to-zoom** — two-finger pinch zooms the globe and map, using the same smooth lerp as desktop scroll-zoom. - **View switcher** — a dropdown in the top-right lets you switch between Terrain, Satellite, Climate, and Heightmap views without opening the bottom sheet. - **Edit-mode toggle** — a floating pencil button (bottom-right) activates plate editing. Tap it to toggle edit mode (glows green when active), then tap plates to mark them. Tap the Rebuild button to apply all changes at once. - **Touch-friendly targets** — buttons, checkboxes, and sliders are enlarged for comfortable finger input. - **Performance** — detail warning thresholds are lowered on touch devices (orange at 200K, red at 500K). Export widths above 8192px are disabled on mobile. - **Tooltips** reposition above their trigger instead of to the right, so they stay on screen. - **Orientation** changes are handled automatically. ## How It Works ### Pipeline 1. **Fibonacci spiral** distributes N points evenly on a unit sphere with optional jitter 2. **Stereographic projection** maps the sphere points to 2D 3. **Delaunator** computes Delaunay triangulation in projected space 4. **Pole closure** connects convex hull edges to a pole point, creating a watertight mesh 5. **Coarse plate generation** on a fixed ~20,000-region reference mesh (resolution-independent), via farthest-point seed placement (with top-3 jitter for variety), round-robin flood fill with per-plate growth rates, directional bias coupled inversely to growth rate, growth-rate governor, and compactness penalty 6. **Ocean/land assignment** on the coarse mesh using farthest-point continent seeding with area budgeting 7. **Plate projection** maps coarse plate assignments onto the high-res mesh via nearest-neighbor adjacency walk, then smooths boundaries with resolution-scaled majority-vote passes 8. **Collision detection** simulates plate drift to classify convergent/divergent/transform boundaries 9. **Stress propagation** diffuses collision stress inward through continental plates via frontier BFS 10. **Elevation assignment** combines distance fields, stress-driven uplift, ocean floor profiles, rift valleys, back-arc basins, hotspot volcanism, island arcs, coastal roughening, and multi-layered noise 11. **Terrain post-processing** applies domain warping (controlled by Terrain Warp slider) using FBM simplex noise to deform the elevation field for organic coastlines and mountain ridges via greedy mesh walk, then bilateral smoothing (controlled by Smoothing slider) to blend BFS banding artefacts, glacial erosion (controlled by Glacial Erosion slider) carves fjords, U-shaped valleys, and lake basins at high latitudes and altitudes, priority-flood pit resolution carves canyons through mountain saddle points to ensure all land drains to the ocean, iterative implicit stream power hydraulic erosion with sediment deposition (controlled by Hydraulic Erosion slider) carves self-reinforcing river valleys, thermal erosion (controlled by Thermal Erosion slider) softens ridges via talus-angle material transport, ridge sharpening (controlled by Ridge Sharpening slider) accentuates mountain ridgelines, and always-on soil creep gently rounds off hillslopes 12. **Wind simulation** computes a longitude-varying ITCZ by scanning for the thermal maximum at each longitude (accounting for land/sea heating differential and elevation lapse rate), builds pressure fields from Gaussian zonal bands centered on the ITCZ plus land/sea thermal modifiers and elevation barometric effects, then derives wind vectors from pressure gradients with latitude-dependent Coriolis deflection and surface friction. Computed for both NH summer and winter. 13. **Ocean currents** uses a rule-based geographic approach: classifies ocean cells by wind belt (trades, westerlies, polar easterlies) to set base zonal flow, runs three BFS passes from coastal seeds to compute distance to western and eastern coastlines (classified by coast-normal direction), deflects currents poleward near western boundaries (warm, intensified ×2) and equatorward near eastern boundaries (cold, weaker ×0.8), detects circumpolar channels at ±60° latitude for unobstructed eastward flow, smooths with 5 Laplacian passes, and classifies heat transport by meridional flow direction. Computed for both seasons. 14. **Precipitation** uses a blended dual-model approach. The complex model computes moisture advection from coasts using iterative upwind propagation driven by wind vectors, with depletion based on distance and elevation gain, plus six mechanisms: ITCZ convective uplift, frontal convergence at subpolar lows, orographic rain/rain shadow, lee cyclogenesis, polar front diffuse precipitation, and seasonal subtropical high suppression (shifts poleward in local summer to create Mediterranean dry-summer patterns). A heuristic zonal model computes smooth precipitation from ITCZ distance (with aggressive subtropical drying at 15–30°), seasonal hemisphere boost with Mediterranean subtropical suppression (up to 55% summer reduction at 25-42° latitude), continental dryness, and orographic rain shadow. The two models are blended 50-50 then normalized via 95th-percentile scaling. Computed for both seasons. 15. **Temperature** computes per-cell surface temperature using the ITCZ as the thermal equator (28°C peak, warmest latitude band), with poleward cooling following a power-law curve (exponent 1.2, 13° tropical plateau, 52°C range). Modulated by seasonal hemisphere offset with latitude-dependent seasonal amplitude boost (up to ±12°C peaking at 55-75° latitude), continentality-scaled maritime factor (coast 0.50× to deep interior 1.20× seasonal swing), moisture-dependent elevation lapse rate (4.5 C/km in wet regions to 9.3 C/km in dry regions, interpolated by precipitation), ocean current warmth (16-pass diffusion onto coastal land, ±20°C effect with 0.95 continentality gate), and precipitation/cloud cover moderation. Normalized to a fixed -45 to +45 C range. Computed for both seasons. 16. **Rendering** builds a Voronoi cell mesh with per-vertex colors and terrain displacement ### Key Algorithms - **Seeded PRNG** — Park-Miller LCG for deterministic generation - **3D Simplex noise** — with fBm and ridged fBm variants for terrain detail - **Harmonic-mean distance blending** — `(1/a - 1/b) / (1/a + 1/b + 1/c)` for smooth elevation transitions - **Domain warping** — noise-driven coordinate offsets for organic coastlines - **Density-based subduction** — tanh mapping of density differences with undulation noise - **BFS distance fields** — randomized frontier expansion from boundary seeds, used for elevation, coast distance, rift width, ridge profiles, and back-arc basins - **Gaussian dome uplift** — hotspot volcanism modeled as dual-component Gaussians (thermal swell + volcanic peak) with domain-warped shape distortion, anisotropic drift elongation, summit calderas, radial rift ridges, and age-dependent texture blending ## Project Structure ``` index.html Main page — HTML markup + import map + structured data import.html Import page — heightmap upload + climate visualization styles.css All CSS (shared by both pages) robots.txt Search engine crawler directives sitemap.xml Sitemap for search engine indexing site.webmanifest Web app manifest (metadata + theming) llms.txt AI/LLM-readable site description (AISEO) humans.txt Project credits CNAME Custom domain config (orogen.studio) 404.html Custom 404 page preview.png Social preview image (og:image / Twitter card) js/ main.js Generator entry point — UI wiring, animation loop import-main.js Import page entry point — file upload, import dispatch, painted-map legend table painted.js Painted-map import — legend parsing, pixel classification, region voting, stroke dissolution, coast roughening, uplift field, Braun-Willett stream-power solve painted-layers.js Colours and legends for the painted layers (class, uplift, erodibility, drainage, slope, basins, overlay) painted-report.js What a legend's numbers make before a solve: the divide and typical hillslope angles per class painted-overlay.js The annotation layer — mark legend parsing, pixel classification, region voting, coast_jitter per region painted-overlay-view.js The overlay sheet as a texture on the globe, the map and the exports state.js Shared mutable application state generate.js Worker dispatcher — posts jobs, handles results planet-worker.js Web Worker — runs geology pipeline off main thread planet-code.js Planet code encode/decode (seed + sliders → base36) rng.js Seeded PRNG (Park-Miller LCG) simplex-noise.js 3D Simplex noise with fBm and ridged fBm color-map.js Elevation → RGB colour mapping + satellite biome colors sphere-mesh.js Fibonacci sphere, Delaunay, SphereMesh dual-mesh plates.js Tectonic plate generation (farthest-point seeding, round-robin flood fill, compactness constraints) coarse-plates.js Resolution-independent plate pipeline — coarse reference grid, projection, boundary smoothing super-plates.js Groups same-type plates into ~20 super plates for broad orogenic belts ocean-land.js Ocean/land assignment with continent seeding elevation.js Collisions, stress propagation, distance fields, elevation terrain-post.js Domain warping, bilateral smoothing, glacial/hydraulic/thermal erosion, ridge sharpening, soil creep climate-util.js Shared climate utilities — smoothing, ITCZ lookup, percentile selection wind.js Seasonal wind simulation — pressure fields, ITCZ tracking, Coriolis wind ocean.js Ocean surface currents — rule-based wind-belt gyres, coast BFS, circumpolar detection precipitation.js Precipitation simulation — moisture advection, ITCZ/frontal/orographic effects, blended with heuristic heuristic-precip.js Heuristic zonal precipitation model — smooth latitude/continentality/orographic patterns temperature.js Temperature simulation — ITCZ thermal equator, lapse rate, continentality, ocean currents scene.js Three.js scene, cameras, controls, lights planet-mesh.js Voronoi mesh, map projection, hover highlight edit-mode.js Ctrl-click plate multi-select + hover info detail-scale.js Non-linear (power-curve) detail slider mapping png-write.js 8-bit and 16-bit greyscale PNG encoders (a canvas gives neither) unreal-render.js Renders a lon/lat window of the planet into a float raster of kilometres unreal-export.js Cuts that raster into Unreal landscape tiles, derives the weightmaps, writes Region.json unreal-ui.js The Unreal Landscape panel, built in JS so both pages share one copy ``` ## Dependencies Loaded via CDN import maps (no installation needed): - [Three.js](https://threejs.org/) v0.160.0 — 3D rendering - [Delaunator](https://github.com/mapbox/delaunator) v5.0.1 — 2D Delaunay triangulation ## License This project is licensed under the GNU General Public License v3.0 — see [LICENSE](LICENSE) for details. ## Acknowledgments Inspired by [Red Blob Games' planet generation](https://www.redblobgames.com/x/1843-planet-generation/) — Fibonacci sphere meshing, dual-mesh traversal, and distance-field elevation approach. Additional inspiration and reference from: - [Worldbuilding Pasta](https://worldbuildingpasta.blogspot.com/) — worldbuilding science and climate reference - [Artifexian](https://www.youtube.com/@Artifexian) — worldbuilding tutorials and planetary science inspiration - [Madeline James](https://www.youtube.com/@MadelineJamesWorldbuilds) ([website](https://www.madelinejameswrites.com/)) — worldbuilding methodology and climate design reference - [Fractal Philosophy](https://www.youtube.com/watch?v=7xL0udlhnqI) — procedural terrain generation inspiration