Module reference
Every module in Natura 1.0.0, generated from the code: the first line of each file's header comment, how to load it, the system its factory builds with the default configuration, and the fields that system exposes right after init (a system may add more once it steps). 75 files; 60 of 60 test and probe files pass under node v26.4.0 (1226 assertions counted).
How to read an entry. Load gives the browser global a <script> tag defines and the node require; Needs lists what must be loaded first in a browser (node's require loads it for you). System is what a make... factory returns: pass it to Natura.World({ systems: [...] }); other systems read its fields as ctx.fields.<name>.<field>. Most factories take one config object; the defaults and every option are at the top of the factory in the source (the link goes to that line).
Index
The core. The clock, the system interface, the registry and the World runner that couples systems.
| module | what it is |
|---|---|
| natura.js | The CORE of the Natura pocket-universe framework. The beating heart everything plugs into: a universal CLOCK (one time, every cadence day->eon), a common SYSTEM interface (generalizing the Terrain Engine's PROCESS -- init/step/fields/events, deterministic + ... |
Sky and star. The clock made physical, and the deep-time energy source.
| module | what it is |
|---|---|
| celestial.js | Natura CELESTIAL: the abstract clock made PHYSICAL. A hierarchy of orbiting bodies (a star at the origin, a planet that spins on a tilted axis, a moon that circles the planet) whose real geometry GENERATES what the middle-scale systems consume: the sun's ... |
| stellar.js | Natura STELLAR: the deep-time energy source. A star's whole life told as a function of AGE in billions of years -- the slow main-sequence brightening, the swelling into a red giant, and the long cooling of the white-dwarf ember afterward. |
Land and water. The ground and what water does on and under it.
| module | what it is |
|---|---|
| worldgen.js | A LARGE, boundless CONTINENT for Natura (the operator's "large nearly-infinite spaces, not islands"). |
| tectonics.js | Natura TECTONICS: the deepest, slowest rung -- the ground itself is not fixed. The crust is broken into PLATES that drift, and where two plates CONVERGE their edges crumple upward into mountain ranges (the Himalaya, the Andes); where they pull APART the crust ... |
| terrain.js | Natura TERRAIN: the ground the world sits on, and the PHYSICAL half of "weather changes the world it falls on." Wraps the Terrain Engine for the initial island, then EVOLVES its heightfield by stream-power EROSION driven by the weather's moisture: where the ... |
| soil.js | Natura SOIL: pedogenesis and the matter cycle, the living skin between rock and life. Most worlds treat "fertility" as one number painted on the ground; this treats the SOIL as a real body that GROWS from bedrock, RECORDS the life that lived on it, MOVES ... |
| watershed.js | Natura GROUNDWATER + DRAINAGE (the subsurface layer the water CYCLE (hydro.js) leaves out). |
| hydro.js | Natura WATER CYCLE (ONTOLOGY-FOLD-IN #5): water as ONE CONSERVED substance moving through its phases. |
| ocean.js | Natura OCEAN / HYDROLOGY: where the water GOES. The rain the weather drops does not just vanish -- it runs downhill along the terrain, gathering into RIVERS (flow accumulation on the D8 drainage network), pooling in the hollows as LAKES, and reaching the sea ... |
| cryosphere.js | Natura CRYOSPHERE. Land ice as a per-cell mass balance: snow ACCUMULATES where the air is below freezing and ice ABLATES (melts) where it is above, by a degree-year model. |
Weather, fire and frost. The atmosphere and what it does to the ground.
| module | what it is |
|---|---|
| weather.js | The first real NATURA system: dynamic weather that CHANGES THE WORLD IT FALLS ON. A grid atmosphere over a terrain: drifting pressure systems drive a circulating wind (geostrophic), which advects TEMPERATURE and HUMIDITY (Stam semi-Lagrangian backtrace -- the ... |
| weather-patch.js | The LOCAL SKY over a single place, a render-free Natura system. The grid weather.js models a whole map's pressure fronts + orographic rain; this is its PATCH-scale sibling: one spot's CLOUD cover, RAIN, and soil MOISTURE, drifting over time and exposed as ... |
| fire.js | Natura FIRE: the drought -> fire -> regrowth loop, one of the most satisfying couplings in the framework. |
| frost.js | Natura MICRO / FROST: the small pole of the scale ladder, "the branching of rime on a leaf in a storm." Ice grows on a cold surface by vapour deposition, and it grows in DENDRITES -- feathery branches -- because the process is DIFFUSION-LIMITED: the tips ... |
Light, matter and pattern. Optics, materials, and the pattern-formers.
| module | what it is |
|---|---|
| canopy.js | A small Natura STRUCTURE system: a rainforest canopy as a LIGHT FIELD over height AND region. |
| caustics.js | Natura OPTICS: CAUSTICS (the net of light on the seafloor). The framework simulated heat and light as fields but never LIGHT PROPAGATION -- how a wavy water surface REFRACTS sunlight and piles it into the shifting bright web on the bottom of a pool. |
| refraction.js | Natura ATMOSPHERIC REFRACTION / MIRAGE (physical / optical): light bending through a near-surface air-temperature gradient. |
| chemistry.js | Natura CHEMISTRY / the CHEMICAL LAYER (ONTOLOGY-FOLD-IN #1, the biggest hole): matter that changes COMPOSITION, not just shape and temperature. |
| crystal.js | Natura CRYSTALLIZATION (physical / material): nucleation + grain growth, and the one law behind a geode, a cast metal, and a frozen pane -- HOW FAST IT COOLED SETS THE GRAIN. |
| granular.js | Natura GRANULAR MEDIA (physical / material): sand, grain, gravel -- a solid that flows but is not a fluid. |
| vortex.js | Natura VORTEX-BLOB FLUID (physical / micro-landscape): a Lagrangian fluid substrate. Instead of a grid, the flow is carried by a handful of VORTEX PARTICLES, each a little spin (circulation) in the fluid; each one whirls the fluid around it (smoothed 2D ... |
| reaction-diffusion.js | Natura REACTION-DIFFUSION: a two-chemical field that self-organises into Turing patterns. Render-free + deterministic (seeded rng, no Date/Math.random). |
| sync.js | Natura SYNCHRONIZATION (the Kuramoto model): a rhythm no one called. A population of phase oscillators, each with its OWN natural tempo, each nudged toward the phases it can hear -- and as the coupling K crosses a critical threshold the crowd spontaneously ... |
| growth.js | Procedural BRANCHING GROWTH: grow a whole form from one seed by a recursive branch rule. Render-free and deterministic (all randomness drawn from a seeded rng, never Math.random). |
Life. Plants, animals, populations and the webs between them.
| module | what it is |
|---|---|
| vegetation.js | Natura VEGETATION: plants grow, spread, and die by climate. The REAL "weather changes the world it falls on" -- it reads the weather's rain, holds a decaying SOIL-WATER, and grows BIOMASS logistically toward a carrying capacity set by water + warmth + season ... |
| biome.js | Natura BIOME DYNAMICS: the map of biomes CHANGES with the climate over time -- forests advance, deserts creep, tundra retreats up the mountains as the world warms. |
| ecosystem.js | Natura ECOSYSTEM: creatures living on the world. Agent-based predator-prey: HERBIVORES graze the vegetation (energy in, biomass out), move toward greener ground and flee predators, breed when fed and die when starved or old; PREDATORS hunt the herbivores ... |
| lifecycle.js | Natura LIFE-CYCLE. A creature's life as a state machine, and a POPULATION as the turnover of many: birth -> growth -> maturity -> aging -> death -> decay -> nutrients -> (the ground that feeds the next). |
| organisms.js | A GENERAL Natura LIFE system: a population of ENTITIES (animals AND phototroph plants alike) that each wear the shared ontology VERBS, driven by the world's LOCAL sun and fields. |
| rainforest-life.js | The RAINFOREST biome's SPECIES, a render-free registry for the organisms life system. One concern: WHAT lives in a rainforest and HOW it behaves -- each species declaring its chronotype and a small behave() that uses the shared VERBS (activity is set for it ... |
| mutualism.js | Natura MUTUALISM / COEVOLUTION (the cooperative +/+ edge of LIFE<->LIFE, the mirror of the ecosystem's antagonism). |
| niche.js | Natura NICHE CONSTRUCTION (ONTOLOGY-FOLD-IN #2, "the deepest living-world move left"): life that REMAKES its world and then lives in the changed world -- the inverse of "weather changes the world it falls on." A population of BUILDERS (beavers, corals, worms ... |
| sensing.js | Natura SENSING (ONTOLOGY-FOLD-IN #3, Life > sensing): what a creature can actually DETECT, and its LIMITS. |
| stigmergy.js | Natura SELF-ORGANIZED TRAILS (ONTOLOGY: the INFORMATION primitive as a deposited-and-decaying spatial FIELD). |
| wintering.js | Natura WINTERING: how a warm-blooded life gets through the lean season. The seasons made more than colour: the same autumn that turns the leaves is, for the animals, a race to lay something by, and the winter is a long ledger drawn down against it. |
Minds and societies. Belief, contagion, markets, knowledge and the built world.
| module | what it is |
|---|---|
| mind.js | Natura MIND (the ontology's MIND rung, previously untouched). The uncanny vein ONTOLOGY.md flagged: "the mind's model diverges from the world." A mind is not a sensor wired to reality; it holds its OWN MODEL (beliefs about nearby threat + food + a warm haven) ... |
| society.js | Natura SOCIETY. SOCIETY is emergent OVER many minds: it reads the MIND system beneath it and produces the collective. |
| epidemic.js | Natura/EXISTA EPIDEMIC (the SOCIETY domain's involuntary verb: CATCHING). A contagion moving through a population, run as real network epidemiology -- not a well-mixed scalar SIR but a POPULATION on a CONTACT NETWORK, where a pathogen passes only along the ... |
| economy.js | Natura/EXISTA ECONOMY (the SOCIETY domain's material verbs: producing, exchanging, pricing, distributing). |
| speculation.js | Natura/EXISTA SPECULATION (the SOCIETY domain's FINANCIAL market, the shadow of economy.js). |
| commons.js | Natura THE COMMONS (society / resource): a renewable common-pool resource and the tragedy that takes it, or the governance that saves it. |
| technology.js | Natura KNOWLEDGE / TECHNOLOGY (the ontology's CULTURE rung seen through what a people can DO, not what they feel). |
| traffic.js | Natura TRAFFIC (society / flow): the microscopic Intelligent Driver Model on a ring. Each driver accelerates toward a desired speed and brakes on the gap + closing-rate to the car ahead -- purely local, no coordination. |
| city.js | Natura CITY (the SOCIETY ontology's BUILT-WORLD rung; the first HUMAN-WORLD domain the framework has touched -- not a nature system but the artefact a society raises on the land it lives on). |
| settlements.js | Natura/EXISTA SETTLEMENTS: the human LONG GAME played out on a real watershed. A handful of villages sit on the valley the watershed.js aquifer feeds; each one DRAWS water from the SPATIAL water table (pumping it down, locally), FARMS the soil beside it ... |
| commonwealth.js | THE GRAND COUPLING. One running World in which the natural world and the human world are wired into a single causal web, so a shock in one place travels downstream through all the others with real LAG. |
Made things. Artifacts that wear out, structures that bear load, mechanisms that move.
| module | what it is |
|---|---|
| artifact.js | Natura ARTIFICE (a domain the framework has never touched, and deliberately NOT nature): the LIFE-CYCLE OF MADE THINGS. |
| structure.js | Natura STRUCTURE (artifice / material, EXISTA): load, stability, and failure. artifact.js wears things out statistically; this resolves real FORCE through a structure. |
| mechanism.js | Natura MECHANISM: rigid-body planar kinematics -- linkages (joints + bars + sliders) and GEARS (external, internal-ring, orbiting planets, racks). |
Verbs. Small, render-free behaviours any life system can share (verbs/).
| module | what it is |
|---|---|
| verbs/index.js | The thin ROUTER for the life ontology verbs. It holds NO logic; it just composes the small single-concern verb files (daynight / forage / flee / phenology / school) into one flat `Verbs` surface a life system can reach for. |
| verbs/daynight.js | ONE life ontology verb, one concern: an organism's day/night ACTIVITY (wake <-> rest) read from the LOCAL sun by its CHRONOTYPE. |
| verbs/forage.js | ONE life ontology verb, one concern: move toward the best LOCAL source of a resource when you need it. |
| verbs/flee.js | ONE life ontology verb, one concern: move AWAY from a local threat (the inverse of forage). |
| verbs/school.js | ONE life ontology verb, one concern: move WITH your neighbours (shoaling / flocking / herding). |
| verbs/phenology.js | ONE life ontology verb, one concern: the LIFE-STAGE GROWTH a living thing moves through over its lifetime. |
| verbs/court.js | ONE life ontology verb, one concern: COURTSHIP + MATE CHOICE, the engine of SEXUAL selection (distinct from natural selection: who SURVIVES vs who is CHOSEN). |
Laws. Physical laws as plain functions (laws/).
| module | what it is |
|---|---|
| laws/interference-colour.js | The FOUNDING module of the neap.framework LAWS library (2026-08-22). ONE wave-optics law, MANY physical manifestations: a perceived colour arises when white light is split into two beams with an OPTICAL PATH DIFFERENCE (OPD, in nanometres) that then ... |
| laws/blackbody.js | The colour of HEAT, the second member of the neap.framework LAWS library (2026-08-22). A hot thing GLOWS, and its colour is set by ONE number: its temperature. |
Creatures. Drawing and sounding animals: data, 2D and 3D drawing, behaviour, voice (creatures/).
| module | what it is |
|---|---|
| creatures/creatures.js | Creatures: the FACADE that composes the layers. The one public entry point. |
| creatures/species.js | CreatureSpecies: the DATA layer of the creature factory. Pure data, no drawing and no behaviour: each entry is a set of proportions, colours and feature flags that the renderer (creatures/render.js) turns into an animal, and the facade ... |
| creatures/render.js | CreatureRender: the DRAWING layer. Turns a species def (from creatures/species.js) plus a pose (from creatures/behaviour.js, eased by the caller) into pixels on a 2D canvas context. |
| creatures/behaviour.js | CreatureBehaviour: the DECISION layer. What an animal DOES over time, kept apart from how it is drawn (creatures/render.js) and from what it is (creatures/species.js). |
| creatures/voice.js | The SOUND concern of the creatures framework (the 4th layer, beside species DATA, render DRAWING, behaviour DECISION). |
| creatures/render3d.js | FIRST-CLASS 3D for the natura creatures framework. The 2D side (render.js) draws a creature in profile. |
| creatures/sdfmesh.js | UNIFY the elephant primitives into ONE watertight mesh. The parametric build (render3d.js buildElephant) is separate primitives that INTERSECT -- so junctions (leg-body, trunk-face, ear-head) z-fight and never truly connect. |
| creatures/rig.js | SKIN the unified SDF elephant so it ANIMATES without a per-frame rebuild. buildElephantUnified makes ONE watertight mesh (~100-200ms) -- too slow to rebuild every frame. |
| creatures/skinned-gl.js | A sculpted, skinned, TEXTURED creature in real time (2026-09-26: my zebra and giraffe). The canvas painter (render3d.js) shades a triangle soup, one colour per face: fine for creatures built from primitives, but a coat of crisp stripes or a thin cream net ... |
| scene-meadow.js | MorningMeadow: the shared early-morning MEADOW BACKDROP. The environment behind the creatures, factored out so First Light and the sim-driven Living Meadow (and any future ground-level Natura view) draw the SAME morning world instead of each keeping its own ... |
Scripts and probes. Run in node: exports of a creature model to a file, and robustness probes.
| module | what it is |
|---|---|
| creatures/export-obj.js | Bridge the JS "bkit" to the Blender .py bkit: build the unified elephant with buildElephantUnified and write a Wavefront OBJ + MTL (grouped by material) that Blender can import for a Cycles/Eevee hero render. |
| creatures/export-dae.js | Export the natura elephant as a COLLADA .dae (geometry + normals + one material per colour) for upload into OpenSimulator (which ingests COLLADA). |
| creatures/export-dae-rigged.js | Export the natura elephant as a RIGGED COLLADA .dae: a real custom anatomical skeleton (pelvis/spine/chest/neck/head, a 5-bone trunk chain, four legs each hip->knee->foot, two ears, a tail = 25 bones) + weighted linear-blend skinning derived from the rig's ... |
| creatures/export-meshdata.js | Export the elephant geometry as compact JSON per-material submeshes (local-indexed) for the WorldBridge module to encode into an OpenSim llmesh asset server-side. |
| daynight-probe.js | Verify the DAY/NIGHT ACTIVITY verb by RUNNING it (the balance-trap lesson: never reason that a behaviour "should" stabilise; run it ON vs OFF, multi-seed, and read the ground truth). |
| scale-probe.js | Does each system's EMERGENCE survive a change of SCALE (grid size / agent count / dt)? Not a unit test of correctness (the *-test.js files do that) but a robustness sweep: run each system's signature emergence at a SMALL scale and a LARGE scale (and, where dt ... |
The core
The clock, the system interface, the registry and the World runner that couples systems.
natura.js
The CORE of the Natura pocket-universe framework (see DESIGN.md, ONTOLOGY.md). The beating heart everything plugs into: a universal CLOCK (one time, every cadence day->eon), a common SYSTEM interface (generalizing the Terrain Engine's PROCESS -- init/step/fields/events, deterministic + testable), a REGISTRY of system definitions, and the WORLD runner that steps a chosen STACK of systems and COUPLES them (each system reads the others' exposed fields). Composable: a world is a chosen set of systems; run one (frost on a leaf) or many (planet+climate+weather+life).
Deterministic by construction: the clock time and dt are INPUTS, randomness comes from a seeded rng (no Date.now / Math.random) -- so a run is reproducible and resumable. UMD (node test / window.Natura).
- Source
natura.js(119 lines)- Load
- browser:
<script src="natura.js">definesNatura; node:require('./natura.js') - Exports
World,makeClock,defineSystem,getSystem,clearRegistry,rngFrom,mix,UNITS- Factory
makeClock(config)returns object, not a system definition- Tests
natura-test.js(passes, 22 assertions); also loaded byartifact-test.js,biome-test.js,canopy-test.js,caustics-test.js,celestial-test.js,chemistry-test.js,city-test.js,commons-test.js,commonwealth-test.js,compose-test.js,cryosphere-test.js,crystal-test.js,daynight-probe.js,economy-test.js,ecosystem-test.js,epidemic-test.js,fire-test.js,frost-test.js,granular-test.js,growth-test.js,hydro-test.js,lifecycle-test.js,mind-test.js,mutualism-test.js,niche-test.js,ocean-test.js,organisms-test.js,quickstart-test.js,rainforest-life-test.js,reaction-diffusion-test.js,refraction-test.js,scale-probe.js,settlements-test.js,society-test.js,soil-test.js,speculation-test.js,stellar-test.js,stigmergy-test.js,structure-test.js,sync-test.js,technology-test.js,tectonics-test.js,terrain-test.js,traffic-test.js,vegetation-test.js,verbs/court-test.js,vortex-test.js,watershed-test.js,weather-patch-test.js,weather-test.js,wintering-test.js(all pass)
Sky and star
The clock made physical, and the deep-time energy source.
celestial.js
Natura CELESTIAL (SYSTEMS.md, ALGORITHMS.md): the abstract clock made PHYSICAL. A hierarchy of orbiting bodies (a star at the origin, a planet that spins on a tilted axis, a moon that circles the planet) whose real geometry GENERATES what the middle-scale systems consume: the sun's altitude and the daylight at the world's latitude, the seasons from axial tilt, the moon's phase, and the tides (semidiurnal, with spring/neap from sun-moon alignment). It reaches UP to the cosmic scale -- the body list is an orrery you can add planets and moons to -- and DOWN into the climate: weather and vegetation can read celestial.daylight / .decl instead of the clock's heuristic, so the sun physically drives the world. Everything is ANALYTIC in the clock time (no integration drift, fully resumable) and deterministic. Couples to: (out) weather, vegetation, ocean/tides.
A Natura system spec (init/step/fields/events). UMD (node test / window.Celestial).
- Source
celestial.js(184 lines)- Load
- browser:
<script src="celestial.js">definesCelestial; node:require('./celestial.js') - Exports
makeCelestial- System
makeCelestial(config)returns the system'celestial'(domaincosmic, scaleplanetary; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.celestial.*:daylight,decl,sunAltitude,insolation,dayLengthHours,moonPhase,moonIllum,tide,springNeap,season(string),bodies(array) - Tests
celestial-test.js(passes, 15 assertions); also loaded byocean-test.js(all pass)
stellar.js
Natura STELLAR (SYSTEMS.md #11, ALGORITHMS.md): the deep-time energy source. A star's whole life told as a function of AGE in billions of years -- the slow main-sequence brightening, the swelling into a red giant, and the long cooling of the white-dwarf ember afterward. Everything is ANALYTIC in the clock time (no integration over a Gyr), so it is exact and resumable at any moment of the star's life. It exposes the star's luminosity, radius, temperature, and phase, and the INSOLATION at a planet's orbit -- which is the boundary condition the whole climate hangs from: a brightening sun marches the habitable zone outward (frozen -> temperate -> scorched over eons), and the biome system, reading that trend, shifts the living world to match. The cosmic rung of the scale ladder.
Reads only the clock (at eon scale). Deterministic + node-testable. UMD (node test / window.Stellar).
- Source
stellar.js(88 lines)- Load
- browser:
<script src="stellar.js">definesStellar; node:require('./stellar.js') - Exports
makeStellar,evolve- System
makeStellar(config)returns the system'stellar'(domaincosmic, scalestellar; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.stellar.*:luminosity,radius,temperature,phase(string),insolation,ageGyr - Tests
stellar-test.js(passes, 8 assertions); also loaded bybiome-test.js,cryosphere-test.js(all pass)
Land and water
The ground and what water does on and under it.
worldgen.js
A LARGE, boundless CONTINENT for Natura (the operator's "large nearly-infinite spaces, not islands"). Periodic value-noise fBm plus ridged mountain ranges, TILEABLE on the [-1,1]^2 domain: because the lattice wraps, the world is a seamless torus you can walk forever, with real climate zones (mountain ranges throw rain-shadows, so the windward side is wet and the lee is dry) that creatures migrate across. Land-dominant with inland seas, so life has continuous room to roam. Deterministic per seed (no Date.now / Math.random). UMD (node + browser). heightAt(x,y): >0 land, <0 sea, ~0.3+ mountains.
- Source
worldgen.js(66 lines)- Load
- browser:
<script src="worldgen.js">definesWorldGen; node:require('./worldgen.js') - Exports
makeContinent,pnoise,pfbm,pridge- Factory
makeContinent(config)returns object, not a system definition- Tests
- no test of its own; also loaded by
biome-test.js,fire-test.js,ocean-test.js(all pass)
tectonics.js
Natura TECTONICS (SYSTEMS.md #10, ALGORITHMS.md): the deepest, slowest rung -- the ground itself is not fixed. The crust is broken into PLATES that drift, and where two plates CONVERGE their edges crumple upward into mountain ranges (the Himalaya, the Andes); where they pull APART the crust thins and RIFTS into valleys and new sea; and away from the edges the old highlands erode slowly back down (isostasy). Run it over millions of years and a flat craton grows a cordillera along its convergent margins. This is the boundary condition UNDER the terrain -- a continent that worldgen draws in an instant, tectonics makes EVOLVE. The bottom of the cross-scale stack: plate motion over Myr sets the elevation that weather rains on, that rivers carve, that life lives on.
A Natura system spec (init/step/fields/events). Reads only the clock (deep time) + a seeded rng. Deterministic + node-testable. UMD (node test / window.Tectonics).
- Source
tectonics.js(138 lines)- Load
- browser:
<script src="tectonics.js">definesTectonics; node:require('./tectonics.js') - Exports
makeTectonics- System
makeTectonics(config)returns the system'tectonics'(domainphysical, scaleplanetary; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.tectonics.*:N,elevation(Float32Array),plate(Int8Array) - Tests
tectonics-test.js(passes, 6 assertions)
terrain.js
Natura TERRAIN (SYSTEMS.md #2, ALGORITHMS.md): the ground the world sits on, and the PHYSICAL half of "weather changes the world it falls on." Wraps the Terrain Engine for the initial island, then EVOLVES its heightfield by stream-power EROSION driven by the weather's moisture: where the rain runs (high flow) over steep ground that has been WET, it incises. So the windward slopes wear down under the rain-shadow's rain while the dry lee is preserved -- erosion inherits the rain-shadow, the way vegetation does, only in stone instead of leaf.
A Natura system spec (init/step/fields), deterministic + node-testable. Couples to WEATHER (moisture). Computes its own D8 flow accumulation (the engine's flow needs separate setup). UMD.
- Source
terrain.js(109 lines)- Load
- browser:
<script src="terrain.js">definesNaturaTerrain; node:require('./terrain.js') - Exports
makeTerrain- System
makeTerrain(config)returns the system'terrain'(domainphysical, scaleplanetary; hooks: init, step, fields)- Fields
- read as
ctx.fields.terrain.*:N,elevation(Float32Array),slope(Float32Array),flow(Float32Array),land(Uint8Array),seaLevel - Tests
terrain-test.js(passes, 7 assertions)
soil.js
Natura SOIL: pedogenesis and the matter cycle, the living skin between rock and life. Most worlds treat "fertility" as one number painted on the ground; this treats the SOIL as a real body that GROWS from bedrock, RECORDS the life that lived on it, MOVES downhill as mass, and feeds the plants that in turn build it. It is the slow verb of the land: stone becomes grit becomes soil becomes food becomes leaf becomes soil, and a hillside sorts itself into bare ridges and fat valley floors because the matter literally runs downhill. Nothing here is a scalar knob -- every cell carries a column of real stuff whose mass is conserved, so the emergences (a soil CATENA, fertile bottoms, a land that remembers its biology, a mass-balanced loop, and the wound a fire leaves on bare ground) FALL OUT of the mechanism rather than being written in.
The mechanisms, all coupled on an N x N terrain grid: 1. WEATHERING -- bedrock -> regolith -> mineral soil. PHYSICAL (freeze-thaw, driven by temperature swings across 0C) makes coarse grit (sand/silt); CHEMICAL (dissolution/oxidation, driven by moisture x warmth) makes clay and frees a trickle of mineral nutrient. Rate gated by climate + slope. 2. HORIZONS / DEPTH -- a real soil column: a LITTER layer (fresh dead matter), a HUMUS store (the dark decomposed carbon), a MINERAL soil depth, over WEATHERED regolith, over BEDROCK. 3. ORGANIC CYCLE -- litter in (from the vegetation/carcass driver) -> DECOMPOSITION (moisture+temp) -> humus -> MINERALIZATION -> plant-available NITROGEN and PHOSPHORUS, each with uptake + leaching. 4. MOISTURE + TEXTURE -- water-holding capacity rises with CLAY and humus; sandy/steep ground DRAINS and leaches. Texture itself is an emergent product of which weathering won. 5. EROSION + DEPOSITION -- slope + surface water strip the topsoil (humus, fine mineral, and the nutrients riding in them) off ridges and lay them down in the valleys. Mass MOVES, never vanishes. 6. VEGETATION FEEDBACK (two-way) -- soil depth + fertility + moisture GATE plant growth; plant growth and death BUILD soil (litter above, roots mixed below). The land and its life co-produce each other.
Ships with its OWN self-contained drivers (a slope heightfield, a moisture+temperature climate, and a soil-responsive vegetation/litter source) so it RUNS and TESTS standalone -- but it reads ctx.fields for 'terrain', 'weather', and 'vegetation' when present, so it COUPLES to the real systems unchanged.
A Natura system spec (init/step/fields/events), deterministic by construction: randomness comes ONLY from init(rng) and ctx.rng, time is dt (seconds) and ctx.clock. UMD (node test / window.Soil).
- Source
soil.js(758 lines)- Load
- browser:
<script src="soil.js">definesSoil; node:require('./soil.js') - Exports
makeSoil- System
makeSoil(config)returns the system'soil'(domaingeology, scalepedological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.soil.*:N,land(Uint8Array),bedrock(Float32Array),regolith(Float32Array),mineral(Float32Array),humus(Float32Array),litter(Float32Array),soilDepth(Float32Array),surface(Float32Array),sand(Float32Array),silt(Float32Array),clay(Float32Array),availN(Float32Array),availP(Float32Array),organicN(Float32Array),organicP(Float32Array),fertility(Float32Array),moisture(Float32Array),whc(Float32Array),water(Float32Array),slope(Float32Array),flow(Float32Array),initSlope(Float32Array),biomass(Float32Array),ledger(object) - Tests
soil-test.js(passes, 28 assertions)
watershed.js
Natura GROUNDWATER + DRAINAGE (the subsurface layer the water CYCLE (hydro.js) leaves out). hydro.js moves water through its phases above ground; ocean.js routes coastal rivers; but nowhere does the land itself have a DRAINAGE NETWORK carved by where the water must go, nor a hidden WATER TABLE beneath it. Here the terrain is read once and solved: every hollow is filled so water never dead-ends (priority-flood), flow is routed downhill (D8) and ACCUMULATED, so the branching tree of streams-to-rivers-to-sea emerges as the memory of where the water went. Beneath it sits the AQUIFER -- a smoothed water table that RISES with recharge (couple it to hydro's moisture or weather's rain) and FALLS with warmth/drought; where it breaks the surface, SPRINGS flow; where it sinks away, the ground goes dry. So drought and flush here are not a dialled knob but an emergent consequence of the coupled climate. Deterministic, node-testable. UMD.
- Source
watershed.js(172 lines)- Load
- browser:
<script src="watershed.js">definesWatershed; node:require('./watershed.js') - Exports
makeWatershed- System
makeWatershed(config)returns the system'watershed'(domainphysical, scalelandscape; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.watershed.*:N,elev(Float32Array),filled(Float32Array),flowAccum(Float32Array),riverMask(Uint8Array),waterTable(Float32Array),depthToWater(Float32Array),springMask(Uint8Array),lake(Uint8Array),adj(Float32Array),offset,springCount,riverCount,maxAcc,land - Tests
watershed-test.js(passes, 13 assertions); also loaded byscale-probe.js,settlements-test.js(all pass)
hydro.js
Natura WATER CYCLE (ONTOLOGY-FOLD-IN #5): water as ONE CONSERVED substance moving through its phases. Weather already rains and ocean already routes rivers, but nowhere is the water a single conserved budget -- so here every drop is accounted for across LIQUID (pools, soil), VAPOUR (in the air), and CLOUD (condensed aloft), and the total never changes. Warmth EVAPORATES liquid to vapour; vapour drifts and, where the air is cool enough to be over-full, CONDENSES to cloud; cloud RAINS back to liquid; liquid RUNS downhill and pools in the valleys -- then evaporates again. The emergence is the CONSERVATION itself: drought and flood are not water made or destroyed, they are the same water out of balance (warm one place, dry it, and the water it loses falls as rain and flood somewhere cooler). Couples to WEATHER (temperature) + TERRAIN (runoff) and, naturally, to the CRYOSPHERE (ice is water locked out of the cycle). Deterministic, node-testable. UMD.
- Source
hydro.js(118 lines)- Load
- browser:
<script src="hydro.js">definesHydro; node:require('./hydro.js') - Exports
makeHydro- System
makeHydro(config)returns the system'hydro'(domainphysical, scalelandscape; hooks: init, step, fields)- Fields
- read as
ctx.fields.hydro.*:N,liquid(Float32Array),vapour(Float32Array),cloud(Float32Array),ice(Float32Array),moisture(Float32Array),elev(Float32Array),total - Tests
hydro-test.js(passes, 9 assertions); also loaded bycompose-test.js,watershed-test.js(all pass)
ocean.js
Natura OCEAN / HYDROLOGY (SYSTEMS.md #4, ALGORITHMS.md): where the water GOES. The rain the weather drops does not just vanish -- it runs downhill along the terrain, gathering into RIVERS (flow accumulation on the D8 drainage network), pooling in the hollows as LAKES, and reaching the sea; and the SEA itself breathes with the moon -- celestial's tide raises and lowers sea level, so the coastline advances and retreats over the tidal flats. Heavy rain over a big catchment brings a FLOOD. This closes the water cycle (rain -> runoff -> river -> sea -> evaporation -> rain) and makes the celestial TIDES visible on the shore -- one system reading another's output, the coupling made real.
A Natura system spec (init/step/fields/events), deterministic + node-testable. Reads an elevation sampler, weather.rain, and celestial.tide. UMD (node test / window.Ocean).
- Source
ocean.js(114 lines)- Load
- browser:
<script src="ocean.js">definesOcean; node:require('./ocean.js') - Exports
makeOcean- System
makeOcean(config)returns the system'ocean'(domainphysical, scalelandscape; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.ocean.*:N,riverFlow(Float32Array),water(Float32Array),seaNow,land(Uint8Array),elev(Float32Array) - Tests
ocean-test.js(passes, 6 assertions)
cryosphere.js
Natura CRYOSPHERE (the ICE domain, SYSTEMS.md: the missing cold force under the physical stack). Land ice as a per-cell mass balance: snow ACCUMULATES where the air is below freezing and ice ABLATES (melts) where it is above, by a degree-year model. The whole thing is bound together by the ICE-ALBEDO FEEDBACK -- white ice reflects sunlight, so the more of the land is iced the COLDER the world gets, which grows more ice: a positive loop that makes the climate BISTABLE. That is the emergence this system exists to show -- an ICE AGE is not a smooth response to cooling but a TIPPING: the ice stays near zero as the world cools, then past a threshold it runs away to a glaciated planet, and to melt it back you must warm well PAST where it first froze (hysteresis). The ice also LOCKS UP water (the sea withdraws) and GRINDS the bedrock it sits on (glacial carving), so it couples out to the ocean and the terrain.
Reads a deep-time temperature forcing (a scalar, or a fn of the clock) + optional STELLAR insolation (a fainter sun -> a colder world -> more ice) + an elevation sampler (mountains glaciate first). Deterministic, node-testable. UMD (node test / window.Cryosphere).
- Source
cryosphere.js(145 lines)- Load
- browser:
<script src="cryosphere.js">definesCryosphere; node:require('./cryosphere.js') - Exports
makeCryosphere- System
makeCryosphere(config)returns the system'cryosphere'(domainphysical, scalegeological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.cryosphere.*:N,ice(Float32Array),carve(Float32Array),iceFraction,meanAlbedo,seaLevelDrop,snowElev,volume,forcing - Tests
cryosphere-test.js(passes, 15 assertions); also loaded bycompose-test.js(all pass)
Weather, fire and frost
The atmosphere and what it does to the ground.
weather.js
The first real NATURA system (DESIGN.md step 1): dynamic weather that CHANGES THE WORLD IT FALLS ON. A grid atmosphere over a terrain: drifting pressure systems drive a circulating wind (geostrophic), which advects TEMPERATURE and HUMIDITY (Stam semi-Lagrangian backtrace -- the fluids-and-flow recipe); air forced UP over mountains cools and rains (orographic), leaving the lee dry (rain-shadow emerges, it is not scripted); rain ACCUMULATES into a moisture field other systems (erosion, vegetation) read -- the coupling that makes weather change the ground.
A Natura system spec (init/step/fields/events), deterministic + node-testable. Reads the clock for season + day/night. Terrain comes in as an elevation sampler so weather stands alone and tests alone; wiring the real Terrain Engine as the coupled terrain system is a thin later step. UMD (node test / window.Weather).
- Source
weather.js(159 lines)- Load
- browser:
<script src="weather.js">definesWeather; node:require('./weather.js') - Exports
makeWeather,satOf- System
makeWeather(config)returns the system'weather'(domainphysical, scaleweather; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.weather.*:N,rain(Float32Array),moisture(Float32Array),temp(Float32Array),cloud(Float32Array),pressure(Float32Array),windU(Float32Array),windV(Float32Array),land(Uint8Array) - Tests
weather-test.js(passes, 10 assertions); also loaded bybiome-test.js,daynight-probe.js,ecosystem-test.js,fire-test.js,frost-test.js,ocean-test.js,quickstart-test.js,scale-probe.js,terrain-test.js,vegetation-test.js(all pass)
weather-patch.js
The LOCAL SKY over a single place, a render-free Natura system. The grid weather.js models a whole map's pressure fronts + orographic rain; this is its PATCH-scale sibling: one spot's CLOUD cover, RAIN, and soil MOISTURE, drifting over time and exposed as fields the rest of the world reads -- a cloud dims the canopy light, rain wets the ground, moisture makes the flowers bloom and the fruit ripen. "Weather that changes the world it falls on," at the scale of a clearing. Deterministic: cloud drifts as a sum of slow sines at incommensurate (seeded) periods, so it never repeats but always reproduces; moisture integrates the rain and drains when dry. It runs on REAL elapsed time (ctx dt), independent of the day cycle, so wet and dry spells come and go over minutes while the day turns on its own clock. UMD (node / window.WeatherPatch).
- Source
weather-patch.js(44 lines)- Load
- browser:
<script src="weather-patch.js">definesWeatherPatch; node:require('./weather-patch.js') - Exports
makeWeatherPatch- System
makeWeatherPatch(config)returns the system'weather'(domainphysical, scalelocal; hooks: init, step, fields)- Fields
- read as
ctx.fields.weather.*:cloud,rain,moisture - Tests
weather-patch-test.js(passes, 8 assertions)
fire.js
Natura FIRE (SYSTEMS.md #9, ALGORITHMS.md): the drought -> fire -> regrowth loop, one of the most satisfying couplings in the framework. A single lightning strike in a dry season catches in the fuel (the vegetation), and the fire SPREADS cell to cell -- faster DOWNWIND (the weather's wind) and UPSLOPE (the terrain), stronger where the fuel is thick and the ground is dry, and it DIES against wet ground or where the fuel runs out. Burning consumes the vegetation (couples back: the biomass drops where it burns) and leaves a SCAR that slowly heals as the plants regrow -- so the same valley can burn again seasons later. Emergent: the burn follows the wind, wet regions survive as firebreaks, a dry year carries a strike across a whole catchment.
A Natura system spec (init/step/fields/events). Reads vegetation (biomass=fuel, soilWater=dryness), weather (wind), and an elevation sampler (slope). Deterministic + node-testable. UMD.
- Source
fire.js(127 lines)- Load
- browser:
<script src="fire.js">definesFire; node:require('./fire.js') - Exports
makeFire- System
makeFire(config)returns the system'fire'(domainphysical, scalelocal; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.fire.*:N,fire(Float32Array),scar(Float32Array),burned(Float32Array) - Tests
fire-test.js(passes, 8 assertions); also loaded byscale-probe.js(all pass)
frost.js
Natura MICRO / FROST (SYSTEMS.md #12, ALGORITHMS.md): the small pole of the scale ladder, "the branching of rime on a leaf in a storm." Ice grows on a cold surface by vapour deposition, and it grows in DENDRITES -- feathery branches -- because the process is DIFFUSION-LIMITED: the tips stick out into the undepleted vapour and grow fastest, while the hollows are starved, so the pattern forks and forks again. This is the dielectric-breakdown / DLA model (the eta-exponent controls how feathery): a Laplacian VAPOUR field (1 at the far edges, 0 on the ice) relaxes each step, and the frost adds cells on its frontier with probability proportional to the local vapour^eta. Standalone it grows a snowflake; in a world it ACTIVATES only where the weather is below freezing and humid -- a micro system woken by the macro one. The same recipe draws lightning and river deltas; here it is rime.
A Natura system spec (init/step/fields/events), deterministic (seeded rng). UMD (node test / window.Frost).
- Source
frost.js(95 lines)- Load
- browser:
<script src="frost.js">definesFrost; node:require('./frost.js') - Exports
makeFrost- System
makeFrost(config)returns the system'frost'(domainphysical, scalemicro; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.frost.*:N,ice(Uint8Array),count - Tests
frost-test.js(passes, 7 assertions)
Light, matter and pattern
Optics, materials, and the pattern-formers.
canopy.js
A small Natura STRUCTURE system: a rainforest canopy as a LIGHT FIELD over height AND region.
One concern, render-free: it exposes the forest's light structure as fields() the way weather exposes moisture -- sunAt(x,y) : the LOCAL sun elevation [-1,1] at a place -- the world's day phase shifted by the place's REGION (longitude, east dawns earlier) and dimmed by its canopy SHADE (depth). Organisms read this to wear the day/night verb per their layer + region: the floor keeps the shortest, latest day of all. lightAt(y) : light intensity [0,1] reaching height y (ambient daylight * Beer-Lambert transmission down the leaves). shadeAt(y) : the canopy light-debt at height y (gentle-capped, fed to the verb's {shade}). gaps, layers: the sky-gaps (where shafts fall) and the layer bands -- for the renderer. The sun comes from the world CLOCK (day phase), so region-phase is a real time-shift; a celestial coupling can refine amplitude later. Static structure (gaps/transmission are seeded once); nothing here touches a canvas. UMD.
- Source
canopy.js(60 lines)- Load
- browser:
<script src="canopy.js">definesCanopy; node:require('./canopy.js') - Exports
makeCanopy,LAYERS- System
makeCanopy(config)returns the system'canopy'(domainphysical, scalelocal; hooks: init, step, fields)- Fields
- read as
ctx.fields.canopy.*:gaps(array),layers(object),transmission(function),shadeAt(function),lightAt(function),sunAt(function),daylight,dayPhase,cloud - Tests
canopy-test.js(passes, 19 assertions); also loaded byrainforest-life-test.js(all pass)
caustics.js
Natura OPTICS: CAUSTICS (the net of light on the seafloor). The framework simulated heat and light as fields but never LIGHT PROPAGATION -- how a wavy water surface REFRACTS sunlight and piles it into the shifting bright web on the bottom of a pool. Parallel sunlight strikes the surface; at each point the surface tilt bends the ray (Snell, air->water), and the bent rays travel down to the floor and LAND -- converging into bright fold-lines where the surface is concave, thinning where it is convex. The light is CONSERVED (every ray lands somewhere) but REDISTRIBUTED, which is exactly what a caustic is: not more light, but gathered light. Couples to ocean/hydro (drive it from the live water-surface height field). Deterministic, node-testable. UMD. The reusable core of the August light pieces (Where the Light Gathers, The Net of Light, The Light in Your Cup).
- Source
caustics.js(85 lines)- Load
- browser:
<script src="caustics.js">definesCaustics; node:require('./caustics.js') - Exports
makeCaustics- System
makeCaustics(config)returns the system'caustics'(domainphysical, scalelandscape; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.caustics.*:N,caustic(Float32Array),surface(Float32Array),peakToMean,totalLight - Tests
caustics-test.js(passes, 7 assertions); also loaded byscale-probe.js(all pass)
refraction.js
Natura ATMOSPHERIC REFRACTION / MIRAGE (physical / optical): light bending through a near-surface air-temperature gradient. Hot ground makes a thin low-density (low-n) layer, so rays curve UP and you see the sky pooled on the road ahead -- the INFERIOR mirage (the desert "water"). A cold surface under warm air (an INVERSION) makes a dense high-n layer, so rays curve DOWN and distant things LOOM, rise, and stack into a Fata Morgana -- the SUPERIOR mirage (a ship that becomes a castle in the air). The sign of the gradient sets the mirage; its strength sets how far a thing is displaced. Sibling of caustics.js (surface refraction); this is the atmospheric half. Couples to weather (the temperature). Deterministic, node-testable. UMD. From Castle in the Air.
- Source
refraction.js(53 lines)- Load
- browser:
<script src="refraction.js">definesRefraction; node:require('./refraction.js') - Exports
makeRefraction- System
makeRefraction(config)returns the system'refraction'(domainphysical, scalelandscape; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.refraction.*:bend,anomaly,mirageType(string),inverted(boolean),apparent(function),loom - Tests
refraction-test.js(passes, 5 assertions)
chemistry.js
Natura CHEMISTRY / the CHEMICAL LAYER (ONTOLOGY-FOLD-IN #1, the biggest hole): matter that changes COMPOSITION, not just shape and temperature. Every STATES system so far is thermal / phase / mechanical / erosive -- iron bends and melts but never RUSTS. Here each cell holds a MATERIAL and an aging progress 0..1, and it WEATHERS over sim-time driven by EXPOSURE: iron rusts in DAMP air (dry iron barely ages -- the driver, not the clock, decides), copper and bronze grow a green PATINA over decades, silver TARNISHES, wood ROTS where it is damp AND warm. The emergence is that composition tracks the CONDITIONS: the same iron rusts on the wet coast and stays bright in the desert. Couples to WEATHER (moisture), and gives ARTIFACT a chemical clock (a bronze statue greens, a shipwreck rusts). Deterministic, node-testable. UMD (node test / window.Chemistry).
- Source
chemistry.js(106 lines)- Load
- browser:
<script src="chemistry.js">definesChemistry; node:require('./chemistry.js') - Exports
makeChemistry,matColor,MATERIALS,IDX- System
makeChemistry(config)returns the system'chemistry'(domainphysical, scalematerial; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.chemistry.*:N,material(Int8Array),aged(Float32Array),meanAged,matColor(function),MATERIALS(array) - Tests
chemistry-test.js(passes, 10 assertions); also loaded bycompose-test.js(all pass)
crystal.js
Natura CRYSTALLIZATION (physical / material): nucleation + grain growth, and the one law behind a geode, a cast metal, and a frozen pane -- HOW FAST IT COOLED SETS THE GRAIN. As the melt cools, nuclei appear (faster cooling -> many nuclei at once); each is the seed of a GRAIN that grows outward until it meets its neighbours, tiling the whole into a mosaic. Cool it FAST and you get a swarm of tiny grains (a fine, hard microstructure); cool it SLOW and a few nuclei grow into big lazy crystals (the geode's cathedral). Grain size ~ 1/nucleation-density -- the metallurgist's Hall-Petch knob. Distinct from frost.js (DLA dendrites, a different growth law). Deterministic, node-testable. UMD. From Geode / How Slowly It Cooled / The Grain in the Steel.
- Source
crystal.js(78 lines)- Load
- browser:
<script src="crystal.js">definesCrystal; node:require('./crystal.js') - Exports
makeCrystal- System
makeCrystal(config)returns the system'crystal'(domainphysical, scalemicro; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.crystal.*:N,grain(Int32Array),orient(Float32Array),grainCount,meanGrainSize,solidFraction - Tests
crystal-test.js(passes, 5 assertions); also loaded byscale-probe.js(all pass)
granular.js
Natura GRANULAR MEDIA (physical / material): sand, grain, gravel -- a solid that flows but is not a fluid. A cellular pile under gravity: grains fall, and when blocked slide diagonally, so a poured heap settles to its ANGLE OF REPOSE instead of leveling like water. Drain it through an orifice and the strangest thing: the flow is CONSTANT, independent of how much sand is left above (Beverloo's law) -- an hourglass keeps time because of it -- and a too-narrow orifice ARCHES and JAMS. (The Brazil-nut segregation is the sibling behaviour under shaking; noted for a later mode.) From The Narrow of the Glass / The Big One Rises. Deterministic (seeded tie-break), node-testable. UMD.
- Source
granular.js(76 lines)- Load
- browser:
<script src="granular.js">definesGranular; node:require('./granular.js') - Exports
makeGranular- System
makeGranular(config)returns the system'granular'(domainphysical, scalemicro; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.granular.*:N,H,grid(Uint8Array),count,exited,discharge,heapWidth,heapHeight - Tests
granular-test.js(passes, 5 assertions); also loaded byscale-probe.js(all pass)
vortex.js
Natura VORTEX-BLOB FLUID (physical / micro-landscape): a Lagrangian fluid substrate. Instead of a grid, the flow is carried by a handful of VORTEX PARTICLES, each a little spin (circulation) in the fluid; each one whirls the fluid around it (smoothed 2D Biot-Savart), and so they advect EACH OTHER. Out of that fall the classic emergent motions: a counter-rotating PAIR self-propels in a straight line (a smoke ring's cross-section), like-signed vortices ORBIT one another, and circulation is conserved throughout. It gives a cheap VELOCITY FIELD other systems can drift smoke / fog / seeds / scent through. SYSTEMS.md #12 named "a smoke-ring (vortex-blob)" as a planned MICRO member; this builds it. From "It Carries Itself". Deterministic, node-testable. UMD.
- Source
vortex.js(69 lines)- Load
- browser:
<script src="vortex.js">definesVortex; node:require('./vortex.js') - Exports
makeVortex- System
makeVortex(config)returns the system'vortex'(domainphysical, scalemicro; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.vortex.*:vortices(array),circulation,absCirc,centroid(array),sampleAt(function) - Tests
vortex-test.js(passes, 5 assertions)
reaction-diffusion.js
Natura REACTION-DIFFUSION: a two-chemical field that self-organises into Turing patterns. Render-free + deterministic (seeded rng, no Date/Math.random). UNIVERSAL pattern-former: a leopard's spots, a pufferfish's maze, coral, fingerprints, travelling waves -- ONE two-species PDE tuned differently, exactly Turing's 1952 idea that markings are not drawn by any plan but EMERGE. A proper Natura SYSTEM (init/step/fields) -- it fits the framework the way weather/vegetation/ecosystem do (a stepped field on a grid). The renderer maps V to colour; this only evolves the chemistry. Captured from the "It Paints Itself" piece so every future piece shares one solver. UMD (node / window.ReactionDiffusion).
- Source
reaction-diffusion.js(128 lines)- Load
- browser:
<script src="reaction-diffusion.js">definesReactionDiffusion; node:require('./reaction-diffusion.js') - Exports
makeReactionDiffusion,PRESETS- System
makeReactionDiffusion(config)returns the system'rd'(domainphysical, scalemicro; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.rd.*:N,V(Float32Array),U(Float32Array),at(function),gradAt(function) - Tests
reaction-diffusion-test.js(passes, 17 assertions)
sync.js
Natura SYNCHRONIZATION (the Kuramoto model): a rhythm no one called. A population of phase oscillators, each with its OWN natural tempo, each nudged toward the phases it can hear -- and as the coupling K crosses a critical threshold the crowd spontaneously LOCKS into one beat (or, with a phase-lag on a ring, splits into a CHIMERA: a synchronized domain and an incoherent one, coexisting). Fireflies flashing as one, a clapping crowd finding a rhythm, metronomes on a shared board, crickets, pacemaker cells. The emergence is the order parameter R climbing from ~0 (noise) to ~1 (one beat) through Kc. Reusable core of the August synchrony pieces (The Beat Nobody Called, Some Keep Time, ...). Deterministic, node-testable. UMD.
- Source
sync.js(85 lines)- Load
- browser:
<script src="sync.js">definesSync; node:require('./sync.js') - Exports
makeSync- System
makeSync(config)returns the system'sync'(domainphysical, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.sync.*:N,phase(Float64Array),naturalFreq(Float64Array),K,R,meanPhase,localR(Float64Array),localRmin,localRmax,lockedFraction - Tests
sync-test.js(passes, 10 assertions); also loaded byscale-probe.js(all pass)
growth.js
Procedural BRANCHING GROWTH: grow a whole form from one seed by a recursive branch rule. Render-free and deterministic (all randomness drawn from a seeded rng, never Math.random). UNIVERSAL -- the same rule grows a tree, a river network, a lung, a lightning bolt, a root, a blood vessel, a coral: one seed, one branch rule, a whole branching form. Single concern: the TOPOLOGY of branching (a graph of segments + tips), NOT how it is drawn or unfurled over time -- a renderer reveals it, a sim may grow on it. The per-FORM character (a spire reaching vertical, a willow drooping, how many children a node throws) is supplied by the caller as strategies (bias + splits), so this stays one generator instead of one-per-tree-shape. Prototyped in "The Seed Dreaming Under Snow". Future members of this module (same branch-graph output): space-colonization (grow toward attractors) and differential-growth (a relaxing filament). UMD (node / window.Growth).
- Source
growth.js(224 lines)- Load
- browser:
<script src="growth.js">definesGrowth; node:require('./growth.js') - Exports
branch,colonize,differentiate,cloud,FORMS,TAU- Tests
growth-test.js(passes, 52 assertions)
Life
Plants, animals, populations and the webs between them.
vegetation.js
Natura VEGETATION (SYSTEMS.md #5, ALGORITHMS.md): plants grow, spread, and die by climate. The REAL "weather changes the world it falls on" -- it reads the weather's rain, holds a decaying SOIL-WATER, and grows BIOMASS logistically toward a carrying capacity set by water + warmth + season, spreading to neighbours and dying back in drought. So the windward slopes go green where the rain falls and the lee stays bare in the rain-shadow -- because the PLANTS respond, not a render hack.
A Natura system spec (init/step/fields/events), deterministic + node-testable. Couples to WEATHER (rain, temp, land) and the CLOCK (season/light). UMD (node test / window.Vegetation).
- Source
vegetation.js(106 lines)- Load
- browser:
<script src="vegetation.js">definesVegetation; node:require('./vegetation.js') - Exports
makeVegetation- System
makeVegetation(config)returns the system'vegetation'(domainlife, scaleecological; hooks: init, step, fields)- Fields
- read as
ctx.fields.vegetation.*:N,biomass(Float32Array),soilWater(Float32Array),greenness(Float32Array),land(Uint8Array),standingDead(Float32Array) - Tests
vegetation-test.js(passes, 9 assertions); also loaded bydaynight-probe.js,ecosystem-test.js,fire-test.js,quickstart-test.js,scale-probe.js(all pass)
biome.js
Natura BIOME DYNAMICS (SYSTEMS.md #8, ALGORITHMS.md): the map of biomes CHANGES with the climate over time -- forests advance, deserts creep, tundra retreats up the mountains as the world warms. Each cell holds a CLIMATE (a long-run running average of the weather's temperature and rainfall, not the day's weather), and the climate-appropriate biome for that cell is found by a Whittaker-style classifier (the Terrain Engine's biome taxonomy -- sea/beach/ice/tundra/taiga/forest/grass/desert/marsh -- adapted to Natura's units). A cell does NOT flip the instant the weather wobbles: it accumulates SUCCESSION pressure toward the climate-favoured biome and only converts once that pressure has held long enough, so a biome front advances or retreats slowly and with hysteresis -- a real ecological succession, not noise.
Reads weather (temp, rain) + an elevation sampler; an optional warmingPerYear forces a climate trend so the biomes visibly shift. Deterministic + node-testable. UMD (node test / window.Biome).
- Source
biome.js(112 lines)- Load
- browser:
<script src="biome.js">definesBiome; node:require('./biome.js') - Exports
makeBiome,classify,BIOMES,COLD- System
makeBiome(config)returns the system'biome'(domainlife, scaleregional; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.biome.*:N,biome(Int8Array),climateTemp(Float32Array),climateMoist(Float32Array),BIOMES(array) - Tests
biome-test.js(passes, 6 assertions)
ecosystem.js
Natura ECOSYSTEM (SYSTEMS.md #7, ALGORITHMS.md): creatures living on the world. Agent-based predator-prey: HERBIVORES graze the vegetation (energy in, biomass out), move toward greener ground and flee predators, breed when fed and die when starved or old; PREDATORS hunt the herbivores, breed when fed, starve when the prey thin out. Out of these local rules the classic LOTKA-VOLTERRA oscillation emerges -- prey rise, predators rise chasing them, prey crash, predators starve, prey recover -- and the food web is drawn on the real vegetated, rained-on world beneath.
A Natura system: agents in State, exposes a GRAZING field (vegetation reads it to lose biomass) + populations + the agents (for viz). Deterministic + node-testable. UMD.
- Source
ecosystem.js(246 lines)- Load
- browser:
<script src="ecosystem.js">definesEcosystem; node:require('./ecosystem.js') - Needs
verbs/flee.js- Exports
makeEcosystem- System
makeEcosystem(config)returns the system'ecosystem'(domainlife, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.ecosystem.*:N,grazing(Float32Array),populations(object),agents(array),chorusR,chorusPhase - Tests
ecosystem-test.js(passes, 12 assertions); also loaded bydaynight-probe.js(all pass)
lifecycle.js
Natura LIFE-CYCLE (SYSTEMS.md #6; the LIFE domain's last unbuilt system). A creature's life as a state machine, and a POPULATION as the turnover of many: birth -> growth -> maturity -> aging -> death -> decay -> nutrients -> (the ground that feeds the next). The ontology's biological continuum made mechanical -- "LIFE is matter passing THROUGH life; death is its tail." Each creature ages on the clock, eats (energy in) against its metabolism (energy out), grows through stages by age, breeds when adult and fed, and dies of starvation, cold, or old age; its carcass decays back into a nutrient field. The emergence is the TURNOVER: individuals die, yet the population persists across generations, holds an age STRUCTURE, and rides its food's carrying capacity -- and the matter that made the dead returns to the soil. Couples to VEGETATION (food) + WEATHER (cold stress); its OUT (creatures + nutrients) feeds a viz, the ecosystem, and the soil. In a minded world each creature carries a MIND that drives its behaviour (BUILD ON). Deterministic + node-testable. UMD.
- Source
lifecycle.js(162 lines)- Load
- browser:
<script src="lifecycle.js">definesLifecycle; node:require('./lifecycle.js') - Exports
makeLifecycle,STAGE- System
makeLifecycle(config)returns the system'lifecycle'(domainlife, scalelocal; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.lifecycle.*:cap,N,nutrients(Float32Array),stage(Uint8Array),age(Float32Array),energy(Float32Array),health(Float32Array),x(Float32Array),y(Float32Array),carcassT(Float32Array),nAlive,nEgg,nJuv,nAdult,nSen,nCarcass,meanAge,births,deaths,dStarve,dCold,dOld,STAGE(object) - Tests
lifecycle-test.js(passes, 9 assertions)
organisms.js
A GENERAL Natura LIFE system: a population of ENTITIES (animals AND phototroph plants alike) that each wear the shared ontology VERBS, driven by the world's LOCAL sun and fields. Render-FREE (touches no canvas).
One system, many biomes: a biome supplies a SPECIES REGISTRY -- data plus a small render-free behave() -- and this system gives every entity the shared lifecycle for free: its activity read from its CHRONOTYPE against the LOCAL sun (sampled from a structure field if present, else the world's clock/celestial), and access to the OTHER species (for forage/flee). Entities are layered STATE BAGS per SCHEMA.md (kind/species/pos/vel/state), not a class tree; a plant is just an entity with a phototroph chronotype and a growth behave. Follows the Natura system interface (init/step/fields) so it composes in a World and couples via ctx.fields. Coordinates are the biome's own [0,1] space (the renderer maps to pixels); the system never assumes a grid. UMD (node / window.Organisms).
- Source
organisms.js(86 lines)- Load
- browser:
<script src="organisms.js">definesOrganisms; node:require('./organisms.js') - Needs
verbs/index.js- Exports
makeOrganisms- System
makeOrganisms(config)returns the system'organisms'(domainlife, scalelocal; hooks: init, step, fields)- Fields
- read as
ctx.fields.organisms.*:entities(array),bySpecies(object),count,of(function) - Tests
organisms-test.js(passes, 13 assertions); also loaded byrainforest-life-test.js(all pass)
rainforest-life.js
The RAINFOREST biome's SPECIES, a render-free registry for the organisms life system.
One concern: WHAT lives in a rainforest and HOW it behaves -- each species declaring its chronotype and a small behave() that uses the shared VERBS (activity is set for it by the system; it adds forage/flee/move). NO render here: state carries only data (a flower's hue is a number, a mould's spread a scalar); the renderer maps species + state to bodies. Deterministic: behaviours draw randomness from the world's seeded rng (api.ctx.rng), never Math.random, so a run reproduces. Reusable by any rainforest piece. UMD (node / window.RainforestLife).
- Source
rainforest-life.js(198 lines)- Load
- browser:
<script src="rainforest-life.js">definesRainforestLife; node:require('./rainforest-life.js') - Exports
SPECIES,morphoBehave,batBehave,snailBehave,hunterBehave,monkeyBehave,catBehave,frogBehave,slothBehave,snakeBehave- Tests
rainforest-life-test.js(passes, 20 assertions)
mutualism.js
Natura MUTUALISM / COEVOLUTION (the cooperative +/+ edge of LIFE<->LIFE, the mirror of the ecosystem's antagonism). Every prior life coupling is a MINUS for someone: predation eats, disease kills, grazing/competition takes. Nowhere did two species HELP each other and both gain. Here a REWARDER guild (plants: they make nectar, a costly gift) and a SERVICE guild (pollinators: they carry pollen, a service the plant cannot do itself) each depend on the other to reproduce -- so their fates are LINKED, they rise and fall together, and neither can be understood alone. The naming is the flower/pollinator instance, but the model is the general reward-for-service mutualism: fig & wasp, coral & its algae (sugar for shelter), acacia & ant (nectar for defense), cleaner fish & client. Four coupled phenomena, each a real emergence proven by RUNNING (mutualism-test.js), never by reasoning: 1. RECIPROCAL COUPLING -- the two populations move TOGETHER (positively), the opposite of predator-prey's out-of-phase chase; remove one and the other declines. 2. THE ALLEE THRESHOLD -- an OBLIGATE pair (neither reproduces without the other) is BISTABLE: a founder pair too small collapses to extinction, above a critical density it climbs to a high mutual equilibrium. Cooperation has to reach a quorum to catch. (mutualism as an Allee effect / a cooperation tipping point.) 3. COEVOLUTION -- each guild's TRAIT (corolla depth / tongue length) climbs a selection gradient toward its partner's, so mismatched traits CONVERGE (Darwin's Madagascar orchid predicting its long-tongued moth), and a community of several plants + pollinators SORTS into matched pairs (pollination syndromes). 4. THE CHEATER & SANCTIONS -- a nectar-robber takes the reward without doing the service. It saves the cost of cooperating, so WITHOUT a check it INVADES and the mutualism collapses (the tragedy of the commons). A plant that WITHHOLDS reward from ineffective visitors (sanctions / partner choice) makes cheating unprofitable and holds cooperation stable. The reason mutualism is an evolutionary puzzle, and one way nature answers it. Small single-concern file, factory makeMutualism(config), deterministic (no Date.now/Math.random), UMD.
- Source
mutualism.js(254 lines)- Load
- browser:
<script src="mutualism.js">definesMutualism; node:require('./mutualism.js') - Exports
makeMutualism- System
makeMutualism(config)returns the system'mutualism'(domainlife, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.mutualism.*:plants(array),pollinators(array),plantPop,pollPop,meanMatch,traitGap,meanCheat,visits - Tests
mutualism-test.js(passes, 19 assertions)
niche.js
Natura NICHE CONSTRUCTION (ONTOLOGY-FOLD-IN #2, "the deepest living-world move left"): life that REMAKES its world and then lives in the changed world -- the inverse of "weather changes the world it falls on." A population of BUILDERS (beavers, corals, worms, termites) writes a PERSISTENT structure into a field (a dam, a reef, a mound), and that structure RAISES the local habitat, which raises the builders' own carrying capacity -- so building lifts the population far above what the bare ground would hold (ecosystem engineering, a positive feedback). And the structure OUTLASTS its builders: kill the population and the dam still holds, the reef still stands, decaying only slowly -- the world keeps the mark of a life long after it is gone (the legacy). Field-based (builder density + built-structure + derived habitat), deterministic, node-testable. Couples out via its `habitat`/`built` fields (other life colonises the engineered ground). UMD.
- Source
niche.js(90 lines)- Load
- browser:
<script src="niche.js">definesNiche; node:require('./niche.js') - Exports
makeNiche- System
makeNiche(config)returns the system'niche'(domainlife, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.niche.*:N,pop(Float32Array),built(Float32Array),habitat(Float32Array),suit(Float32Array),meanPop,meanBuilt - Tests
niche-test.js(passes, 8 assertions); also loaded bycompose-test.js(all pass)
sensing.js
Natura SENSING (ONTOLOGY-FOLD-IN #3, Life > sensing): what a creature can actually DETECT, and its LIMITS. mind.js holds a creature's BELIEF (its model of the world); this is the channel BENEATH belief -- the raw cue reaching a sensor, through a real MEDIUM, with a real range. A prey gives off cues; each travels differently: SCENT drifts DOWNWIND and lingers, so a nose downwind smells prey a nose upwind never will; SOUND radiates far and around things; SIGHT is bright by day and near-blind in the dark or fog; HEAT betrays a warm body but only close. So detection is an INFORMATION GAME, not a fact: the same prey is loud to one sense and silent to another, findable from one quarter and hidden from the next. Couples to WEATHER (wind carries scent, fog/night blind sight) and turns PREDATION's "the predator sees all" into "senses within its means" -- the hunt begins only where a cue crosses the sensor's threshold. Field-based, deterministic, node-testable. UMD.
- Source
sensing.js(131 lines)- Load
- browser:
<script src="sensing.js">definesSensing; node:require('./sensing.js') - Exports
makeSensing- System
makeSensing(config)returns the system'sensing'(domainlife, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.sensing.*:N,scent(Float32Array),sound(Float32Array),sight(Float32Array),heat(Float32Array),detect(Float32Array),light,fog,wind(object),sources(array) - Tests
sensing-test.js(passes, 14 assertions); also loaded bycompose-test.js(all pass)
stigmergy.js
Natura SELF-ORGANIZED TRAILS (ONTOLOGY: the INFORMATION primitive as a deposited-and-decaying spatial FIELD). A foraging highway that emerges with NO central plan: a colony's ants lay a HOME scent as they search and, once laden, a FOOD scent on the way back; searchers climb the FOOD gradient toward food while laden ants climb the HOME gradient back to the nest; unused scent EVAPORATES. Out of thousands of purely-local moves a shortest-ish path self-organizes -- and it FADES when the food runs out. This is the reusable core of the gallery piece "The Crumb Wars" (multi-colony war), folded down to the one-colony mechanism. Every deposited/ decaying field -- scent trails, niche structures, fire scars -- is this same shape. Deterministic, node-testable. UMD.
- Source
stigmergy.js(118 lines)- Load
- browser:
<script src="stigmergy.js">definesStigmergy; node:require('./stigmergy.js') - Exports
makeStigmergy- System
makeStigmergy(config)returns the system'stigmergy'(domainlife, scaleecological; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.stigmergy.*:N,homeTrail(Float32Array),foodTrail(Float32Array),ants(array),collected,foodRemaining,trailStrength,trailMean,atFood,trailConcentration - Tests
stigmergy-test.js(passes, 7 assertions); also loaded byscale-probe.js(all pass)
wintering.js
Natura WINTERING: how a warm-blooded life gets through the lean season. The seasons made more than colour: the same autumn that turns the leaves is, for the animals, a race to lay something by, and the winter is a long ledger drawn down against it. Four ways to keep the ledger, all on ONE physiology:
FAT -- the store is the BODY. Fatten in autumn (hyperphagia), then hibernate on it. Two ways to sleep: SHALLOW (a bear: body only a few degrees cool, metabolism suppressed to a quarter anyway, one long continuous sleep, cubs born and nursed in it) and DEEP (a ground squirrel, a woodchuck, a bat: body down to a degree or two above freezing, or below it, with a full ARousal back to 37 every week or two -- and the arousals, not the cold, are where most of the winter's fat goes). LARDER -- the store is ONE PLACE. A chipmunk fills a pantry in its burrow and eats from it at each arousal; a red squirrel keeps a midden of cones and stays awake all winter on it. SCATTER -- the store is EVERYWHERE. A grey squirrel buries thousands of nuts one by one, finds most again by memory and smell, loses some to thieves, forgets the rest -- and the forgotten ones come up as oaks in spring. The forest is planted by what the squirrels forget. DAILY -- no store that lasts. A chickadee eats all day to put on a tenth of its weight in fat, lets its body cool a regulated ten degrees each night in a tree hole, and burns nearly all of it by dawn.
The physiology (per individual, integrated exactly with an exponential step so tiny birds and big bears are both stable): basal metabolism by Kleiber (70 kcal/day per kg^0.75 for mammals, 129 for passerines); heat lost through the coat as a conductance C = 0.2 M^0.5 W/K, cut by the den/burrow/nest's insulation; torpid metabolism = suppression x BMR x Q10^((Tb-Tnorm)/10); a defended floor (a deep hibernator in a burrow colder than its floor burns fuel to hold the floor); arousal = thermogenesis at several times BMR until warm. Deep torpor ends when a DEBT fills, at a rate that is itself temperature dependent (Q10), so bouts run longest in the coldest midwinter and shorten at both ends of the season -- as real ones do. Heart and breath rates follow metabolism from their allometric resting values.
The place: air temperature (seasonal + diurnal), day length from latitude, SNOW that falls below freezing and melts above it, and the ground: a burrow's temperature lags the surface by weeks, and under deep snow the surface stays near zero whatever the air does -- the snow is the blanket the sleepers under it depend on. The food: seasonal kinds (mast, forage, berries, seeds, cones, insects, salmon) and one master knob, the year's MAST crop, on which a whole northern hardwood community's winter hangs.
Deterministic (seeded rng, clock time as input) + node-testable. UMD. See wintering-test.js.
- Source
wintering.js(500 lines)- Load
- browser:
<script src="wintering.js">definesWintering; node:require('./wintering.js') - Exports
makeWintering,SPECIES,PLACES,FOODS,tFromDoy,doyOf,bmrW,condW,DAY,YEAR- System
makeWintering(config)returns the system'wintering'(domainlife, scalelocal; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.wintering.*:place(object),animals(array),snow,snowPeak,layers(array),anom,storm,stormN,raining(boolean),snowing(boolean),_wseed,tBurrow(object),doy,Ta,dayLen,food(object),evs(array),year - Tests
wintering-test.js(passes, 49 assertions)
Minds and societies
Belief, contagion, markets, knowledge and the built world.
mind.js
Natura MIND (the ontology's MIND rung, previously untouched). The uncanny vein ONTOLOGY.md flagged: "the mind's model diverges from the world." A mind is not a sensor wired to reality; it holds its OWN MODEL (beliefs about nearby threat + food + a warm haven) that it updates only by PERCEIVING, only while it ATTENDS, coloured by EMOTION, and left to DECAY + DREAM while it sleeps. So the model comes apart from the world -- and that gap is NEUTRAL: the same physics is a curse or a grace depending on the emotion that drives it. FEAR conjures a threat that is not there and, past a threshold, TRAPS the mind believing it (a phantom; the disturbing pole). HOPE sustains a belief in a good place after the mind has left it -- it keeps homing to a hearth gone cold (a solace; the warm pole). One divergence, two colorings. The measurable emergence is that DIVERGENCE between what a mind believes and what is true: it grows with inattention + emotion, shrinks with waking attention. The map is not the territory, made to actually run.
A Natura system (init/step/fields/events), deterministic + node-testable. Reads a world TRUTH it can only partially perceive (config.truth(x,y,ctx) -> {threat,food,warmth}; defaults to a roaming threat, patchy food, and a still hearth, so it stands alone, but in a coupled world truth() samples ctx.fields). Couples OUT: fields.mind.intent / fear / hope / arousal drive a behaviour/LIFE system (which verb a creature runs). UMD (node test / window.Mind).
- Source
mind.js(202 lines)- Load
- browser:
<script src="mind.js">definesMind; node:require('./mind.js') - Exports
makeMind,defaultTruth,INTENT- System
makeMind(config)returns the system'mind'(domainmind, scaleindividual; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.mind.*:M,x(Float32Array),y(Float32Array),bThreat(Float32Array),bFood(Float32Array),bWarmth(Float32Array),fear(Float32Array),hope(Float32Array),hunger(Float32Array),content(Float32Array),curiosity(Float32Array),arousal(Float32Array),intent(Uint8Array),fracAsleep,fracAfraid,fracHopeful,fracContent,fracDreaming - Tests
mind-test.js(passes, 22 assertions); also loaded bysociety-test.js(all pass)
society.js
Natura SOCIETY (the ontology's SOCIETY rung, previously untouched; SYSTEMS.md). SOCIETY is emergent OVER many minds: it reads the MIND system beneath it and produces the collective. This first SOCIETY system is the ATMOSPHERE + its CONTAGION. It reads where the minds are and what they feel, and forms a spatial MOOD FIELD -- the fear and hope in the air over a crowd -- which the minds in turn breathe back in (a mind conforms toward the feeling around it). Out of that loop comes the SOCIETY-scale uncanny: a false belief does not just persist in one mind, it SPREADS, and a whole population can come to share a conviction that answers to nothing in the world -- a rumour, a panic, a myth -- held up by everyone confirming everyone else. Consensus without truth. The MIND rung showed the map diverging from the territory; the SOCIETY rung shows a shared map diverging together, which is harder to break because each mind's error is propped by its neighbours'.
Reads ctx.fields.<mind> (positions + fear/hope/beliefs/arousal). EXPOSES fearField/hopeField (the mood a mind reads back via its `conform` coupling) + collective observables (meanFear/meanHope, CONSENSUS, the dominant feeling) + events (panic, rally, schism). Deterministic + node-testable. UMD.
- Source
society.js(180 lines)- Load
- browser:
<script src="society.js">definesSociety; node:require('./society.js') - Exports
makeSociety- System
makeSociety(config)returns the system'society'(domainsociety, scalecollective; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.society.*:N,fearField(Float32Array),hopeField(Float32Array),meanFear,meanHope,meanFearRaw,meanHopeRaw,meanDread,meanGlow,consensus,dominant(string),atmosphere,scar,legacy,temper,influence(null),inflMax,inflHerf - Tests
society-test.js(passes, 20 assertions)
epidemic.js
Natura/EXISTA EPIDEMIC (the SOCIETY domain's involuntary verb: CATCHING). A contagion moving through a population, run as real network epidemiology -- not a well-mixed scalar SIR but a POPULATION on a CONTACT NETWORK, where a pathogen passes only along the edges between people, and a few highly-connected SUPERSPREADERS carry the outbreak far past what the average contact-rate would predict. Each person is SUSCEPTIBLE, then (if a contact infects them) EXPOSED and incubating, then INFECTIOUS, then RECOVERED-and- immune (or DEAD). Out of nothing but that per-contact chance comes the whole shape of a season: the epidemic CURVE that rises, peaks, and breaks; the peak that arrives BEFORE the susceptibles run out (the turning point is herd immunity, and the epidemic OVERSHOOTS it); the HERD-IMMUNITY THRESHOLD past which a vaccinated population never ignites; the way immunising the few superspreaders stops far more than immunising the many at random; and -- with waning immunity -- the drop into recurrent, ENDEMIC waves. This is not mood-contagion (see society.js, where fear spreads); this is a real disease with immunity and mortality, run as physics.
A Natura system (init/step/fields/events), deterministic + node-testable. Randomness only from init's seeded rng (the network + initial seed) and ctx.rng (per-contact transmission, recovery, mortality). UMD.
- Source
epidemic.js(188 lines)- Load
- browser:
<script src="epidemic.js">definesEpidemic; node:require('./epidemic.js') - Exports
makeEpidemic- System
makeEpidemic(config)returns the system'epidemic'(domainsociety, scalepopulation; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.epidemic.*:N,x(Float32Array),y(Float32Array),deg(Int32Array),adj(array),state(Uint8Array),justInfected(array),parent(Int32Array),gen(Int16Array),secondary(Int32Array),nS,nE,nI,nR,nD,susceptible,infectious,everInfected,attackRate,dead,r0,reff,herdThreshold,peakI,peakDay,sAtPeak,meanDegree,maxDegree,day - Tests
epidemic-test.js(passes, 23 assertions)
economy.js
Natura/EXISTA ECONOMY (the SOCIETY domain's material verbs: producing, exchanging, pricing, distributing). A market, run as real general-equilibrium: agents who each make what they are relatively best at given the going prices, spend their earnings on what they want, and a price for every good that RISES where money chases scarcity and FALLS where goods pile up -- with no auctioneer, only the crowd clearing itself. Out of nothing but heterogeneous skill and taste comes the whole of it: prices that track scarcity, SPECIALISATION by comparative advantage, GAINS FROM TRADE over self-sufficiency, and -- from differences too small to see -- a WEALTH distribution that concentrates. Money is conserved to the cent (the clearing is exact), so nothing here is faked. NOT nature: this is the human world, the same emergence machinery pointed at a market instead of a meadow.
A Natura system (init/step/fields/events), deterministic + node-testable. UMD.
- Source
economy.js(167 lines)- Load
- browser:
<script src="economy.js">definesEconomy; node:require('./economy.js') - Exports
makeEconomy- System
makeEconomy(config)returns the system'economy'(domainsociety, scalecollective; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.economy.*:N,G,price(Float64Array),produced(Float64Array),demand(Float64Array),money(Float64Array),gini,meanUtil,totalMoney,output,activity,specialization,tPeriod - Tests
economy-test.js(passes, 14 assertions)
speculation.js
Natura/EXISTA SPECULATION (the SOCIETY domain's FINANCIAL market, the shadow of economy.js). economy.js is the REAL market, where a price finds the level that clears goods against wants -- its wisdom. This is the ASSET market, where a price answers not to what a thing is worth but to what everyone thinks everyone else will pay next -- its madness. One asset of fixed fundamental value V, and a population split between two ways of guessing tomorrow's price: FUNDAMENTALISTS, who believe price reverts to value and so buy it cheap and sell it dear (a stabilising force), and CHARTISTS / trend-followers, who extrapolate the recent move and so buy what is rising and sell what is falling (a destabilising one). Agents SWITCH toward whichever style has been paying lately. Out of nothing but that comes the whole life of a market: endogenous BUBBLES (when the trend pays, agents turn chartist, which makes the trend pay more, until the price has left value far below it) and CRASHES (when the gap is so wide that a stumble makes the fundamentalists right, and everyone switches back at once); FAT-TAILED returns (calm broken by violent days); and VOLATILITY CLUSTERING (storms cluster into storms). No news, no shock, no outside cause -- the boom and the bust are made entirely of the crowd watching itself.
A Natura system (init/step/fields/events), deterministic + node-testable. Randomness only from ctx.rng. UMD.
- Source
speculation.js(100 lines)- Load
- browser:
<script src="speculation.js">definesSpeculation; node:require('./speculation.js') - Exports
makeSpeculation- System
makeSpeculation(config)returns the system'speculation'(domainsociety, scalecollective; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.speculation.*:V,price,ret,chartists,deviation,volatility,peakDev,wealthF,wealthC,t - Tests
speculation-test.js(passes, 9 assertions)
commons.js
Natura THE COMMONS (society / resource): a renewable common-pool resource and the tragedy that takes it, or the governance that saves it. A shared stock (a fishery, a pasture, an aquifer) GROWS logistically but collapses through a depensation floor if drawn too low; harvesters each expand effort while it pays, so under OPEN ACCESS the stock is drawn past the floor and crashes -- the tragedy of the commons, no one's fault and everyone's. Add Ostrom's governance -- a quota, monitoring, and graduated sanctions that build COMPLIANCE and curb effort -- and the same commons settles instead onto a sustained high yield. Distinct from economy.js (price) and speculation.js (bubbles): this is the shared-resource feedback. Deterministic mean-field (no rng). UMD.
- Source
commons.js(74 lines)- Load
- browser:
<script src="commons.js">definesCommons; node:require('./commons.js') - Exports
makeCommons- System
makeCommons(config)returns the system'commons'(domainsociety, scaleregional; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.commons.*:stock,effort,compliance,harvest,yield,collapsed(boolean) - Tests
commons-test.js(passes, 6 assertions)
technology.js
Natura KNOWLEDGE / TECHNOLOGY (the ontology's CULTURE rung seen through what a people can DO, not what they feel). Where SOCIETY spreads a MOOD, this spreads INFORMATION WITH CONTENT: techniques that have prerequisites, serve functions, and RECOMBINE. A technique is not a scalar "tech level"; it is a discrete id sitting in a hidden TECH-TREE, and a population is a set of agents each HOLDING a set of those ids. Knowledge here is a thing that can be invented, taught (imperfectly), bettered, made obsolete, and -- the uncanny pole this rung exists to show -- LOST. A technique known to too few, whose few holders turn over before they pass it on, VANISHES from the world; a people can fall into a dark age and have to re-invent what it once knew. Consensus without truth was SOCIETY's ghost; a DARK AGE is this rung's.
The engine of growth is COMBINATORIAL: a new technique is formed by combining >=2 techniques already known, and the more a population knows the more pairs it can try, so invention ACCELERATES on itself (cumulative culture -- the ratchet). But the same combinatorics needs VARIETY: recombination of a monoculture (everyone knowing the same few things) finds little; a DIVERSE population, its knowledge spread across many corners, invents faster. And a hidden RECIPE map + PREREQUISITE gates give the tree its shape -- some combos unlock a real new tech (gated by lower techs already held), most combine to nothing -- so the growth is structured, not a free-for-all, and higher techs genuinely stand on lower ones.
Five coupled mechanisms, none meaningful alone: (1) INVENTION by recombination against a hidden recipe tree; (2) DIFFUSION with FIDELITY < 1 (a lesson can fail or garble); (3) OBSOLESCENCE -- a better technique for a niche displaces a worse one in USE; (4) LOSS -- turnover + rarity can erase a technique from the whole population; (5) CUMULATIVE prerequisites -- a high tech needs the lower techs it is built on. Deterministic (rng only from init's seed + ctx.rng; time only from dt/clock), node-testable. UMD.
- Source
technology.js(345 lines)- Load
- browser:
<script src="technology.js">definesTechnology; node:require('./technology.js') - Exports
makeTechnology- System
makeTechnology(config)returns the system'technology'(domainculture, scalepopulation; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.technology.*:knownCount,meanHeld,maxTier,diversity,invented,lost,diffusions,inUseUtility,holders(Int32Array),T - Tests
technology-test.js(passes, 25 assertions)
traffic.js
Natura TRAFFIC (society / flow): the microscopic Intelligent Driver Model on a ring. Each driver accelerates toward a desired speed and brakes on the gap + closing-rate to the car ahead -- purely local, no coordination. Below a critical density the road runs free; above it a single brake-tap NUCLEATES a PHANTOM JAM, a stop-and-go wave that travels BACKWARD through forward-moving cars, though no one hit anything and no one stopped for a reason. The fundamental diagram (flow vs density) rises then falls -- the emergence. city.js has only a macroscopic volume-delay curve; this is the missing car-following layer. Deterministic. UMD.
- Source
traffic.js(133 lines)- Load
- browser:
<script src="traffic.js">definesTraffic; node:require('./traffic.js') - Exports
makeTraffic- System
makeTraffic(config)returns the system'traffic'(domainsociety, scalelocal; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.traffic.*:N,positions(Float64Array),speeds(Float64Array),meanSpeed,flow,density,jamCount,minGap,vdCost(Float64Array),vdXmax,capacity,critDensity,jamDensity,freeSpeed - Tests
traffic-test.js(passes, 6 assertions); also loaded bycity-test.js,scale-probe.js(all pass)
city.js
Natura CITY (the SOCIETY ontology's BUILT-WORLD rung; the first HUMAN-WORLD domain the framework has touched -- not a nature system but the artefact a society raises on the land it lives on). A city is EMERGENT: nobody plans the core, yet a monocentric downtown rises out of a flat, uniform plain because every parcel answers the same local question -- "what is this land worth, and what should stand on it?" -- and the answers COUPLE. Value depends on ACCESS; access runs along ROADS whose cost rises as they CONGEST; development follows value; density near you RAISES your value (AGGLOMERATION); a raised core draws population that commutes back along the roads that then congest harder. Out of that loop, with no central hand, comes the shape of a city: a dense downtown, a gradient of density falling with distance, ribbon development crawling out along a new road, and -- once the centre chokes on its own traffic -- SUB-CENTRES budding off it (monocentric -> polycentric). Buildings AGE; a neglected, under-valued district DECAYS and its BLIGHT spreads to its neighbours; and when access and demand lift the land's worth back above what stands on it, the blight is CLEARED and REDEVELOPED denser than before -- the renewal cycle that turns a city over from within. This is the Alonso/von-Thunen bid-rent gradient, Krugman's agglomeration, a gravity traffic assignment, and the filtering/renewal cycle, all as ONE coupled grid.
SELF-CONTAINED: it seeds its own plain, its own founding road + settlement, and its own exogenous regional growth (a slow inflow of households + firms looking for somewhere to land), so it RUNS and TESTS standalone. It reads no peer system, but exposes rich fields() (use / density / landValue / accessibility / blight / congestion / population) that a renderer or a coupled world can read. Deterministic: all randomness comes from init(rng) and ctx.rng; time is dt seconds. UMD (node require / window.City).
- Source
city.js(544 lines)- Load
- browser:
<script src="city.js">definesCity; node:require('./city.js') - Exports
makeCity- System
makeCity(config)returns the system'city'(domaincity, scalebuilt; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.city.*:N,use(Uint8Array),density(Float32Array),landValue(Float32Array),access(Float32Array),accessPop(Float32Array),blight(Float32Array),road(Uint8Array),flow(Float32Array),roadCost(Float32Array),pop(Float32Array),jobs(Float32Array),totalPop,totalJobs,peakDensity,developed,meanBlight,maxCongestion,meanAccess,poolPop,poolJobs - Tests
city-test.js(passes, 24 assertions)
settlements.js
Natura/EXISTA SETTLEMENTS: the human LONG GAME played out on a real watershed. A handful of villages sit on the valley the watershed.js aquifer feeds; each one DRAWS water from the SPATIAL water table (pumping it down, locally), FARMS the soil beside it (depleting a fertility it must fallow to restore), grows or shrinks by the water and food it can win, and passes a CONTAGION to its neighbours along the valley. The point is the tension the title names: a village can draw hard and crop hard for a big harvest NOW, or pace itself within what the land renews and last. Because the aquifer is a SHARED spatial field (watershed diffuses groundwater sideways), one village's greed is felt DOWNSTREAM -- an upstream over-pumper lowers the table under the villages below it, the tragedy of the commons made spatial. Run greedy and the valley booms then CRASHES (the aquifer bottoms out, wells go dry, the crowded and hungry catch the plague); run paced and it endures.
This is the SPATIAL, watershed-grounded cousin of commonwealth.js (which couples the same forces as a non-spatial time series). It COUPLES to watershed.js: writes a `draw` field watershed subtracts from the table, reads back `depthToWater` to know how deep its wells must reach. soil.js is the deep pedogenesis model; the fallow/fertility here is a compact stand-in so the whole valley stays one tractable world. Deterministic (init rng + ctx.rng); dt seconds. UMD (node require / window.Settlements).
- Source
settlements.js(209 lines)- Load
- browser:
<script src="settlements.js">definesSettlements; node:require('./settlements.js') - Exports
makeSettlements- System
makeSettlements(config)returns the system'settlements'(domainsociety, scaleregional; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.settlements.*:N,draw(Float32Array),villages(array),totalPop,meanFert,meanInfected,peakInfected,totalDead,alive,day,floods - Tests
settlements-test.js(passes, 12 assertions)
commonwealth.js
THE GRAND COUPLING. One running World in which the natural world and the human world are wired into a single causal web, so a shock in one place travels downstream through all the others with real LAG. This is the capstone the separate exista windows were always pointing at: not a set of pretty dials, but a universe where climate drives vegetation drives soil drives harvest drives the economy drives population drives disease drives unrest drives a grain-price mania -- each with its own delay, each feeding back.
It is a PURPOSE-BUILT coupled world (the pattern that made The Skin of the World and Lives and Livelihoods work): the real exista agent-systems where they connect naturally (economy.js, epidemic.js, speculation.js), and thin BRIDGE systems (climate, land, harvest, population, mood) where the physical coupling is real but two systems share no variable. A `coupler` system runs first each tick, reads the last tick's fields, and writes the levers (economy.activity, epidemic.distancing, speculation.V) -- including SPARKING a latent plague when crowding x malnutrition push the reproduction number past 1, so epidemics ARISE from conditions rather than being scripted.
Time: one tick = one WEEK (dt = UNITS.WEEK). The agent-systems scale their rates by dt-in-days (epidemic burns over a realistic few-week wave); the bridge systems key off the clock (yearPhase / years) so seasons and slow soil-building stay timescale-correct. Deterministic (seeded rng only). UMD.
- Source
commonwealth.js(272 lines)- Load
- browser:
<script src="commonwealth.js">definesCommonwealth; node:require('./commonwealth.js') - Needs
natura.js,economy.js,epidemic.js,speculation.js- Exports
makeCommonwealth,makeClimate,makeLand,makeHarvest,makePopulation,makeMood,makeCoupler- Factory
makeCommonwealth(config)returns an object with world, dt, step, drought, goodYears, plague, read (not a named system definition)- System
makeClimate(config)returns the system'climate'(domainatmosphere, scaleyear; hooks: init, step, fields)- Fields
- read as
ctx.fields.climate.*:temp,rain,drought - System
makeLand(config)returns the system'land'(domainbiosphere, scaleyear; hooks: init, step, fields)- Fields
- read as
ctx.fields.land.*:biomass,fertility - System
makeHarvest(config)returns the system'harvest'(domainagriculture, scaleyear; hooks: init, step, fields)- Fields
- read as
ctx.fields.harvest.*:yieldRate,foodStock,hunger,know - System
makePopulation(config)returns the system'population'(domaindemography, scaleyear; hooks: init, step, fields)- Fields
- read as
ctx.fields.population.*:pop,births,deaths - System
makeMood(config)returns the system'mood'(domainsociety, scaleyear; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.mood.*:unrest,fear - System
makeCoupler(config)returns the system'coupler'(domaincoupling, scaleyear; hooks: init, step, fields)- Fields
- read as
ctx.fields.coupler.*:workforce,density,transmiss,grainV,sparks,know - Tests
commonwealth-test.js(passes)
Made things
Artifacts that wear out, structures that bear load, mechanisms that move.
artifact.js
Natura ARTIFICE (a domain the framework has never touched, and deliberately NOT nature): the LIFE-CYCLE OF MADE THINGS. Where lifecycle.js models a creature's birth/growth/death, this models the birth/wear/failure/repair/death of MATERIALS and ARTIFACTS -- a chair, a bearing, a blade. It is the engineering-reliability twin of the biological continuum: matter is drawn from a finite raw STOCK, forged with labour into artifacts (each carrying a fixed material QUALITY, and an AGE, CONDITION, and accumulated WEAR/fatigue), put to USE where it wears, fails on a realistic bathtub HAZARD, is MAINTAINED at a cost with diminishing returns until repair no longer beats replacement, and finally SCRAPPED -- its matter recycled back toward raw, losing a fraction to entropy each turn. Five coupled mechanisms, one closed material loop.
The emergences (all proven by RUNNING in artifact-test.js, never by reasoning): (a) failures across a cohort trace the classic BATHTUB curve -- high infant mortality, a low flat middle, a rising wear-out tail; (b) MAINTENANCE lifts mean service life, but with DIMINISHING RETURNS, and there is a repair-vs-replace crossover where a thing is better thrown away than mended; (c) the population settles to a STEADY STATE (working vs broken vs scrap) under fixed produce/wear/recycle rates -- a factory in flow equilibrium; (d) recycling-with-loss makes the usable material stock DECAY over many cycles unless replenished -- the second law written into a supply chain (mass is conserved; usefulness is not).
A standalone system by default (an autarkic little economy), but it COUPLES: it will read a labour/energy supply from another system's fields if wired (ctx.fields[labourName].supply throttles production), and it EXPOSES the whole material ledger + population census + reliability observables for a viz or an economy on top. Deterministic by construction: all randomness comes from the seeded rng (init) and ctx.rng (step); never Date.now / Math.random. Time is dt (seconds). UMD (node test / window.Artifact).
- Source
artifact.js(371 lines)- Load
- browser:
<script src="artifact.js">definesArtifact; node:require('./artifact.js') - Exports
makeArtifact,STATE- System
makeArtifact(config)returns the system'artifact'(domainartifice, scalematerial; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.artifact.*:cap,rawStock,scrapStock,entropyLost,replenished,productMass,yardMass,totalMass,usableMass,nWorking,nBroken,nScrap,nEmpty,built,failed,repaired,retired,fInfant,fMid,fWearout,recycledMass,meanAge,meanCondition,meanWear,meanQuality,state(Uint8Array),age(Float32Array),condition(Float32Array),wear(Float32Array),quality(Float32Array),repairs(Uint16Array),massPerUnit,STATE(object) - Tests
artifact-test.js(passes, 20 assertions)
structure.js
Natura STRUCTURE (artifice / material, EXISTA): load, stability, and failure. artifact.js wears things out statistically; this resolves real FORCE through a structure. Load-bearing members share a weight; each has an Euler buckling limit Pcrit ~ stiffness/L^2; loaded past it a member BOWS (deflection grows as sqrt(P/Pcrit - 1) -- the pitchfork bifurcation of stability), and past a failure margin it gives way and sheds its load onto the rest -- which can push THEM over, cascading to collapse. Bracing (shorter effective L) raises Pcrit and buys capacity. Three September pieces converge here (The Load It Cannot Bear = the buckling bifurcation, As High As It Holds = truss + cascade, Hold Fast = joints). Deterministic mean-field. UMD.
- Source
structure.js(83 lines)- Load
- browser:
<script src="structure.js">definesStructure; node:require('./structure.js') - Exports
makeStructure- System
makeStructure(config)returns the system'structure'(domainartifice, scalelocal; hooks: init, step, fields, events)- Fields
- read as
ctx.fields.structure.*:N,members(array),load,standing,failedFraction,maxDeflect,carried,collapsed(boolean) - Tests
structure-test.js(passes, 9 assertions); also loaded byscale-probe.js(all pass)
mechanism.js
Natura MECHANISM: rigid-body planar kinematics -- linkages (joints + bars + sliders) and GEARS (external, internal-ring, orbiting planets, racks). Render-free + deterministic (no Date/Math.random): a piece's renderer draws it; this only computes how the parts MUST move. Captured from "The Shape of a Motion" so every future piece shares one solver AND the hard-won gear-motion truth (mesh phase, the carrier-frame contact rate, involute tooth geometry, contact-on-the-tooth-surface). The durable facts live in the FRAMEWORK, not one page. UMD (node / window.Mechanism).
- Source
mechanism.js(227 lines)- Load
- browser:
<script src="mechanism.js">definesMechanism; node:require('./mechanism.js') - Exports
makeMechanism,moduleOf,teethForRadius,meshedRatio,meshBase,meshGear,epicyclicCarrierRate,toothContactRate,gearsMesh,baseRadius,involutePoint,involuteRollAt,contactPointOnFlank,addendumRadius,dedendumRadius,toothHalfAngle,backlashLead,followerLag,instantCentre,genevaCross,bevelConeAngles,differentialSplit,differentialOther,trochoidInfo,chainCoupleAngle,PRESSURE_ANGLE,TAU- Factory
makeMechanism(config)returns object, not a system definition- Tests
mechanism-test.js(passes, 51 assertions)
Verbs
Small, render-free behaviours any life system can share (verbs/).
verbs/index.js
The thin ROUTER for the life ontology verbs. It holds NO logic; it just composes the small single-concern verb files (daynight / forage / flee / phenology / school) into one flat `Verbs` surface a life system can reach for. Add a verb = drop a file beside these and add one line here. In the browser, load the verb files first (they each attach to window.NaturaVerbs), then this; in node, it requires them. UMD -> window.Verbs.
- Source
verbs/index.js(16 lines)- Load
- browser:
<script src="verbs/index.js">definesVerbs; node:require('./verbs/index.js') - Needs
verbs/daynight.js,verbs/forage.js,verbs/flee.js,verbs/phenology.js,verbs/school.js,verbs/court.js- Exports
activity,atTod,restAtTod,sunFromDayPhase,sunFromTod,sunFromSinAlt,CHRONOTYPES,forage,flee,grow,stageOf,school,attractiveness,displayCost,choose,breed- Tests
- no test of its own; also loaded by
verbs/school-test.js,verbs/verbs-test.js(all pass)
verbs/daynight.js
ONE life ontology verb, one concern: an organism's day/night ACTIVITY (wake <-> rest) read from the LOCAL sun by its CHRONOTYPE. Pure and RENDER-FREE (no canvas, no DOM) -- a life system calls it.
`sun` in [-1,1] is the local sun elevation (-1 deep dark, 0 twilight, +1 overhead). The CALLER samples it from the world's real sun -- celestial.js `sunAltitude` (its sine is already ~[-1,1]) or the clock's dayPhase -- at the entity's OWN place (its latitude/longitude via a region phase, its canopy/depth via a shade debt). The physics of where the sun is lives UPSTREAM (celestial/clock); this maps local-sun -> activity, and nothing more. It applies to ALL life, not just animals: a phototroph plant is "active" (open, fixing carbon) exactly when the sun is up. (Consolidates the day/night logic that was scattered across art pieces; the small-file sibling of forage/flee.) UMD.
- Source
verbs/daynight.js(51 lines)- Load
- browser:
<script src="verbs/daynight.js">definesNaturaVerbs.daynight; node:require('./verbs/daynight.js') - Exports
activity,atTod,restAtTod,sunFromDayPhase,sunFromTod,sunFromSinAlt,CHRONOTYPES- Tests
- no test of its own; also loaded by
verbs/verbs-test.js(all pass)
verbs/forage.js
ONE life ontology verb, one concern: move toward the best LOCAL source of a resource when you need it. Pure and RENDER-FREE. Universal -- a butterfly seeks nectar, a monkey a fruiting tree, a bat an insect swarm, a snail an algal patch, a grazer fresh grass: the entity supplies WHAT the resource is and HOW it moves; this supplies WHICH source, scored richest-over-nearest (a full source right here beats a fuller one far off). UMD.
- Source
verbs/forage.js(26 lines)- Load
- browser:
<script src="verbs/forage.js">definesNaturaVerbs.forage; node:require('./verbs/forage.js') - Exports
forage- Tests
- no test of its own; also loaded by
verbs/verbs-test.js(all pass)
verbs/flee.js
ONE life ontology verb, one concern: move AWAY from a local threat (the inverse of forage). Pure and RENDER-FREE. Generalized from the CANONICAL herbivore flight in ecosystem.js (a grazer sums an away-vector from predators within a NEAR radius, goes WARY at a wider PERCEIVE radius) -- lifted OUT of that one system so every life system shares it instead of re-implementing it inline (the bad habit these steers are correcting). Universal: a butterfly from a hunting bird, a herd from a wolf, a shoal from a shark. UMD.
- Source
verbs/flee.js(40 lines)- Load
- browser:
<script src="verbs/flee.js">definesNaturaVerbs.flee; node:require('./verbs/flee.js') - Exports
flee- Tests
- no test of its own; also loaded by
verbs/verbs-test.js(all pass)
verbs/school.js
ONE life ontology verb, one concern: move WITH your neighbours (shoaling / flocking / herding). Pure and RENDER-FREE. The third steering verb beside forage (toward a resource) and flee (from a threat): here the pull is toward the GROUP itself. Reynolds' three rules -- SEPARATION (don't crowd a close neighbour), ALIGNMENT (steer the way the group steers), COHESION (drift toward the group's centre) -- which together make a leaderless crowd move as one body. Universal: a shoal of reef fish, a flock of starlings, a herd on the move, a swarm of midges (weight the rules differently and the same verb gives each its character). Proven inline in "As One" (the dense murmuration); lifted OUT here so every life system shares it instead of re-rolling it, exactly as flee was lifted from ecosystem.js. Supports METRIC neighbours (within a radius) OR TOPOLOGICAL (the k nearest by COUNT -- the Cavagna result: a real flock minds a fixed NUMBER of neighbours, not everything within a distance, which is why it stays cohesive however far it stretches). Geometry-agnostic via a delta hook (a wrapped/toroidal world passes its own metric). UMD -> window.NaturaVerbs.school / module.exports.
- Source
verbs/school.js(80 lines)- Load
- browser:
<script src="verbs/school.js">definesNaturaVerbs.school; node:require('./verbs/school.js') - Exports
school- Tests
verbs/school-test.js(passes, 14 assertions)
verbs/phenology.js
ONE life ontology verb, one concern: the LIFE-STAGE GROWTH a living thing moves through over its lifetime. Pure and RENDER-FREE. Universal -- a seed swells to a sprout to a bud to an open bloom, a spat grows to an adult snail, a hypha spreads to a fruiting mould, a green fruit ripens, a nucleus grows to an impinged grain: growth ADVANCES while the thing is fed and lit, SLOWS as it nears full size, and life passes named STAGES at thresholds along the way. Prototyped in the "Under Glass" greenhouse piece (a watered, lit plant grows toward bloom then seeds) and already hand-rolled three times over in the rainforest (a mould's spread, a fruit's ripening, a flower's nectar) -- lifted OUT so every life system shares one growth law instead of re-writing `x += rate*dt` by hand. UMD (node / window.NaturaVerbs.phenology).
- Source
verbs/phenology.js(66 lines)- Load
- browser:
<script src="verbs/phenology.js">definesNaturaVerbs.phenology; node:require('./verbs/phenology.js') - Exports
grow,stageOf- Tests
verbs/phenology-test.js(passes, 41 assertions)
verbs/court.js
ONE life ontology verb, one concern: COURTSHIP + MATE CHOICE, the engine of SEXUAL selection (distinct from natural selection: who SURVIVES vs who is CHOSEN). Pure and RENDER-FREE, the small-file sibling of daynight / forage / flee / phenology. Universal to any sexually-reproducing life: a peacock's train, a bowerbird's bower, a cricket's song, a stickleback's red belly, a firefly's flash-rate -- all a costly DISPLAY assessed by a CHOOSER whose PREFERENCE decides who breeds. The four primitives compose into the whole lifecycle the ontology names (display -> assess -> pair-choice -> reproduction), and -- run over generations with the heredity primitive below -- they produce DIRECTIONAL SEXUAL SELECTION: choosy choosers mate with the showiest displayers, so a costly display ESCALATES generation on generation far past anything survival would favour -- a trait grown because it is CHOSEN, not because it helps -- checked only by the survival COST of the display (the handicap): the peacock's train is as big as survival will bear and no bigger, and it does not grow at all without the choice (all three RUN-verified in court-test.js). The SAME verb, given a MATCHING (recognition) taste instead of an open-ended one, produces the OPPOSITE pole -- STABILISING selection: the display converges to the preferred VALUE and holds there, tracking it if it shifts, never running away (also RUN-verified) -- so the one primitive gives BOTH fundamental kinds of mate choice. The further LANDE-KIRKPATRICK runaway, where the PREFERENCE itself co-escalates with the display through their genetic covariance, is a delicate two-locus regime a dedicated life system can pursue on these primitives -- the covariance does not build from mean-field choice alone, recorded honestly rather than claimed. Nothing in the framework ran mate choice or heredity before this -- court.js is the FIRST, a new primitive. (The Bower is a single-bird real-time courtship INTERACTION, a different scale, not a population model this captures.) UMD (node / window.NaturaVerbs.court).
- Source
verbs/court.js(96 lines)- Load
- browser:
<script src="verbs/court.js">definesNaturaVerbs.court; node:require('./verbs/court.js') - Exports
attractiveness,displayCost,choose,breed- Tests
verbs/court-test.js(passes, 16 assertions)
Laws
Physical laws as plain functions (laws/).
laws/interference-colour.js
The FOUNDING module of the neap.framework LAWS library (2026-08-22).
ONE wave-optics law, MANY physical manifestations: a perceived colour arises when white light is split into two beams with an OPTICAL PATH DIFFERENCE (OPD, in nanometres) that then recombine, so each wavelength interferes constructively or destructively by how the OPD compares to lambda. The reflected intensity of a thin soap film and the transmitted intensity of a birefringent crystal between crossed polars are the SAME function -- I(lambda) = sin^2(pi * OPD / lambda) -- black at OPD 0 (the "black film" / extinction), then the Newton / Michel-Levy colour series as OPD climbs. This is the "processes are as important as the things" idea made concrete: capture the LAW once, and the soap bubble, the oil slick, and the thin-section crystal all read from it.
Consolidates the inline thin-film colour code discovered in The Thinnest Colour, Bubbles / What the Foam Keeps (reflected iridescence) and the Michel-Levy birefringence colour in the petrographic thin-section piece (crossed-polars). Render-free + node-tested (the framework bar). Pure: no Date.now / Math.random.
The colour pipeline is real, not a hue hack: integrate I(lambda) against an illuminant and the CIE 1931 colour-matching functions (the Wyman-Sloan-Shirley 2013 analytic multi-lobe fit) to get CIE XYZ, then the standard XYZ->linear-sRGB matrix + the sRGB transfer curve. UMD (node + browser).
- Source
laws/interference-colour.js(107 lines)- Load
- browser:
<script src="laws/interference-colour.js">definesNaturaLaws.interferenceColour; node:require('./laws/interference-colour.js') - Exports
LAMBDA_MIN,LAMBDA_MAX,STEP,xbar,ybar,zbar,spectrumColour,xyzToSrgb,intensityAt,colourFromOPD,thinFilm,birefringence- Tests
laws/interference-colour-test.js(passes, 17 assertions)
laws/blackbody.js
The colour of HEAT, the second member of the neap.framework LAWS library (2026-08-22).
A hot thing GLOWS, and its colour is set by ONE number: its temperature. Planck's law gives the spectrum a black body radiates at temperature T, and pushed through the eye that spectrum has a colour -- the Planckian locus, sweeping deep RED (a cooling ember, ~1000K) through ORANGE and WHITE (the Sun, ~5800K) into BLUE-WHITE (a hot star, >10000K). This is the sibling of laws/interference-colour: both turn PHYSICS into a PERCEIVED COLOUR, and this one REUSES that module's CIE-1931 colour pipeline (xbar/ybar/zbar + XYZ->sRGB) -- the point of a laws library is that the laws COMPOSE.
Captures the colour-of-temperature helper the pieces keep re-deriving inline (embers/fire, heated iron in The Forge, star colour). Render-free + node-tested (the framework bar). Pure; no Date.now / Math.random. UMD.
- Source
laws/blackbody.js(45 lines)- Load
- browser:
<script src="laws/blackbody.js">definesNaturaLaws.blackbody; node:require('./laws/blackbody.js') - Needs
laws/interference-colour.js- Exports
planck,colourOf,C2- Tests
laws/blackbody-test.js(passes, 11 assertions)
Creatures
Drawing and sounding animals: data, 2D and 3D drawing, behaviour, voice (creatures/).
creatures/creatures.js
Creatures: the FACADE that composes the layers.
The one public entry point. It wires the three concern-modules together and hands a caller a small, stable surface, so a consumer (the First Light meadow piece, or a Natura-world renderer drawing its agents as models) never reaches into species/render/behaviour directly:
Creatures.draw(ctx, name, x, y, dir, phase, scale, pose) -- resolve `name`, dispatch to the right body-plan builder Creatures.SPEC(name) -- the proportion def (either table) Creatures.isBird(name) -- which body plan Creatures.BEH / .GALLOP / .targetOf(c, e) -- behaviour loops + the current-segment picker Creatures.mulberry / .clamp -- the seeded RNG + clamp, for scene use
This is the "composer" in factory-and-composer terms: species.js is the factory data, render.js and behaviour.js are the factories/engines, and this file composes them into a usable whole.
UMD. Browser: load species.js, render.js, behaviour.js FIRST (they attach to window), then this. Node: it requires them relatively (used by the test).
- Source
creatures/creatures.js(44 lines)- Load
- browser:
<script src="creatures/creatures.js">definesCreatures; node:require('./creatures/creatures.js') - Needs
creatures/species.js,creatures/render.js,creatures/behaviour.js- Exports
SPEC,isBird,isSnake,draw,SPECIES,BIRDS,SNAKES,BEH,GALLOP,TROT,targetOf,mulberry,clamp,setLight- Tests
creatures/creatures.test.js(passes, 275 assertions)
creatures/species.js
CreatureSpecies: the DATA layer of the creature factory.
Pure data, no drawing and no behaviour: each entry is a set of proportions, colours and feature flags that the renderer (creatures/render.js) turns into an animal, and the facade (creatures/creatures.js) looks up by name. Adding a creature is adding a row here; the fox, fawn, boar and crow were each one row, not new drawing code -- that is the whole point of the split. Two body plans live in two tables: SPECIES (quadrupeds) and BIRDS (bipeds).
Field glossary (quadruped): L/H body length+height, leg length + thigh fraction, neck length + neckAng rest angle, head/snout size, ear size, tail length + tailAng + optional bushy (brush) width, hump (shoulder rise), gait {stride,lift,duty,speed, hop?}, col [base, mid-shade, dark], belly colour, optional patches[] (soft coat markings), spots (juvenile dapple), fur {n,len,w} (coat density/length/weight), and feature flags canid / horns / mane / tusks / sock / *Tip / nose. Bird fields are documented on the BIRDS table below.
UMD (node test / window.CreatureSpecies). No dependencies.
- Source
creatures/species.js(252 lines)- Load
- browser:
<script src="creatures/species.js">definesCreatureSpecies; node:require('./creatures/species.js') - Exports
SPECIES,BIRDS,SNAKES,get,isBird,isSnake- Tests
- no test of its own; also loaded by
creatures/creatures.test.js(all pass)
creatures/render.js
CreatureRender: the DRAWING layer.
Turns a species def (from creatures/species.js) plus a pose (from creatures/behaviour.js, eased by the caller) into pixels on a 2D canvas context. It knows nothing about WHICH animals exist or HOW they decide to move -- it takes a resolved def and a name (the name only seeds stable per-animal texture) and draws. Two body plans, two builders: drawCreature (quadruped) and drawBird (biped).
Level of detail: `det` (0 far silhouette .. 1 full model), derived from on-screen scale or forced via pose.lod, gates the fine work (form-shading, markings, fur, feathers, catchlight) so a far animal is a cheap flat shape that resolves into fur and an eye as it nears -- the dot->model idea.
The operator's note (2026-08-03): the render itself is not the priority and a better pipeline will come one day; these canvas creatures have their own charm. So this module stays deliberately simple (immediate-mode 2D, no scene graph), and the value lives in the data + behaviour it renders.
UMD (node test / window.CreatureRender). No dependencies; math helpers are internal.
- Source
creatures/render.js(1162 lines)- Load
- browser:
<script src="creatures/render.js">definesCreatureRender; node:require('./creatures/render.js') - Exports
drawCreature,drawBird,drawSnake,birdLeg,setLight,util- Tests
- no test of its own
creatures/behaviour.js
CreatureBehaviour: the DECISION layer.
What an animal DOES over time, kept apart from how it is drawn (creatures/render.js) and from what it is (creatures/species.js). A behaviour is a loop of segments; each segment holds a slice of the loop (f, a fraction) and the posture + movement to hold during it: adv (cross-ground move, 0..1, or >1 for a dash), neck/ear/stand posture, an optional peck (bird strike), and an optional gait override (a bolting deer swaps to the gallop mid-loop). targetOf() picks the current segment for a creature at loop time e; the scene eases the real pose toward it so heads raise and legs plant smoothly. The renderer never sees a behaviour, only the resulting pose -- so the same loop drives the meadow piece or a Natura-world agent identically.
UMD (node test / window.CreatureBehaviour). No dependencies.
- Source
creatures/behaviour.js(67 lines)- Load
- browser:
<script src="creatures/behaviour.js">definesCreatureBehaviour; node:require('./creatures/behaviour.js') - Exports
GALLOP,TROT,BEH,targetOf- Tests
- no test of its own; also loaded by
creatures/creatures.test.js(all pass)
creatures/voice.js
The SOUND concern of the creatures framework (the 4th layer, beside species DATA, render DRAWING, behaviour DECISION). Each creature gets a reusable VOICE: a context-agnostic WebAudio synth so any piece drops in a cricket / tree-frog / owl / heron with its call already built and tuned. Stop re-deriving sounds per piece.
SOUND-DESIGN LAW (from library/shelves/craft/making-sound.md, learned the hard way): band-limited TRANSIENT / TEXTURAL sounds only -- sine / triangle / FILTERED NOISE. NEVER a square/saw (harmonics ring to 20 kHz = "phone ringing"), NEVER a sustained pitched oscillator held as a pad (reads as "eerie music"). Every voice returns its nodes so a scheduler can stop them. Continuous beds (crickets, wind) honour opts.dur; one-shots (a hoot, a croak) are self-timed.
DEVICE-FREE VERIFICATION: every voice runs in an OfflineAudioContext identically to a live one, so voice-check.html renders + FFT-spectrograms them with NO speakers. That IS the decisive check.
Load: <script src="creatures/voice.js"></script> -> window.CreatureVoice (and Creatures.voice if the composer is present). Node/UMD too, for the test/bench.
- Source
creatures/voice.js(502 lines)- Load
- browser:
<script src="creatures/voice.js">definesCreatureVoice; node:require('./creatures/voice.js') - Exports
play,VOICES,SCENES,names,scenes- Tests
- no test of its own
creatures/render3d.js
FIRST-CLASS 3D for the natura creatures framework.
The 2D side (render.js) draws a creature in profile. This draws it as a real, solid, lit 3D FORM you can turn to any angle -- the same creature, consistent across mediums. A creature is assembled from parametric PRIMITIVES (ellipsoid, tube, sheet) into a triangle soup with per-face colour + normal; the renderer rotates by (azimuth, elevation), shades each face by a key/fill/ambient light, painter-sorts by depth, and draws. A pose object (trunkCurl, earFlare, headDown, gait...) deforms the build so behaviour.js can drive it.
Correctness is verified the bkit way: montage() renders the canonical multi-view (front/back/sides/isos/top) so every angle can be checked at once, not just a turntable.
UMD: window.Creatures3D (and Node for tests). No deps.
- Source
creatures/render3d.js(614 lines)- Load
- browser:
<script src="creatures/render3d.js">definesCreatures3D; node:require('./creatures/render3d.js') - Exports
buildElephant,buildTreeFrog,buildBird,buildFish,buildOctopus,buildSkinned,place,render,montage,VIEWS,prims- Tests
- no test of its own
creatures/sdfmesh.js
UNIFY the elephant primitives into ONE watertight mesh.
The parametric build (render3d.js buildElephant) is separate primitives that INTERSECT -- so junctions (leg-body, trunk-face, ear-head) z-fight and never truly connect. This instead defines each primitive as a SIGNED-DISTANCE field, SMOOTH-UNIONs them (so they fuse with a filleted blend at every junction), and polygonizes the isosurface with naive SURFACE NETS into a single connected quad mesh. Shared vertices -> render3d's smooth shading flows seamlessly; one surface -> no interpenetration. Build ~50ms, so build-once and (later) skin, not per-frame.
buildElephantSDF(pose, opt) -> array of render3d faces [{v:[V..], c:[r,g,b]}] (SKIN body only; caller adds tusks/eyes/etc as small prims on top). UMD: window.CreaturesSDF.
- Source
creatures/sdfmesh.js(213 lines)- Load
- browser:
<script src="creatures/sdfmesh.js">definesCreaturesSDF; node:require('./creatures/sdfmesh.js') - Exports
buildElephantSDF,buildElephantUnified,makeField,smin- Factory
makeField(config)returns function, not a system definition- Tests
- no test of its own
creatures/rig.js
SKIN the unified SDF elephant so it ANIMATES without a per-frame rebuild.
buildElephantUnified makes ONE watertight mesh (~100-200ms) -- too slow to rebuild every frame. So build it ONCE (rest pose), classify each vertex into a part (trunk / leg0..3 / ear / head / body), and per frame DEFORM the rest vertices by the pose with linear-blend-ish skinning: every deformation is weighted to ZERO at its attachment (trunk root, hip, neck) so the single connected mesh bends without tearing at the joints. Cheap per frame.
buildElephantRigged(prims, opt{species,detail,N}) -> { faces, setPose(pose) }. UMD: window.CreaturesRig.
- Source
creatures/rig.js(170 lines)- Load
- browser:
<script src="creatures/rig.js">definesCreaturesRig; node:require('./creatures/rig.js') - Needs
creatures/sdfmesh.js- Exports
buildElephantRigged- Tests
- no test of its own
creatures/skinned-gl.js
A sculpted, skinned, TEXTURED creature in real time (2026-09-26: my zebra and giraffe).
The canvas painter (render3d.js) shades a triangle soup, one colour per face: fine for creatures built from primitives, but a coat of crisp stripes or a thin cream net needs its texture. This draws a natura quad3d creature with WebGL: its full runtime skin, its baked coat, skinned on the GPU by its own rig (4 bones a vertex), the joint matrices blended from frames baked off its IK gait (quad3d/export_natura3d.py). Same projection and light as render3d's render() -- orthographic, turned by azimuth and elevation, the key from the upper front left -- so it sits in the bestiary as one of the family. A ground shadow is the same skin, flattened.
const R = SkinnedGL.create(canvas) (a WebGL canvas, usually offscreen) R.draw(D, { clip:'walk', t, az, el, scale, ox, oy, yc, bg:[r,g,b] }) -> draws; the canvas can then be blitted D = window.NATURA3D[name] (base64 typed arrays + frames + the coat as a data URI).
- Source
creatures/skinned-gl.js(116 lines)- Load
- browser:
<script src="creatures/skinned-gl.js">definesSkinnedGL; node:require('./creatures/skinned-gl.js') - Exports
create- Tests
- no test of its own
scene-meadow.js
MorningMeadow: the shared early-morning MEADOW BACKDROP.
The environment behind the creatures, factored out so First Light and the sim-driven Living Meadow (and any future ground-level Natura view) draw the SAME morning world instead of each keeping its own copy. One concern -- the backdrop -- in one place: soft dawn sky, a low sun glow, a lit green ground, a layered hazy treeline (the sun not yet over it), ground mist, depth-graded grass and wildflowers, and a few birds crossing the sky. Deterministic (seeded), so it is stable frame to frame.
MorningMeadow.draw(g, W, Hn, e) paints it; MorningMeadow.horizon(Hn) is the horizon line the caller places creatures against. UMD (window.MorningMeadow / module.exports). Self-contained.
- Source
scene-meadow.js(202 lines)- Load
- browser:
<script src="scene-meadow.js">definesMorningMeadow; node:require('./scene-meadow.js') - Exports
draw,horizon,HORIZON,lightTint,sunAt,palAt- Tests
- no test of its own
Scripts and probes
Run in node: exports of a creature model to a file, and robustness probes.
creatures/export-obj.js
Bridge the JS "bkit" to the Blender .py bkit: build the unified elephant with buildElephantUnified and write a Wavefront OBJ + MTL (grouped by material) that Blender can import for a Cycles/Eevee hero render. node export-obj.js [african|asian] [N] [outPrefix] [pose] pose = a preset name (stand|drink|reach|walk0..walk3) or inline JSON; the RIG deforms the unified mesh so we can export any posed frame (walk cycle, drinking) for a Blender animation sequence.
- Source
creatures/export-obj.js(66 lines)- Run
node creatures/export-obj.js(see the header for its arguments)- Tests
- no test of its own
creatures/export-dae.js
Export the natura elephant as a COLLADA .dae (geometry + normals + one material per colour) for upload into OpenSimulator (which ingests COLLADA). Adapts export-obj.js. Triangulates polygons; groups triangles by colour into materials. node export-dae.js [african|asian] [N] [outFile] [pose]
- Source
creatures/export-dae.js(128 lines)- Run
node creatures/export-dae.js(see the header for its arguments)- Tests
- no test of its own
creatures/export-dae-rigged.js
Export the natura elephant as a RIGGED COLLADA .dae: a real custom anatomical skeleton (pelvis/spine/chest/neck/head, a 5-bone trunk chain, four legs each hip->knee->foot, two ears, a tail = 25 bones) + weighted linear-blend skinning derived from the rig's own per-vertex part/param classification (honest weights, not guessed). Emits COLLADA 1.4.1 with a <skin> controller for upload into OpenSimulator. node export-dae-rigged.js [african|asian] [N] [outFile]
- Source
creatures/export-dae-rigged.js(168 lines)- Run
node creatures/export-dae-rigged.js(see the header for its arguments)- Tests
- no test of its own
creatures/export-meshdata.js
Export the elephant geometry as compact JSON per-material submeshes (local-indexed) for the WorldBridge module to encode into an OpenSim llmesh asset server-side. node export-meshdata.js [african|asian] [N] [outFile]
- Source
creatures/export-meshdata.js(47 lines)- Run
node creatures/export-meshdata.js(see the header for its arguments)- Tests
- no test of its own
daynight-probe.js
Verify the DAY/NIGHT ACTIVITY verb by RUNNING it (the balance-trap lesson: never reason that a behaviour "should" stabilise; run it ON vs OFF, multi-seed, and read the ground truth). Checks (1) it does NOT destabilise the ecosystem (populations stay sane vs OFF), and (2) the rhythm actually manifests -- prey move slower at night (bedded) and kills concentrate in low light (the nocturnal/crepuscular hunt).
- Source
daynight-probe.js(54 lines)- Run
node daynight-probe.js- Tests
daynight-probe.js(passes)
scale-probe.js
Does each system's EMERGENCE survive a change of SCALE (grid size / agent count / dt)? Not a unit test of correctness (the *-test.js files do that) but a robustness sweep: run each system's signature emergence at a SMALL scale and a LARGE scale (and, where dt matters, a fine and coarse dt) and confirm the qualitative bifurcation/threshold holds at BOTH. A system that only emerges at one hand-tuned grid is a fragile toy; a real model is scale-robust. Answers the operator's "sufficient depth AND scales?" by MEASURING it. node scale-probe.js.
- Source
scale-probe.js(133 lines)- Run
node scale-probe.js- Tests
scale-probe.js(passes, 16 assertions)
Bench and demo pages
Pages that exercise a module in a browser. Open them from an unzipped copy of the source (they load the modules beside them with relative <script> tags); here you can read their source.
creatures.htmlthe 2D creature bench (?montage=NAME, ?zoom=NAME) that creatures/ARCHITECTURE.md points tocreatures/pond.htmlcreature demo: render3d.js and voice.js together (a wetland at dusk)creatures/pose-inspect.htmlcreature bench: every species across a set of posescreatures/sdf-bench.htmlcreature bench: the SDF-unified elephant against the primitive buildcreatures/voice-check.htmlcreature bench: the device-free audio bench for voice.jslaws/blackbody-swatch.htmla bench page for a laws modulelaws/interference-colour-swatch.htmla bench page for a laws module