scene: ridge heightfields, slope shading, endless world-x drift #81
Loading…
Reference in a new issue
No description provided.
Delete branch "nibu/ridge-heightfield"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What changed
The ridge scene (behind the existing scene flag,
src/app/features/scene/ridge/) is no longer four solid cards on a periodic strip.ridgeWorld.tsprofile): ridged multifractal value noise (each octave folded at its crest, weighted by the previous octave's signal), domain-warped, plus a soft swell so valleys are not flat. One function; each layer is a parameter row (cells, relief, crag, octaves, warp, gully, mist). Not periodic: noise lattice is hashed per cell, lacunarity 2.07.ridgeBake.ts, pure, no DOM): per column the crest slope gives a normal, lit against the sun (sunDirectionfromsunAzimuth); lit side vs shadow side, a lit crest rim, a light-to-haze gradient down each face (valley mist), erosion streaks (folded noise at gully width, stronger on steep columns). Contrast scales with the existingtransmittance; base colour, haze and edge blur are stilllayerColour/hazeColour/edgeBlur(AERIAL not duplicated).setTimeout, columns per task sized from the last slice's measured time). The compositor slides the track (one Web Animation per chunk,fill: forwards); on finish the chunks move one slot left and the track restarts at 0 in the same task (no jump at ~3-8 px/s), and the canvas that left is baked with the next stretch of world. A second animation sways the whole rig (up to 5% sideways, 3% down, 150 s loop): the slow yaw and pitch. No per-frame script. 2D canvas, no WebGL; reduced-motion pause,stilltier and the cadence guard are kept (flattening draws the baked chunks in view).onBakeoption reports each chunk's cost;harness/scene/ridgeDemo.tsexposes it onwindow.bakes/window.longTasks.fbmPeriodic,valueNoisePeriodic),FBM, the period-tiled soften and scatter. README section updated.Memory: 3 chunk canvases of 1.2 viewport widths per layer (3.6 widths) vs 2 before; about 1.8x layer canvas memory.
Measured (Chromium, SwiftShader on a CPU-only host; 1280x720 DPR 1; 5 runs, median; host load average about 30 on 16 cores, so noisy and pessimistic)
setCPUThrottlingRate4)Budget proposed: first view under ~150 ms desktop (met, no octaves cut: 5/5/5/4) and no background task over 50 ms. The longest background task is under 50 ms in the final run but not reliably: an earlier run of the same code under heavier load showed 109 ms (desktop) and 118 ms (4x). Remaining unsliced steps: the single blur draw (a banded blur cost more in margins than it saved and was reverted) and the deliberately single first-view task. Page long tasks: the first-view task (77-131 ms desktop, 265-330 ms at 4x) plus single-run outliers of 461 and 676 ms I could not attribute (none of my own measured tasks is that long; host contention is the likely cause).
Unmeasured: the Redmi (phone). No real GPU was seen; these are CPU numbers from software rendering and 4x throttle is a proxy. The cadence guard's frame clock was stubbed in the screenshot/measurement driver (SwiftShader frames would trip it); the guard is covered by unit tests.
Verification
npx vitest run: 50 files, 722 tests pass (scene/ridge: 77). Scene-level tests now cover the endless drift (the fake animation can finish): each chunk's pixels are the pure bake of its world columns, rotation repositions and reorders slots and restarts the drift (one chunk of distance), the recycled canvas is rebaked with the next chunk id, three rotations in a row, and every blur reads a per-job scratch canvas of exactly that chunk's padded width. The ridged core has direct tests for the fold, the domain warp, previous-octave weighting, non-integer lacunarity and contrast by distance.Ridge.ts: 4 errors, the same four as ondev(prefer-destructuring,syncPlayStatetwice,report);rotateordering fixed.no-param-reassignis disabled at the top ofRidge.tsandridgeBake.ts. prettier clean.npm run typecheckfails repo-wide on this host (795 errors, matrix-js-sdk types etc.); in the touched files only the existingVitestUtilserror inRidge.test.tsremains.0.9 sin(2 pi * sunAzimuth)(toward +x for azimuth 0 to 0.5, strongest at 0.25); with nosunAzimuththe face lighting falls back to 0.3 and the in-scatter is off.Preview
Built locally (standalone page with numbers and screenshots); to be published at a fixed slug by the sanctioned script once it exists. Void's stable tip-of-dev URL https://minds.gamecult.org/void/rat-dev/ will show the scene once this is merged into dev.
"Either mode" in the brief was taken to mean the CSS-ground/2D ridge scene vs the tiers (full/still); the mesh tier (PR #23) is not touched.
🤖 Generated with Claude Code
Browser check at head
d172c4ed(headless Chromium on a CPU-only host; visual work, so looked at rather than mutation-tested).Known gaps: the ridge shape is a 1D crest profile shaded per column, not a 2D heightfield; the longest background task sits at the 50 ms edge (49 ms desktop, 47 ms at 4x throttle; 109-118 ms once under heavy host load); some unexplained page long tasks (461-676 ms single runs); no real GPU and no Redmi measurement.