Ridge backdrop A+D: baked ridge planes over the live sky (Vienna) #163

Merged
void merged 28 commits from nibu/ridge-ad-backdrop into dev 2026-11-14 11:07:59 +00:00
Member

Replaces the noise ridges with baked, haze-as-alpha ridge planes composited over the live sky.

What ships

  • Baker (scripts/ridge-bake): DEM to 6 sun frames x 3 planes, manifest v1, size and decode budgets (night wraps to dawn).
  • Runtime: manifest loader, frame choice by the sun, true crossfade (rig and still), old scene kept until new planes load, plane-fail signal tied to the live scene, one View owns camera and the sun's place.
  • CI gates on the committed set: fetched and decoded size, WebP header dimensions vs manifest, bake id re-derived from plane bytes.
  • Sky menu credit from the manifest.

Bake coverage: Vienna only (b464e375319f, 1.59 MB). Other presets are unbaked and fall back to the sky-only scene. Which places ship is Meta's call.

Known weak / not decided

  • Fuji relief is weak.
  • Stacked planes leak about 22/255 in overlap (stack-leak design fork, unruled).
  • Product calls left open: noon half-switch off the bake date, apparent vs geometric elevation convention, failed rebuild dropping a live ridge, sun disc out of window at 16:9, manifest memo vs rebake across a tab's life.

Verification: Soul verdicts in campaign ratatoskr-backdrop (view.s3, baker.s2, gates.s1, runtime.s1 with fixes). Full vitest 1535 passed, build exit 0, merged with current dev.

Merge: SQUASH only. History carries an 84 KB pyc (bffe988f) that must not land.

Rollback (ruling ridge-ad-rollback): park the branch tag and revert the squash commit.

🤖 Generated with Claude Code

Replaces the noise ridges with baked, haze-as-alpha ridge planes composited over the live sky. **What ships** - Baker (`scripts/ridge-bake`): DEM to 6 sun frames x 3 planes, manifest v1, size and decode budgets (night wraps to dawn). - Runtime: manifest loader, frame choice by the sun, true crossfade (rig and still), old scene kept until new planes load, plane-fail signal tied to the live scene, one View owns camera and the sun's place. - CI gates on the committed set: fetched and decoded size, WebP header dimensions vs manifest, bake id re-derived from plane bytes. - Sky menu credit from the manifest. **Bake coverage: Vienna only** (b464e375319f, 1.59 MB). Other presets are unbaked and fall back to the sky-only scene. Which places ship is Meta's call. **Known weak / not decided** - Fuji relief is weak. - Stacked planes leak about 22/255 in overlap (stack-leak design fork, unruled). - Product calls left open: noon half-switch off the bake date, apparent vs geometric elevation convention, failed rebuild dropping a live ridge, sun disc out of window at 16:9, manifest memo vs rebake across a tab's life. **Verification**: Soul verdicts in campaign ratatoskr-backdrop (view.s3, baker.s2, gates.s1, runtime.s1 with fixes). Full vitest 1535 passed, build exit 0, merged with current dev. **Merge: SQUASH only.** History carries an 84 KB pyc (bffe988f) that must not land. **Rollback** (ruling ridge-ad-rollback): park the branch tag and revert the squash commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
nibu added 28 commits 2026-11-14 11:05:38 +00:00
No content change: tree equals dev's.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Moved from the mockup workspace: ridge.py, sun.py, places.json, tests. core.py is
dropped (ridge.py only imported its save_png, unused; the rest carried hard-coded
paths). places.json is read beside ridge.py; tiles and caches come from RIDGE_TILES
and RIDGE_WORK.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
relight_planes splits the opaque relight into three straight-alpha planes
by the affine-haze trick; the premultiplied colour is made exact over the
reference haze per channel (a scalar alpha alone drifts 34/255 on the far
plane, because the haze share differs per channel).  export.py bakes a
place, writes WebP planes, manifest.json and index.json under a budget.

Tests: the straight-alpha test compared a hazy body with a few solid ink
pixels (fixture, not code); the rebake fixture replaced a plane with one
that had no solid pixel; an everywhere-opaque plane decodes as RGB, now
read back as RGBA.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cuts ridgeWorld, ridgeBake, horizon.ts, viennaHorizon.json, bake-horizon.py and the layer/rig/drift half of Ridge.ts, the
HORIZON_CREDIT line, onBake, and the dead SkyColours fields (ground, sunAzimuth, band). Rollback is the tag
parked/ratatoskr-noise-ridge (ruling ridge-ad-rollback-tag).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
VFOV_DEG, HORIZON_AT, viewFor and VIENNA are gone; vienna.ts is sunAt.ts over a Place.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
createRidgeScene takes a decoded Backdrop and adds one rig (far, mid, near) with transform-only drift; index.ts create() loads manifest, frame choice and planes with the scene chunk; BackgroundSceneConfig.place; vite copies public/ridge. Tests also cover resize debounce, listener removal and the window-size fallback.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Produced by scripts/ridge-bake/export.py vienna from the Copernicus GLO-30 tiles.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The baked planes are haze as alpha, so b laid over a at opacity w doubled the haze mid-blend and popped when the choice collapsed to b alone. crossfade() is the one rule: a at 1 - w plus b at w, summed in an isolated group (plus-lighter in the rig, lighter in an offscreen for the still). Tests pin composite = lerp on alpha planes, BLEND_EDGE, and the noon azimuth split.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
prepare() does every await and returns a synchronous make(); rebuild swaps after the load and a stale or disposed build is never made, so it never speaks. onPlanesFail/onPlanesOk are announced for the scene that won, on change only; a success is silent. Tests cover held decodes, post-dispose and superseded failures, the manifest-view sun, and the fallback sky after a failure.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
scene test: bake the sky once per state and place (dev's memo keyed on state alone; ridgeSkyFor now takes the manifest View)
All checks were successful
Build pull request / Build pull request (pull_request) Successful in 3m56s
963cfe97f6
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
void merged commit 5b7b4c2eeb into dev 2026-11-14 11:07:59 +00:00
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!163
No description provided.