Repository navigation
Planned Canyon
Planned, not yet implemented. Specified in docs/briefs/views-2026-10.md and tracked in issue #55.
A sunlit desert in isometric relief that changes over minutes and hours, and is saved between runs so that it keeps a record of the machine's history over days. Mesas rise where big processes live, rivers carve gorges where busy processes rain, alluvial fans and deltas spread in the colours of the processes whose rain carried the sediment, lakes fill the pits, and banded strata show in the canyon walls. The terrain is the one stateful view in the plan: it is not a picture of the current sample but an accumulation of everything the machine has done on each plot, and the design has to be honest about what such an accumulation can and cannot tell you. This page is that design, the geology it leans on (stratigraphy, the stream power law, droplet erosion), and a simulation with the specified constants.

docs/mockups/canyon.jpg, from the prototype docs/mockups/code/canyon.py: a 256 x 256 heightfield after a synthetic demo day (6 h 12 m, 995,554 droplets). A visual target, not an isotop render.
Geology reads history from rock. Nicolas Steno (1669) formulated the first laws of stratigraphy: superposition (in an undisturbed sequence the oldest layer is at the bottom), original horizontality (sediments are laid down in horizontal layers) and lateral continuity (a layer extends until it thins or meets a barrier). James Hutton's unconformity at Siccar Point (1788) added that a sequence can be tilted, eroded and buried again, and Charles Lyell's cross-cutting relations that whatever cuts a layer is younger than it. A canyon is stratigraphy exposed by erosion: the walls show the layers, and the river that exposed them is the youngest feature.
The same reading does not carry over to isotop's canyon, and the difference is the most important thing on this page. The terrain stores a heightfield and a top layer of sediment: heights, a base level, per-cell sediment weight and colour, a total quantum count and per-plot carries. It does not store a stack of layers by time. The strata in the walls (colours and bands) are decorative, a function of height with a constant seed, drawn "so the walls read", and not a record of when anything happened. Steno's superposition does not hold in the model.
Think of the canyon as a low-pass filter with memory. Each CPU-second of a process falls as rain on its plot and moves material; each memory-GiB-hour of a process raises its plot; each hour of nothing relaxes everything toward base level. The surface is an integral of that history and, like real landscapes, it forgets: a short burst of rain cuts a small gully that later rain, deposition or relaxation may erase; a plot that has been idle for days relaxes back toward flat. This is the geological Sadler effect (Sadler 1981, Journal of Geology 89), the observation that apparent sediment accumulation rates fall as the time span of the measurement grows because the record is full of gaps at every scale. The terrain preserves long-lived, large signals (a service that runs for weeks and uses gigabytes) and loses short-lived, small ones.
Section 1.1 gives the older history of reading rock. The history of reading this rock begins in the nineteenth century. John Wesley Powell and nine volunteers left Green River Station, in Wyoming Territory, on 24 May 1869 and finished the passage through the Grand Canyon at the mouth of the Virgin River on 30 August 1869. After a small appropriation from Congress he made a second descent in 1871 and 1872, which ended at the mouth of Kanab Creek. His account, Explorations of the Colorado River of the West and Its Tributaries, appeared in 1875, and he revised and enlarged it in 1895 as Canyons of the Colorado.
The geology was worked out next. Clarence Dutton's Tertiary History of the Grand Cañon District (USGS Monograph 2, 1882, with an atlas, issued while Powell directed the Survey) is the source several accounts give for the name Great Unconformity, the surface where flat sedimentary layers sit on tilted older rock in the canyon walls; one source adds that Dutton named it without knowing the age of the rocks on either side, so the name does not measure the gap. Powell's own report contains a drawing of the contact.
The numerical history is shorter. Erosion by channels was modelled as a power law of drainage area and slope from the 1980s (Howard and Kerby 1983; Whipple and Tucker 1999), and by simulated droplets on a heightfield from the mid-2000s (Mei, Decaudin and Hu 2007; Beyer 2015); the view uses the second.
The standard landscape-evolution model is the stream power law (Howard and Kerby 1983; Whipple and Tucker 1999, Journal of Geophysical Research 104): the height
At steady state uplift and incision balance,
Slope falls as a power of drainage area with concavity
The specified view does not integrate the stream power law. It follows hydraulic erosion by droplets (Beyer 2015, a TU Munich bachelor thesis; a particle method in the tradition of Mei, Decaudin and Hu 2007 who simulated erosion with a shallow-water model on the GPU). Each droplet has a position, a direction, a speed, an amount of water and of carried sediment, and each step does the following on the bilinear heightfield:
- Compute the bilinear height gradient
$\nabla h$ at the position; update the direction$d \leftarrow d\cdot\text{inertia} - \nabla h,(1 - \text{inertia})$ and normalise (inertia 0.05: the droplet follows the slope almost exactly). - Step one cell along
$d$ and take the height difference$\Delta h$ . - The carrying capacity is
$c = \max(-\Delta h,\ c_{min})\ v\ w\ \kappa$ with$\kappa = 4$ and$c_{min} = 0.0008$ : a steeper, faster, wetter droplet carries more. - If the droplet carries more than its capacity, or is moving uphill, it deposits:
$\min(\Delta h, s)$ going uphill, else$(s - c)\times0.3$ , spread bilinearly to the four corners of the cell it left. Otherwise it erodes$\min((c - s)\times0.15,\ -\Delta h)$ , taken from the cells under a brush of radius 3. - Update speed
$v \leftarrow \sqrt{v^2 + \Delta h,g}$ with$g = 4$ , water$w \leftarrow 0.99,w$ (evaporation 0.01); a droplet lives at most 70 steps.
These constants are those of the prototype and of the issue. Reading the algorithm as a scaling law (my own argument, not verified numerically): the number of droplets crossing a cell per unit time is proportional to the drainage area
docs/figures/canyon-erosion.py (about 15 s of pure Python): a 96 x 96 field with a Gaussian mesa (a big, quiet process) and a slope, 1500 droplets released around the mesa plot (amber) and 4500 around a second plot (violet). (a) Relief; (b) height change, blue where material was removed and orange where it was deposited; (c) sediment colour, each deposited cell keeping the colour mix of the rain that carried it.
What this port shows, with the caveat that it is a simplified stdlib port and a small grid: the deepest cut is 0.099 against a mesa of relief 0.51 (the mesa's peak drops from 0.611 to 0.587 and its flanks lose up to 16 % of the peak height); eroded material is redeposited in an apron around the plot, in the amber of the rain that carried it, with only a thin violet fringe where the second plot's rain overlaps; and the sediment ledger does not close: 43.0 height-cell units were removed and 28.0 redeposited, so 35 % left the map or was lost with droplets that expired still carrying sediment (this port, unlike the prototype's last-step rule, does not deposit a dying droplet's load). Droplet erosion near an edge is lossy.
The brief says "uplift proportional to memory at each process's plot (Gaussian footprint), with relaxation toward base level over hours". The issue fixes: a Gaussian footprint of
so the equilibrium height is --canyon-rate N (1 to 10000) scales geologic time and erosion per quantum, with the demo's default time lapse of 600 making 8 model hours last 48 s. The footprint widths are 8 cells for a 1 GiB plot, 12 for 4 GiB, 15.3 for 8 GiB (truncated at 24, 36, 46 cells on a 256 grid). The proportionality constant of
Rain is CPU time conserved: one droplet per 10 ms of CPU time per plot, in integer quanta with the remainder carried forward, so the number of droplets released equals the plot's cumulative CPU time divided by the quantum, rounded down, with an error under one quantum per plot. The mockup's status line is consistent with the rule: cpu_time. At most 1500 tracers are simulated per frame; when the backlog is larger a tracer carries a weight
The terrain is one lit relief heightfield (the P3 field primitive) on a 256 x 256 f32 height grid, with a 512 x 512 colour grid so strata bands stay sharp on steep cells; the four side faces are triangle quads, one per strata band per 4-cell edge segment. Shading uses per-cell normals from the height gradient (hill shading; Horn 1981, Proceedings of the IEEE 69), with cast shadows (a 90-step march toward the light) and cavity shading recomputed at most once per second, spread over frames in row slices. Lakes use a priority flood (Barnes, Lehman and Mulla 2014, Computers and Geosciences 62) every 2 s of wall time: water that ends in pits fills each depression to its spill height, minus a constant evaporation per model hour; rivers show recent droplet flow decaying with
| Visual element | Measured quantity (source) | Transform |
|---|---|---|
| Plot (where a process lives) |
(cgroup path, name) of the process |
centre = FNV-1a 64 of cgroup + "\0" + name mapped into cells [16, 240); processes sharing a key share the plot and their memory and rain add up |
| Uplift |
Process.memory at the plot |
Gaussian footprint |
| Rain |
Process.cpu_time deltas |
one droplet per 10 ms of CPU time, integer quanta with carried remainder; at most 1500 tracers per frame, weights above that |
| Sediment colour |
Process.kind of the droplets that carried it |
RGB weight sum of kind_color; erosion removes weight and colour together |
| Lakes | water that ends in pits | priority flood every 2 s, constant evaporation |
| Rivers | recent droplet flow | decays with |
| Labels | the 3 largest plots by memory (<name> mesa at 2 GiB or more, else butte, with memory), the 2 rainiest plots (<name> gorge at the deepest cut within 60 cells, <name> fan at the heaviest sediment) |
label_name |
| Persistent ledger | total quanta, model seconds, per-plot carry and backlog | saved in the file |
| Strata colours, caprock hardness | none | decorative (see section 7 for a caveat) |
| Sky, block sides | none | decorative |
-
Module and state.
src/canyon.rswith pure simulation state in aCanyonstruct in the style ofmedium.rs, which implementsviews::ViewModule; one row at the end ofviews::REGISTRYbuilt withViewInfo::new(name, title, backdrop, build), namecanyon,Backdrop::Dusk, no view-local keys. The rain ledger and uplift are fed from the module'sViewModule::recordhook, whichScene::recordcalls for every row on each sample, so the canyon accrues while any view is shown; the draining of the backlog into droplets happens duringdraw, stepped throughsimulation::FixedStep(60 s demo steps, frame-rate-independent erosion). Every droplet is seeded fromsimulation::Rngby (plot key hash, droplet serial). The grid is 256 x 256. -
Picking. Each owner-grid cell names the largest live process whose footprint dominates there;
positionsare plot tops andboundsthe block corners;notesgive the plot key, member count and CPU-seconds rained this run. Processes are keyed by plot, not by PID, which differs from every other view: a service rains on the same spot across reboots, which is the point of a persistent landscape. (Two plots collide in the same cell with probability about$n^2/(2\cdot224^2)$ , 0.37 expected pairs for 192 plots; overlapping footprints are much more common.) -
Persistence (B11). The file is
canyon-<hash of machine id>.binunder the isotop data directory; payload v1 holds heights, base, sediment weight and colour, total quanta, model seconds and the per-plot carry and backlog. It is saved every 5 minutes (serialised on the frame loop, then written and renamed on a short-lived thread) and synchronously after the main loop exits; the machine key comes from/etc/machine-idon Linux and the host UUID (IOPlatformUUID) on macOS, hashed,defaultorcanyon-unknown.binwhen neither exists. If the version or grid size does not match, a fresh start with a note in the legend. Nothing is written in--demo, in headless runs or under sudo, and if canyon is not in the picker's playlist the file is neither read nor written. Saving on SIGTERM and migrating old versions are out of scope. -
Flags.
--canyon-resetignores the existing file;--canyon-rate N(1..=10000) speeds up geologic time and erosion per quantum (live default 1, demo default 600). -
Demo. Model time
$= 6\text{ h} + N\cdot t$ in fixed 60 s steps; memory frommodel::demo(model_t, count), rain from S4's exact CPU-time integral; constant-seed base terrain; the headless warm-up replays from 0 within a 96k-tracer budget and gives the same result for the same--time. -
Legend.
x600 6 h 12 m | 995,554 droplets = 9,955 CPU-s | uplift = memory at plot | rain = CPU, 1 droplet / 10 ms | sediment = kind of rain | lakes = pits | strata decorative, plus| backlog N,| not saved: <reason>,| machine id unreadableand| N unreadable processes do not rainwhere they apply. -
Dependencies (ROADMAP index): P1, P2, S1, P3, B11, S2, S4. In the current tree: P1, P2, S1, S2, S4 and P3 (
src/render/field.rs) are merged; B11 (persistent view state) is not. -
Platforms. Linux: full. macOS: available; every consumed field (memory footprint,
cpu_time, cgroup key, name, kind) exists and the machine id comes fromIOPlatformUUID; visuals should match the mockup as closely as on Linux. -
No plugin system. Compile-time module and
REGISTRYrow.
- Measured, integrated: the memory of each plot (as uplift, with a time constant of hours), the CPU time spent on each plot (as rain, conserved), the kind of the processes that rained (sediment colour).
- Derived: the shape of the terrain: gorges, fans and lakes are the output of a droplet simulation seeded from plot keys and serial numbers, so their exact shapes are not measurements. Where a gorge runs is the downhill path from the plot, which depends on the terrain, not on the process.
- Decorative: strata, caprock hardness bands, sky and block sides.
- A mesa is a long-lived, large process, not a currently big one: it takes hours of model time to build and hours to decay.
- A gorge means a lot of CPU time was spent, not that it is being spent now. The mockup's "compiler-90 gorge" is the integral of its CPU use over the demo day.
-
Cannot infer: when anything happened (no per-time layers), the exact CPU time of a plot (only droplets released, quantised at 10 ms and aggregated), or comparability across machines (the machine key ties a file to one OS install: a reinstall, a new
/etc/machine-id, starts a new canyon). - Rain is quantised and capped: with weights above 1 a tracer represents many quanta, and the picture is a smoothed average; below one quantum of CPU per plot there is no rain at all.
- Resolution: 256 x 256 cells shared by up to hundreds of plots, each footprint at least 4 cells wide.
Nothing runs in isotop yet. When the view lands:
./target/release/isotop --demo --view canyon --time 12 --width 1600 --output /tmp/canyon.png --renderer cpu
./target/release/isotop --view canyon --canyon-rate 50 # live, saved between runs
./target/release/isotop --view canyon --canyon-reset(Tab and the v picker reach it; the live file is in the isotop data directory.) Meanwhile python3 docs/figures/canyon-erosion.py reproduces the simulation of section 2.2.
Existing: simulation::Rng, simulation::FixedStep and hash (fnv1a_64_bytes) in src/simulation.rs; model::demo and S4's demo_cpu_integral/demo_cpu_seconds in src/model.rs; Process.cpu_time, Process.cgroup, Process.kind in src/model.rs; palette::kind_color; render::label_name; Stage in src/render.rs; ViewModule::record in src/views.rs, called through Scene::record in src/render.rs; the field primitive (Field, Relief, Frame::field) in src/render/field.rs. Planned: src/canyon.rs; B11's Saver thread and versioned files; platform::machine_id() (Linux /etc/machine-id, macOS IOPlatformUUID through the IORegistry FFI) if B11 has no helper; the field primitive's lit relief mode is available. The prototype is docs/mockups/code/canyon.py (numpy, scipy, OpenCV; reference only).
Gaps and disagreements I found: (1) the issue marks strata colours and hardness decorative, but in the prototype hardness multiplies the erosion rate (and caprock a factor 1 - 0.85 cap), so if retained it shapes the terrain deterministically independent of any measurement; either it affects the simulation and should be listed as such, or it does not. (2) The issue says uplift is "proportional to memory" while the prototype uses
- Store a time-indexed layer stack (strata by deposition time) so Steno's superposition holds, and let the canyon walls show real history; the memory cost is a layer count per cell.
- Measure the Sadler effect: the fraction of deposited material that survives as a function of its age, in a long simulated run, and compare with the model's relaxation time.
- Run the droplet model against the stream power law: measure slope-area scaling on a long run and compare the fitted concavity with the 0.45 to 0.5 of real rivers.
- Deposit a dying droplet's remaining sediment (as the prototype does on the last step) and measure how much of the ledger closes.
- Mark a reset for what it is.
--canyon-reset, a version mismatch and a reinstalled machine id each leave a surface with no record of the time between the old terrain and the new one, which stratigraphers call an unconformity; the legend saysnot savedor a fresh start but does not yet say how long the gap was. - Let
--canyon-ratebe a per-plot property (a service's own geological timescale). - Replace the exponential restoring force by a diffusive one (hillslope creep
$D\nabla^2 h$ is already in the stream power model) and see whether relaxed mesas keep their shape.
- N. Steno, De solido intra solidum naturaliter contento dissertationis prodromus (1669); J. Hutton, "Theory of the Earth", Transactions of the Royal Society of Edinburgh 1 (1788); C. Lyell, Principles of Geology (1830-33).
- P. M. Sadler, "Sediment accumulation rates and the completeness of stratigraphic sections", Journal of Geology 89 (1981) 569-584.
- A. D. Howard and G. Kerby, "Channel changes in badlands", Geological Society of America Bulletin 94 (1983) 739-752; K. X. Whipple and G. E. Tucker, "Dynamics of the stream-power river incision model", Journal of Geophysical Research 104 (1999) 17661-17674; J. J. Flint, "Stream gradient as a function of order, magnitude, and discharge", Water Resources Research 10 (1974) 969-973.
- H. T. Beyer, Implementation of a method for hydraulic erosion, bachelor's thesis, Technical University of Munich (2015); X. Mei, P. Decaudin and B.-G. Hu, "Fast hydraulic erosion simulation and visualization on GPU", Pacific Graphics (2007).
- B. K. P. Horn, "Hill shading and the reflectance map", Proceedings of the IEEE 69 (1981) 14-47; R. Barnes, C. Lehman and D. Mulla, "Priority-flood: an optimal depression-filling and watershed-labeling algorithm for digital elevation models", Computers and Geosciences 62 (2014) 117-127.
- Issue #55 and B11 (#38);
docs/briefs/views-2026-10.mdsection 16; docs/VIEW_CONVENTIONS.md. See also Theory-Determinism, Theory-Stable-Layout, Theory-History.
isotop — maximalism for its own sake. Source: tfpickard/isotop. This wiki is published from wiki/ in the repository; edit it there. This footer is decorative.
Philosophy · Gallery · Glossary
Theory
Overview
Sampling: Linux
Sampling: macOS
Background sampler
Model and rates
Life events
History
Journal
Scene and display list
Camera and projection
Rasterization
GPU and parity
Picking
Terminal graphics
Stable layout
Determinism
Simulation toolkit
Colour
Text safety
Mathematics
Fourier epicycles
Wave equation
Flocking
Spatial hashing
Stellar photometry
Lorentz and Schlegel
Reaction-diffusion
Spiking neurons
Schwarzschild
Views
City · Orbit · Ripple
Flow · Cores · Cells
Strata · Globe · Reef
Coop · Matrix
Ptolemy · Tesseract
Necropolis · Cortex
Horizon · Murmuration
Arbor · HR
Hive · Switchboard
Armorial · Lights
Planned
Mold · Chamber
Anthill · Plumbing
Morph · Ouija
Canyon · Die
Guides
Writing a view
Recipes
Headless renders
Contributing to the wiki