fix(#301, #299): the scene is the page, and the chrome floats on glass - #308
Merged
Conversation
The atlas HUD hid under the navbar and the `type` chip -- the colour mode the atlas now defaults to (#304) -- was unreachable. Not a z-index bug: the PAGE SCROLLED. `relative h-screen` below a 65px nav, plus pb-14 and a footer, made the body 871 against a 630 viewport; 100px of scroll put the chip behind the nav. It looked perfect at scroll 0, which is why it read as "renders fine now, randomly glitches later" -- the variable was scroll position, not time -- and why screenshots taken without scrolling always looked fine. The footer was the absurdity at the centre: 297px below the fold, unreachable, serving no one, existing only to generate the scroll that hid the HUD. One root layout renders it for every route, so a 3D atlas inherited a document shape. So the twin routes stop pretending to be documents: - The scene IS the page -- `fixed; inset:0`, rendering BEHIND the chrome. Out of flow, the flex-1 wrapper collapses to free space, the body is exactly the viewport, and THE PAGE CANNOT SCROLL. The HUD cannot hide because there is no scroll to hide it. Measured: scrollHeight 871 -> 630. This also un-clips the globe's bottom (the same bug's other half) and retires the 100dvh question -- `inset:0` computes no length. - The nav floats on glass (base-100/90 + blur), which is the atlas's own answer for its critical panels, applied to the nav. - The footer becomes a compact 44px glass strip pinned over the scene, so it is visible and useful instead of dead below the fold. The diorama comes along, and that closes #299: its Hud was `inset:0`, putting the "Chattanooga Mini" wordmark at y=16, permanently under the nav. Nobody had ever seen the page's own title, and toBeVisible() asserted it WAS visible for months -- it checks CSS, not occlusion. It now lands at y=92. Chrome ownership moves to TwinCanvasHost. It lived in TwinCanvas (the diorama), so when #292 made the atlas the default, /chatt -- the most-shared route -- got NO chrome suppression at all, which is why the PWA popup collided with the target card. A renderer cannot own what the ROUTE needs. Two classes, because the renderers genuinely want different things: twin-fullscreen both: the scene is the page; hides the PWA popup. twin-diorama diorama only: also hides the cookie banner, whose 66px buries a dock sitting at bottom:16. The ATLAS KEEPS ITS BANNER -- /chatt is the link we promote and a first-time visitor must still be able to consent. The banner covers the strip until dismissed; accepted. --nav-h is a CSS var, not a TS constant, because this spans two styling idioms: AtlasViewer uses Tailwind classes and stage/Hud.tsx uses inline style objects, and a var is the only thing both can share. It is calc(4rem + 1px) -- the nav's REAL height; every existing hard-coded site says 64 and is 1px short. Migrating those is out of scope; the debt is commented. Verified against a CI-identical root-path build, 19/19: - the page cannot scroll; scrollTo(0,500) is a no-op - elementFromPoint at the type chip's OWN centre hits the chip, not the nav, AFTER attempting to scroll -- toBeVisible() is CSS-only and would pass with the HUD buried, which is exactly how #299 hid for months - the wordmark probe that PROVED #299 now runs as the fix's assertion - glass contrast: the nav's computed bg composited over #000 and over #fff in a 2D canvas (the canvas does the real OKLCH->sRGB the browser paints with; a regex reads L/C/H as R/G/B and collapses the ratio). Those endpoints bracket every pixel the scene can produce, and blur() moves a backdrop toward its local mean -- strictly inside the bracket. Asserting equal sign at both endpoints makes the minimum provably an endpoint rather than two lucky samples. Plus an honesty guard: alpha < 1 on /chatt and == 1 on /, or an opaque nav would sail through with superb contrast while shipping nothing. Closes #301 Closes #299
This was referenced Jul 17, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #301. Closes #299.
The bug was not z-index — the page scrolled
The
typechip the atlas now defaults to (#304) was unreachable. Measured live on/chatt:elementFromPointat the chip's own centreNAV— "ScriptHammer Home Blog Docs 3D Map"It looks perfect at scroll 0 — which is why it read as "renders fine now, randomly glitches
later" (the variable was scroll position, not time) and why every screenshot taken without
scrolling looked fine.
The footer was the absurdity at the centre: 297px below the fold, unreachable, serving no
one, existing only to generate the scroll that hid the HUD. One root layout renders it for
every route, so a 3D atlas inherited a document shape.
So the twin routes stop pretending to be documents
fixed; inset:0, rendering behind the chrome. Out of flow, theflex-1wrapper collapses to free space, the body is exactly the viewport, and the pagecannot scroll. The HUD cannot hide because there is no scroll to hide it. Measured:
scrollHeight 871 → 630. Also un-clips the globe's bottom — the same bug's other half — andretires the
100dvhquestion, sinceinset:0computes no length.base-100/90+ blur) — the atlas's own answer for its criticalpanels, applied to the nav.
instead of dead below the fold.
#299 closes with it
The diorama's Hud was
inset:0, putting "Chattanooga Mini" at y=16 — permanently under thenav. Nobody had ever seen the page's own title, and
toBeVisible()asserted it wasvisible for months, because it checks CSS and not occlusion. It now lands at y=92 and hit-tests
to itself.
Chrome ownership moves to the route
The
twin-fullscreeneffect lived inTwinCanvas(the diorama), so when #292 made the atlasthe default,
/chatt— the most-shared route — got no chrome suppression at all, which iswhy the PWA popup collided with the target card. A renderer cannot own what the route needs.
Two classes, because the renderers genuinely want different things:
twin-fullscreentwin-dioramabottom:16The atlas keeps its cookie banner (owner's call):
/chattis the link we promote, and afirst-time visitor must still be able to consent. The banner covers the strip until dismissed —
accepted, and it's dismissible.
--nav-his a CSS var, not a TS constantThis spans two styling idioms —
AtlasVieweruses Tailwind classes,stage/Hud.tsxuses inlinestyle objects — and a var is the only thing both can share. It's
calc(4rem + 1px): the nav'sreal height. Every existing hard-coded site says
64and is 1px short; migrating them is outof scope and the debt is commented.
Verification — 19/19 against a CI-identical root-path build
scrollTo(0, 500)is a no-op (structural, cannot flake)elementFromPointat the chip's own centre hits the chip and not the nav, afterattempting to scroll.
toBeVisible()is CSS-only and would pass with the HUD buried — which isexactly how The diorama's 'Chattanooga Mini' wordmark is invisible behind the nav — and toBeVisible() passed on it for months #299 hid for months
contentinfo, carryingFOOTER_LINKS#000and over#fffin a2D canvas (the canvas does the real OKLCH→sRGB the browser paints with; a regex reads L/C/H as
R/G/B and collapses the ratio — this repo has measured a real 4.13:1 mis-read as 1.03:1).
Those endpoints bracket every pixel the scene can produce, and
blur()moves a backdroptoward its local mean — strictly inside the bracket. Asserting equal sign at both endpoints
makes the minimum provably an endpoint rather than two lucky samples. Measured: dark 10.33:1,
light 10.37:1.
Plus an honesty guard — alpha < 1 on
/chattand == 1 on/, or an opaque nav (which hassuperb contrast) would sail through while shipping nothing.
validate-ci.sh --quickgreen includingthe Adding cesium inlines a WASM module as a template literal → vendor chunk fails to parse → client JS dead app-wide #294 chunk-parse check
Screenshots reviewed for both renderers; the diorama's R3F canvas grows 64px and its framing was
checked by eye, not just by a green test.
Follow-ups filed, not fixed: #307 (the HUD's ~302px — PR #297's row split is ~52px of it).