The Railway
The story behind The Railway
Inspired by Physarum polycephalum on Wikipedia
Built with Pure WebGL2 · RGBA32F agent-state textures · R16F pheromone FBO ping-pong · Toroidal sense/turn/move pipeline · Paper-grain composite
Techniques 1M GPU agents · Physarum sensor-based locomotion · Additive point-sprite deposit · 3×3 box-blur + decay diffusion · Food-weighted gradient ascent
Direction Your hand is hunger. Place crumbs. Watch a single-celled organism compute the shortest paths between them.
Result A million invisible agents draw a transport network in dark sepia ink on cream paper — a railway designed not by a planner but by reinforcement of whatever worked
The Story
In 2010, researchers at Hokkaido University placed a dish of wet agar on a table and arranged oat flakes on it in the pattern of Tokyo and its 36 surrounding cities. Onto this map they placed a slime mold — Physarum polycephalum, a single-celled organism the color of a yellow highlighter. Physarum has no brain. It has no neurons. It has no plan. Over the next 26 hours, the mold extended exploratory pseudopods out from its starting position, finding the oats, feeding, and in the process thickening the protoplasmic tubes along the paths that worked. By the next morning it had grown a nutrient transport network whose topology closely resembled the actual Tokyo rail system — a subway map designed not by engineers but by hunger and the quiet mathematics of reinforcement.
The trick is that every part of the organism behaves the same way. Each tendril senses the chemical trails deposited by other tendrils, orients toward higher concentrations, deposits more as it flows, and prunes itself back when starved. Thickening succeeds and thickens further. Thinning fails and thins further. There’s no central planner. The network emerges from a million local decisions that cancel out into a global optimum. It is what computer scientists call a distributed algorithm — except here it’s running on protoplasm.
This experience puts you in the role of the researcher placing oats on the plate. The organism does the rest.
The Take
The screen is cream paper, aged and mottled, with a faint fiber grain. At the center, a single dark crumb sits with a thin black halo reaching outward — the starter colony. You move your cursor and click, and a second crumb appears on the paper. Within seconds a faint tendril extends between them, at first exploratory and meandering, then stronger, then a clear black line. Click again — a third crumb — and watch the mold extend two new branches to find it, gradually reinforcing the ones that succeed.
Place a cluster of crumbs in a square. The mold does not connect them along the perimeter; it draws the Steiner tree — the shortest total-length network connecting all points, often a branched topology rather than the obvious path. Place them in a line, and you get a single thick artery with exploratory rootlets at each node. Place them in a random scatter and a beautiful irregular reticulum emerges, its thickest arteries corresponding to the most-trafficked routes.
Right-click (or two-finger tap on mobile) to remove a crumb. The transport network feeding it fades back to exploratory tendrils and eventually to blank paper. Nothing is permanent. The mold is alive under your hand.
The Tech
One million agents, per-pixel state
The simulation runs as a pure WebGL2 pipeline with no scene graph. The agent population is stored in an RGBA32F texture at 1024×1024 (256k agents at 512×512 on mobile). Each texel encodes one agent: vec4(posX, posY, heading, seed) in normalized [0, 1] space. Agents don’t have explicit identities — their position in the texture IS their identity.
Each simulation frame runs four full-screen passes:
1. Sense, turn, deposit — the agent update shader
A fragment shader reads the agent texture at vUv and computes the new state. For each agent, it samples the pheromone field at three positions ahead — forward, forward-left (+30°), forward-right (−30°) — at a distance of 0.010 units. The sensor sample combines pheromone concentration and food (crumb) presence, with food weighted 7× stronger than pheromone:
float sense(vec2 pos, float angle) {
vec2 p = fract(pos + vec2(cos(angle), sin(angle)) * uSenseDist);
return texture(uPher, p).r + texture(uFood, p).r * uFoodWeight;
}
Whichever direction has the highest reading, the agent turns toward by 15° per step. If the forward reading beats both sides, it holds course. If both sides beat forward, it turns one way at random (this is what produces the Y-junctions). Then it moves forward 0.0015 units along its new heading. Positions wrap toroidally so the colony never hits an edge.
2. Pheromone diffusion + decay
The pheromone field lives in a single-channel R16F texture at 55% of device-pixel resolution. A 3×3 box blur spreads each pixel to its neighbors, then a multiplicative decay (0.945 per frame) thins anything that isn’t being actively reinforced. This is what creates the “use it or lose it” dynamic — without continuous agent traffic, paths dissolve back into paper.
3. Deposit pass
The interesting pass. 1M agents are rendered as single-pixel points using gl.drawArrays(gl.POINTS, 0, 1_000_000). Each point’s vertex shader reads the agent’s position from the state texture and places a gl_Position in clip space; the fragment shader outputs (0.006, 0, 0, 0) with additive blending enabled. The result: a thin layer of new pheromone where every agent currently stands.
4. Composite to screen
The final pass reads the pheromone field and the food field and paints them onto a procedural paper background — a value-noise mottle in cream, subtle paper grain from a high-frequency hash, long-wavelength “fiber” streaks, and a soft vignette. Pheromone density is mapped through 1 − exp(−pher · 2.6) to a warm sepia ink; food crumbs are mapped similarly through a stronger curve to near-black.
Crumbs
The food texture holds up to 32 crumbs rendered from a uniform array. When you click, a crumb is pushed onto the list and the food texture is re-rendered from scratch — cheap, because there are few crumbs and the texture is small. Removing a crumb rebuilds the same way.
Why it feels alive
Physarum’s real beauty is the “use it or lose it” decay balance. If decay is too aggressive, the network can’t hold a thought — it jitters and dissolves. If decay is too weak, everything saturates into a solid mat of ink and you lose the distinction between busy arteries and quiet paper. The sweet spot — 0.945 decay with 0.006 deposit and food weight 7× — lets the colony hold stable paths between crumbs while leaving the background breathable. The whole thing tunes by the same three knobs real biologists use: food strength, agent density, and patience.
This blog post was AI generated with Claude Code. Authored by Artificial Noodles.