Skip to content

fix(#301, #299): the scene is the page, and the chrome floats on glass - #308

Merged
TortoiseWolfe merged 1 commit into
mainfrom
fix/301-twin-chrome-model
Jul 17, 2026
Merged

fix(#301, #299): the scene is the page, and the chrome floats on glass#308
TortoiseWolfe merged 1 commit into
mainfrom
fix/301-twin-chrome-model

Conversation

@TortoiseWolfe

Copy link
Copy Markdown
Owner

Closes #301. Closes #299.

The bug was not z-index — the page scrolled

The type chip the atlas now defaults to (#304) was unreachable. Measured live on /chatt:

nav 65 + h-screen 630 + pb-14 56 + footer ~120  =  871   vs a 630 viewport
scrollHeight 871   innerHeight 630   canScroll TRUE
scrollY chip top elementFromPoint at the chip's own centre
0 156 the chip itself
100 56 NAV — "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

  • The scene IS the pagefixed; 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. Also un-clips the globe's bottom — the same bug's other half — and
    retires the 100dvh question, since inset:0 computes no length.
  • The nav floats on glass (base-100/90 + blur) — 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: visible and useful
    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 the
nav. Nobody had ever seen the page's own title, and toBeVisible() asserted it was
visible 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-fullscreen effect 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:

class who effect
twin-fullscreen both scene is the page; hides the PWA popup
twin-diorama diorama only also hides the cookie banner, whose ~66px buries a dock at bottom:16

The atlas keeps its cookie banner (owner's call): /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, and it's dismissible.

--nav-h is a CSS var, not a TS constant

This spans two styling idioms — AtlasViewer uses Tailwind classes, stage/Hud.tsx uses inline
style objects — and a var is the only thing both can share. It's calc(4rem + 1px): the nav's
real height. Every existing hard-coded site says 64 and is 1px short; migrating them is out
of scope and the debt is commented.

Verification — 19/19 against a CI-identical root-path build

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).

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants