scene: ridge scene as the default background, no WebGL (replaces #13's default) #21

Closed
nibu wants to merge 0 commits from nibu/ridge-scene into main
Member

Replaces the Voxel Space default (#13) with a scene that does no per-frame march and uses no WebGL. Meta's Redmi readout on #13 was ~100 ms frames with heavy aliasing between layers.

Base: main (14d9fa62, checked just now). #13 is still open against main and is not a base; this branch does not contain it. #13 and this PR both rewrite index.ts/tier.ts (style door) and the startFormat line, so they conflict: merge one. Void's src/sky/sun.js is PR #20, not landed, so sky colours are a placeholder behind one function.

What it is

  • Same createScene contract: createRidgeScene({ canvas, tier, ... }) returns { login, dispose } or null (CSS ground kept). Tier flag still defaults to off. startFormat on Scene becomes optional (the ridge scene has no prepass target).
  • 4 ridge layers generated once on the CPU: a clean-room port of CultMath's cultmath_hash/cultmath_value_noise and fbm (periodic, so the drift loops). Each is painted once to a plain integer-size 2D canvas, two periods wide (1x, or 2x at DPR>=2), over a baked sky gradient on the host canvas. No resampling between layers.
  • Per frame: nothing in script. Each layer slides by a Web Animation of translate3d (150-420 s per period). Paused when hidden; under prefers-reduced-motion painted but never played. tier: 'still' flattens to the host canvas immediately.
  • Cadence guard: after 5 warm-up frames, rAF intervals are sampled for 2 s; p95 > 33 ms flattens to a still image and removes the layers. ?probe=1 shows n / median / p95 and keeps sampling.
  • ridge/skyColour.ts skyColours() is the single replaceable function for sky colour (intended: Void's light()).
  • The ray-march scene stays opt-in via backgroundScene.style: 'raymarch'; its existing tests now pass style: 'raymarch'.

Verified

  • vitest, scene dir: 89 tests pass (26 new: noise wrap, profile periodicity and integer lattice, layer sizes integer, sampler maths, fallback, reduced motion, hidden pause, probe, dispose, door). Six hand mutants of the guard logic; five killed, one survivor (warm-up skip) fixed with a new test that now kills it.
  • Headless Chromium (software, this host, no GPU), 3.5 s: probe reads median 16.7 ms, p95 16.7 ms (the 60 Hz vsync). That says the main thread is idle; it says nothing about a phone.
  • tsc on the new files: only the pre-existing ?raw import errors from running outside Vite.

Not measured (plainly)

  • Anything on the Redmi: frame cadence, p95, whether compositing four layers holds 60 fps, memory (about 4 layers x 6 MB at DPR 2, plus sky), and thermal behaviour over time.
  • Whether the 33 ms guard fires correctly on a real 30 Hz power-saver display (it would read p95 ~33.3 and fall to still).
  • Visual aliasing: sub-pixel translate of canvas layers is resampled by the compositor, which is the same class of artefact Meta saw, though with silhouettes only. Not seen on the phone.
  • Light/dark and the real sky colours (placeholder until #20).
  • Eslint and the repo's tsc (no repo toolchain here); prettier 2.8.1 was run.
  • Plateau-like flat tops on the second and third layers in one screenshot; not investigated.

Preview: https://minds.gamecult.org/nibu/ratatoskr-ridge-b48685b9/ (add ?probe=1; ?tier=still). Merge nothing, deploy nothing.

🤖 Generated with Claude Code

Replaces the Voxel Space default (#13) with a scene that does no per-frame march and uses no WebGL. Meta's Redmi readout on #13 was ~100 ms frames with heavy aliasing between layers. **Base: `main`** (14d9fa62, checked just now). #13 is still open against `main` and is not a base; this branch does not contain it. #13 and this PR both rewrite `index.ts`/`tier.ts` (style door) and the `startFormat` line, so they conflict: merge one. Void's `src/sky/sun.js` is PR #20, not landed, so sky colours are a placeholder behind one function. **What it is** - Same `createScene` contract: `createRidgeScene({ canvas, tier, ... })` returns `{ login, dispose }` or `null` (CSS ground kept). Tier flag still defaults to `off`. `startFormat` on `Scene` becomes optional (the ridge scene has no prepass target). - 4 ridge layers generated **once** on the CPU: a clean-room port of CultMath's `cultmath_hash`/`cultmath_value_noise` and fbm (periodic, so the drift loops). Each is painted once to a plain integer-size 2D canvas, two periods wide (1x, or 2x at DPR>=2), over a baked sky gradient on the host canvas. No resampling between layers. - Per frame: nothing in script. Each layer slides by a Web Animation of `translate3d` (150-420 s per period). Paused when hidden; under `prefers-reduced-motion` painted but never played. `tier: 'still'` flattens to the host canvas immediately. - Cadence guard: after 5 warm-up frames, rAF intervals are sampled for 2 s; p95 > 33 ms flattens to a still image and removes the layers. `?probe=1` shows `n / median / p95` and keeps sampling. - `ridge/skyColour.ts` `skyColours()` is the single replaceable function for sky colour (intended: Void's `light()`). - The ray-march scene stays opt-in via `backgroundScene.style: 'raymarch'`; its existing tests now pass `style: 'raymarch'`. **Verified** - vitest, scene dir: 89 tests pass (26 new: noise wrap, profile periodicity and integer lattice, layer sizes integer, sampler maths, fallback, reduced motion, hidden pause, probe, dispose, door). Six hand mutants of the guard logic; five killed, one survivor (warm-up skip) fixed with a new test that now kills it. - Headless Chromium (software, this host, no GPU), 3.5 s: probe reads median 16.7 ms, p95 16.7 ms (the 60 Hz vsync). That says the main thread is idle; it says nothing about a phone. - tsc on the new files: only the pre-existing `?raw` import errors from running outside Vite. **Not measured (plainly)** - Anything on the Redmi: frame cadence, p95, whether compositing four layers holds 60 fps, memory (about 4 layers x 6 MB at DPR 2, plus sky), and thermal behaviour over time. - Whether the 33 ms guard fires correctly on a real 30 Hz power-saver display (it would read p95 ~33.3 and fall to still). - Visual aliasing: sub-pixel translate of canvas layers is resampled by the compositor, which is the same class of artefact Meta saw, though with silhouettes only. Not seen on the phone. - Light/dark and the real sky colours (placeholder until #20). - Eslint and the repo's `tsc` (no repo toolchain here); prettier 2.8.1 was run. - Plateau-like flat tops on the second and third layers in one screenshot; not investigated. Preview: https://minds.gamecult.org/nibu/ratatoskr-ridge-b48685b9/ (add `?probe=1`; `?tier=still`). Merge nothing, deploy nothing. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
scene: ridge scene as the default background, no WebGL
Some checks failed
CLA Assistant / CLAssistant (pull_request_target) Has been cancelled
Build pull request / Build pull request (pull_request) Has been cancelled
Check PR title / lint (pull_request_target) Has been cancelled
b48685b986
Four ridge layers generated once on the CPU from CultMath value-noise fbm, each painted
once to an integer-size 2D canvas over a baked sky; CSS translate3d drift only. Pauses
hidden / reduced motion; falls back to a still image if rAF p95 > 33 ms over 2 s;
?probe=1 shows median/p95. Same createScene contract, tier flag still defaults off.
Ray-march scene stays behind backgroundScene.style = 'raymarch'.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scene: analytic aerial perspective on the baked ridge layers
Some checks failed
CLA Assistant / CLAssistant (pull_request_target) Has been cancelled
Build pull request / Build pull request (pull_request) Has been cancelled
69d8ff3fa1
Per-layer Beer-Lambert transmittance exp(-k d) mixes each layer toward the haze colour, with
desaturation, 0-2 px edge softening (2D canvas filter, where supported) and an optional faint
warm sun-side in-scatter growing with distance. All at bake time; no per-frame work. Sky colours
still come only from skyColours() (gains optional sunAzimuth).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Member

Closed: superseded by #81, which landed the ridge scene as the default on dev.

Closed: superseded by #81, which landed the ridge scene as the default on dev.
nibu closed this pull request 2026-11-10 22:01:14 +00:00
Some checks failed
CLA Assistant / CLAssistant (pull_request_target) Has been cancelled
Build pull request / Build pull request (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/Ratatoskr!21
No description provided.