How the terrain works
The ground is a 16000 x 16000 unit PlaneGeometry (200 x 200 segments) whose vertices are displaced vertically by a fractal Brownian motion function - seven octaves of smooth value noise layered together. Low-frequency octaves define broad valleys and mountain ranges; high-frequency octaves add fine surface detail. A remapping curve flattens values below a threshold into wide plains and water, then exaggerates values above the threshold into steep peaks.
The noise, the remapping curve, and the mountain falloff live in js/terrain-math.js as plain functions with no Three.js dependency, so the world's shape can be unit tested in Node.
Everything drawn over that base ground is an environment element.
On this page
Elements
An element is not a model, a texture, or a placed asset. It is a registry entry in js/environment/elements.js carrying two things: the ranges it can be configured through, and the algorithm that draws it into a height and colour field. Adding a landform to the world means adding an entry, not another bespoke terrain pass, and reconfiguring one means changing a number rather than commissioning new art.
| Element | Configured through |
|---|---|
| Mountain | Peak count, a height range, a radius range, and a girth that stretches a peak along an axis of its own |
| Canyon | A depth range, a width range, a steepness, a branch count, and how far the cut wanders |
| Desert | A dune height range, the spacing between crests, how much of the world the dune sea covers, and a sand gradient |
| Grass | A green gradient, and the height band it covers |
| Sand | A brown gradient, and the height band it covers |
| Water body | A water line, a blue gradient read by depth, and how far the basin is pulled up to a flat surface |
| River | A blue gradient, a windiness, a width range, and a depth range |
| Forest | A tree height range, a density, a grove size range, a grove count, a canopy gradient, and the height band trees will grow in |
| Town | A block size, how many blocks are built on, a building height range, the extent of the site, and building and street gradients |
| Snow | A snow line, a coverage, the steepest ground snow will hold on to, and a white gradient |
| Runway | A length range, a width range, a heading range, the height band a strip may be built in, how far the graded apron reaches, and pavement and paint gradients |
Three rules hold across all of them:
- Every colour is a gradient of one base hue. An element declares a
lightand adarkend of the same colour and blends between them, so nothing shifts hue dramatically across the ground it covers. - Nothing is symmetrical. Rivers and canyons wander on three waves whose lengths share no common multiple, forests are outlined by three lobes at frequencies that share none either, and dune crests are pushed off their axis by noise. There is no repeating pattern to spot from the air.
- The order is the pipeline's, not the preset's. A preset lists the elements it wants and the builder applies them in a fixed order: landforms shaped first, then ground cover laid over them, then water filling what is left below its line, then the cuts and the built things, then snow, and the runway cut last of all over whatever else claimed the ground, because a strip is the one thing in the world that is kept clear. An element never has to know what a preset put beside it.
Mountain density, when a preset does not name a count, is still the formula it has always been:
count = (terrainArea x 0.10) / (pi x avgRadius^2) ~ 14 to 15 mountains
The runway is the one element that chooses where it goes rather than being scattered. Sixty-odd sites are drawn from the world's own seeded stream, each measured at twenty-seven points across the whole footprint of the strip rather than under the middle of it, and the flattest one wins - because what a runway needs is not a particular place but ground that does not move under it. A site outside the height band a strip may be built in is charged for the part of it that lies outside rather than thrown away, so a world with no ground inside the band gets the best ground it has instead of getting no runway at all. The pavement is then levelled dead flat to the site's own height and the apron either side eases back into whatever was there, so a strip sits in the country rather than on a plinth.
It is also cut clear of what it is cut over. Levelling is enough for everything drawn as a height - a grove, a town, a dune all go under the grader - but the water is read back off the finished field afterwards, as the vertices lying under its own line, so a strip graded at or below that line came back out as water and a flight started from the bottom of a lake. Where the water settled on the ground a strip was sited on, the strip is lifted above the line instead, and it carries a record of what it was moved clear of. The runway is the one surface a flight depends on existing, so it is the one piece of ground an element may not be placed onto.
A world is generated without a strip unless one is asked for. In the game that is the RUNWAY box in the settings panel; through the Matter API it is the runway option.
The element editor
Because an environment is a description rather than a mesh, there is nothing to re-author when a range moves: the ground is generated again from the algorithm. L opens the world being flown as the elements it was assembled from, one row each, and choosing an element opens the ranges it declared underneath it. A/D or ←/→ step the range under the cursor, and the ground is drawn again the moment it moves.
| Kind of range | Rows it is drawn as |
|---|---|
| A span, such as a peak height | Two: MIN and MAX. Neither end may be stepped past the other, because a range whose ends have swapped is a range the generator has to guess about |
| A single value, such as a density or a snow line | One |
| A gradient | Two, LIGHT and DARK, each stepped as a percentage of the colour the preset laid it down in |
A colour is stepped along its own hue rather than around the wheel: the keys lighten and darken an end of a gradient and nothing else. The gradient rule above exists precisely so no element shifts colour dramatically across the ground it covers, and an editor that let two presses undo it would be undoing the thing it is editing.
Five things bound what the panel can do:
- A range cannot leave the bounds it declared. The registry says what an element supports, and every reading the panel hands to the generator has already been clamped into it - so no edit can ask for a world an element says it cannot draw.
- One press moves a fiftieth of what the range allows, put on the nearest of 1, 2, or 5 times a power of ten, so a peak height in the hundreds moves by fifties and a ratio between nothing and one moves by hundredths. The step is read off the bounds rather than configured beside them.
- Edits belong to the world they were made on. Choosing another environment, or turning the strip on, is a different set of elements, and the panel is filled again from that preset.
RESTORE THE PRESETputs every range back without changing world. Nothing is stored between sessions. - A game mode brings its own ground, so the editor does not open while one is being played. There is nothing there for it to be editing.
- The runway is ground the editor may not edit around. A range moved until it would reach the strip is held off it by the generator, and the element's own row says so - a setting that reads as applied and is not is worse than one that was refused out loud.
The preset itself is never written to. What the panel holds is a copy, and what it hands out is the same list of placements the Matter API takes, generated by the same builder a preset goes through.
Environments
An assembled environment is a name, a seed, the base ground it is drawn on, and the elements placed over it. It carries no geometry: the world is generated from that description every time it is flown, which is why switching one from the settings panel takes a few tens of milliseconds and no download.
| Environment | Is |
|---|---|
HIGHLANDS | fBm ground under scattered peaks, with snow above 300. The world the simulator has always generated, and the one a fresh install opens on |
RIVER BASIN | A meandering river the width of the world, through low forested country |
CANYON COUNTRY | A branching canyon system cut into a high plateau. The only one of the five with no standing water in it |
DUNE SEA | Wind-blown dunes and rock outcrops, cut by one desert river with palm groves along it |
LAKESIDE | A town on the shore of a wide lake, under forested hills and snow-capped peaks |
The seed is what makes a world reproducible: the same preset lays out the same peaks, the same river, and the same streets every time, so a place worth flying back to is still there.
Three more environments are built for the game modes rather than to be chosen between, and are kept out of the settings panel because a mode brings its own ground with it: OPEN COUNTRY, low rolling ground under a wide sky with one strip cut into it; LOOP VALLEY, a shallow valley with the air over it left clear; and BACK COUNTRY, rough wooded ground with no strip anywhere in it, which is what a search is flown over. All three are deliberately thin - four elements each at most - because what a mode asks the pilot to read is the objective, not the scenery around it. A stage builds its preset with a seed of its own, so four stages of one mode are four worlds rather than the same one four times.
The edge of the world
There is not one. The square an environment describes is one tile of an endless grid of them, and the tiles around the aircraft are drawn out past everything the camera can see, so the ground the fog was promising is actually there. Fly at an edge and another tile is already laid beyond it. There is nothing left to reach.
Each tile is the same description of a world, seeded from its own place in the grid: the same peaks, the same rivers, and the same streets that preset lays down, arranged differently because the place is different. The tile at a given place is that ground every time it is laid, so a country worth flying back to is still there on the way back. The middle tile is the description untouched - a world laid as the middle of a grid and the same world laid on its own are the same ground - which is what keeps every stored seed, every course, and every runway exactly where it was.
The ground is drawn out 12000 units past the aircraft, which is as far as the camera is drawn at, rather than out to where the fog happens to end - the fog is a setting the pilot can turn down and the far plane is not. Tiles are laid a few at a time, one per frame, so crossing into new country costs a frame or two rather than a stall, and the tile the aircraft is actually over is always drawn before it is flown over. Ground far enough behind is released, but not the moment it goes out of reach: a tile is held a little past that, so an aircraft weaving over the line does not generate the same country again every time it crosses back.
What the grid does not yet do is hide its joins. The base ground runs on across a join, because it is noise read off the world rather than off the tile, but what the elements drew stops at the tile they were drawn for - a river reaches the edge and the next tile's river begins somewhere else. Settling those joins the way an assembly settles them is the next step; a seam in the distance is a smaller thing than the end of the world.
The Pilot API still carries a host's own terrain round at the bounds that terrain declares, because a host's world is the size the host says it is. A host whose world continues past what it declared turns the crossing off with wrap: false.
Worlds laid beside each other
A world can also be one square of a larger one. Told which square of a grid it is, an environment is generated in the world's coordinates rather than in its own: its vertices stand where its place in the grid puts them, its sampler answers for that square and nothing outside it, and because the ground is shaped from noise read off the world rather than off the square, the base ground runs on across the join instead of starting again at it.
What does not run on is what the elements drew, since a peak that ended at one square's edge knows nothing about the ground its neighbour laid against it. So the joins are settled: every place two or more squares put a vertex is brought to one height and one colour - the average of what they all had there - and each square is walked back to what it was over the next few vertices in, which closes the seam without flattening the country behind it. A vertex four squares meet at is settled against all four at once, so a corner closes as exactly as an edge does.
Each square is a whole environment - its own elements, its own strips, its own water - laid out from its own place in the grid, so neighbouring squares are the same world without being the same ground. The bundled simulator still flies one square and carries the world round at its edges; the assembly is for a host, through the Matter API.
A day, and water that moves in it
The world is not lit one way any more. A cycle in js/day-night.js carries a phase from midnight through dawn, noon, and dusk and back round, and the sky the world fades to, the fog tinted with it, the colour and strength of the sun, and the fill light under it are all read off that phase as the blend between the two moments either side of it - so a sunrise is a gradual thing rather than a switch thrown at a threshold. The sun walks an arc across the sky and is held a little over the horizon after it sets, so the ground keeps its shape after dark. Midday is exactly the light the world was drawn in before it had a day, and time the flight does not spend flying is time the day does not spend passing.
Water is the one part of the ground that moves and the one part that shines. Every vertex at or under the water line rides a swell of two wave trains crossing at an angle, and catches a sheen on the face of each crest - a colour the land is never painted, so water reads as water rather than as blue ground. The swell is held down to nothing at the bank, so the surface meets the shore it was poured against rather than lapping over it, and the sheen is scaled by how much daylight there is to throw back, so a lake goes flat and dark at night. Both are functions of where a point is in the world and what time it is, which is what lets two squares of an assembly work out the same surface at the place they meet without agreeing on anything.