Task 6 of 6
The payoff. 96×96, two hundred steps, and the only thing that has changed is
scale — the physics is the four kernels you already wrote, and the loop is the one from
last task, wrapped in a step() helper. (It calls kernels, so it is
async, and every caller has to await it.)
What is new is that you render inside the loop. The console collapses
consecutive render() calls into a frame scrubber, so painting every tenth
step costs one line and buys the whole story: drag the handle under the picture and watch
a plausible-but-lifeless fractal grow a drainage network. Frame 1 is ten steps in — the
water has barely spread and the map is still raw noise. Frame 20 has rivers.
The painter is task 1's hillshade with the water laid over it in blue, so the channels
are visible while they form. And the erosion dial is worth dragging for what it
doesn't do: sixteen times the pick-up rate — 0.05 to
0.8 — moves about half as much rock again (44.6 units of height against
66.8 over the run, deepest cut 0.062 against 0.076), and the drainage pattern is
essentially the same picture. Two reasons, and both are the module: where the
water goes was settled by the routing long before any rock shifted, and a stream that
bites faster also loads up faster and starts settling, so the model throttles itself.
That is the whole of temporal accumulation: a cheap step, run often, producing structure
no single pass could have computed.
STEPS steps, painting and rendering every
EVERYth one, so the console shows a scrubber from bare noise to a river
network.await step() STEPS times — it is async, so the await is not optionalEVERY steps, await paint(height, water) then render(paint.canvas)render() calls consecutive — a console.log between two of them splits the scrubberfor (let i = 1; i <= STEPS; i++) {
await step();
if (i % EVERY === 0) {
await paint(height, water);
render(paint.canvas);
}
}
Twenty frames out of two hundred steps, and no bookkeeping at all.
step() awaits four kernels, so it returns a promise like any
other async function. Call it without await and the loop fires two
hundred overlapping steps at grids that are still being written — the picture will
be nonsense and the console will tell you a promise turned up where a grid should be.
The first frames look like nothing is happening: the water is still spreading out. Around frame 3 thin blue threads appear on the slopes, and from there they thicken, merge, and cut visible notches into the ridges. The two hollows fill up and become lakes.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.