Skip to content

feat(splash): film-title redesign + WebGPU gate + shared Button/PillButton primitives#178

Merged
rulkens merged 18 commits into
mainfrom
worktree-splash-screen-core
May 28, 2026
Merged

feat(splash): film-title redesign + WebGPU gate + shared Button/PillButton primitives#178
rulkens merged 18 commits into
mainfrom
worktree-splash-screen-core

Conversation

@rulkens
Copy link
Copy Markdown
Owner

@rulkens rulkens commented May 20, 2026

Summary

Implements Plan 1 of 2 for the splash screen: a first-paint loading curtain with branded content, two CTAs (Explore + Tour), a top-bar AboutPill reopener, graceful failure handling, and a synchronous WebGPU-unsupported gate that runs before React mounts. Tour is wired to dismiss-as-no-op; the real scripted-tour itinerary lands in Plan 2 behind the same button.

Built per the 2026-05-20 splash-screen grill transcript and the Plan 1 spec (both shipped in #174).

  • useSplash hook owns visibility, readiness gating (engine ready + no fetches in flight + famous-meta loaded), localStorage versioning (skymap.splash.seenVersion), deep-link bypass (#focus= / #poi= / ?tour=), the 8 s "Continue anyway" escape, and dismiss / reopen actions.
  • Splash dialog is purely presentational — translucent backdrop-blurred card centered over a dim overlay, mobile-responsive (stacked CTAs <480 px, solid backdrop on iOS), accessible (role=dialog, focus trap, Esc dismiss, ARIA progressbar), per-error rendering (webgpu-init-failed / catalog-fetch-failed show Reload; famous-meta-failed disables Tour with a tooltip but keeps Explore live).
  • AboutPill sits in the top-bar pill row next to SearchTrigger + AutoRotateToggle, reopens the splash without bumping the seenVersion.
  • Pre-React WebGPU gate in main.tsx — synchronous typeof navigator.gpu check; on unsupported browsers, document.body.innerHTML is swapped to a static "use Chrome or Edge + caniuse link" page and React never mounts.
  • useFamousMeta gains a ready: boolean flag (flips on both success and swallowed-error paths) so the splash gate doesn't deadlock on deployments without famous_meta.json.

The branch is 12 commits split per plan task (Tasks 1–10 + Task 8 fix-up + AboutPill CSS fix). npm run typecheck && npm test && npm run build all green; final review confirmed PR-ready (one out-of-scope follow-up flagged for future polish: an unrelated hasDeepLink .includes||.startsWith redundancy inherited from the plan).

Follow-up: Plan 2 (docs/superpowers/plans/2026-05-20-splash-screen-02-stub-tour.md) wires the Powers-of-Ten stub camera tour to the Tour button. Independent PR; depends only on this one landing.

Test plan

Automated coverage shipped in this branch:

  • tests/unsupportedPage.test.ts — 4 assertions (string shape + WebGPU + Chrome/Edge mention + caniuse link)
  • tests/hooks/useFamousMeta.test.ts — 3 assertions (ready=false initially, flips on success, flips on rejection)
  • tests/utils/url/hasDeepLink.test.ts — 7 assertions (#focus, #poi, ?tour detection; ignores ?debug/?volumes/?anchors)
  • tests/hooks/useSplash.test.ts — 16 assertions (visibility, deep-link skip, version gating, readiness, dismiss/reopen, 8s timer, error mapping)
  • tests/components/Splash/AboutPill.test.ts — 5 assertions (aria-label, click, Enter, hidden aria-hidden behavior)
  • tests/components/Splash/Splash.test.ts — 15 assertions (dialog role, survey links, attribution, CTAs, blocked state, error states, Continue-anyway, focus trap, Esc)
  • Full suite: 1689 / 262 files passing

Manual smoke (please verify in dev server before merging):

  • First visit (localStorage cleared) → splash appears; Explore + Tour disabled initially, enable when load completes
  • Clicking Explore dismisses; refreshing tab does NOT show splash again
  • Direct visit to /#focus=ngc224 does NOT show splash
  • About pill (top-bar) reopens splash; Explore dismisses again
  • Canvas visible through backdrop blur on desktop (cosmos materializes behind during load)
  • Mobile (< 480 px viewport) stacks Explore + Tour vertically; backdrop is solid (no blur)
  • Esc dismisses the splash
  • Tab cycles through survey links → Explore → Tour → loops back
  • Splash version bump (manually set localStorage["skymap.splash.seenVersion"] = "0") → splash re-shows on next visit
  • Tour button currently dismisses like Explore (Plan 2 will replace this — expected for now)

🤖 Generated with Claude Code

rulkens and others added 12 commits May 20, 2026 03:50
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Skips React mount on browsers without navigator.gpu and renders a
static "use Chrome or Edge" page instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Flips true on both success and swallowed-error paths so a missing
famous_meta.json doesn't deadlock downstream gates.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owns visibility, readiness gate, dismiss/reopen, localStorage versioning,
deep-link bypass, and the 8 s Continue-anyway timer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lash

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…test

The previous Splash component edit changed the body to avoid a getByText
ambiguity between the body and the error message. Revert the copy to the
spec's mandated text ("Drawn in your browser with WebGPU. Built from real
cosmic data…") and narrow the WebGPU-init test to match "/webgpu failed/i"
so the assertion fires only on the error box, not the body mention.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Splash dialog covers the first-paint window with branded content and
two CTAs; AboutPill joins the top-bar pill row as the reopener.
Tour currently dismisses like Explore — wiring of the stub tour
lands in the companion plan.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…adius

`backdrop-filter: var(--blur-card)` is invalid — the token holds a bare
length (12px), not a filter function. Wrap with `blur(...)` so the frosted-glass
effect actually renders. Sibling pills (SearchTrigger, AutoRotateToggle) use
the correct `blur(var(--blur-card))` pattern; AboutPill was an outlier.

`--radius-pill` was never defined in global.css; the project defines
--radius-xs through --radius-2xl, but no pill variant. Sibling pill components
use the literal `999px` for the full-pill effect. Match that here so the
AboutPill renders as a circle, not a square with 0px radius.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 20, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
skymap b7d0d05 Commit Preview URL

Branch Preview URL
May 28 2026, 10:56 PM

rulkens and others added 6 commits May 28, 2026 14:50
Cascades to title / body / CTAs / footer via inheritance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…n-core

# Conflicts:
#	src/@types/engine/UseFamousMetaReturn.d.ts
#	src/components/App/App.tsx
#	src/hooks/useFamousMeta.ts
…ic fallback

Synthetic is the "no real data, show *something*" path — at the bulk-survey
defaults (floor 0.02 / falloff 1000 Mpc) the 1000-Mpc cloud attenuated to
a near-black haze, defeating the fallback's reason for existing.  Bump to
Milliquas-style values (floor 0.15 / no depth fade) so the user sees a
visible cosmos in worktrees / dev environments without .bin data.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
NaN positionAngleDeg propagates through the vertex shader's cos/sin and
the fragment's r² ellipse-mask test.  Per IEEE 754, all NaN comparisons
return false, so the `if (r2 > 1.0) { discard; }` silently skips for
every fragment.  The full quad rasterises and the `rgb * alpha = NaN *
NaN = NaN` output renders as a black square.

The shader DOES guard axisRatio against NaN (`select(1.0, ..., absAR >
0.0)`), but the PA path doesn't.  Real catalogs never trip this because
the offline pipeline fills missing PA via `fallbackOrientation`;
synthetic is the only source generated at runtime, and the latent bug
sat undiscovered because synthetic was so dim from the now-fixed
intensity floor that the black squares weren't separately visible.

Fix the symptom at the data source — emit `axisRatio=1.0` and `PA=0`
(matches the original "render as a round point" intent without the NaN
trap).  The shader could also gain a NaN guard for PA; deferring that
until a second source actually needs it.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Splash:
- Drop the centred card. Bottom-left typographic overlay with localised
  vignette; centre stays clear for the Milky Way + "You are here" marker.
- Cormorant Garamond title via Google Fonts (matches the in-scene MSDF
  label face). Staggered fade-up reveal, accent draw-underline beat.
- New SplashProgress at viewport edge replaces the inline card progress
  row. Bytes-based count; indeterminate sweep when totalBytes unknown.
- Click on the backdrop dismisses, matching Esc → onExplore.
- New copy ("Have a look at the neighbours") with catalogue credits in
  the footer rather than the body.

Shared chrome:
- New common/Button primitive. font:inherit so it speaks whatever the
  parent speaks; variants primary/secondary/ghost. SettingsPanel reset
  + SpaceMouse connect adopt it.
- New common/PillButton primitive for the top-bar icon pills. AboutPill
  + AutoRotateToggle refactored to thin semantic wrappers over it, so
  the two pills are now visually identical by construction.
- PlayIcon, PauseIcon, InfoIcon extracted to their own files.

Skill:
- .claude/skills/create-component/ encodes the project's component
  conventions (.root class, default-export form, one-component-per-file,
  no global CSS, default-no-tests).

Test deletions: Splash, AboutPill, AutoRotateToggle tests removed in
favour of behaviour-only coverage; thin presentational wrappers don't
warrant test files per the new skill's guidance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@rulkens rulkens changed the title feat(splash): loading-curtain splash screen + AboutPill reopener + WebGPU gate feat(splash): film-title redesign + WebGPU gate + shared Button/PillButton primitives May 28, 2026
@rulkens rulkens merged commit 2429f5f into main May 28, 2026
1 of 2 checks passed
rulkens added a commit that referenced this pull request May 28, 2026
Plan 01 (loading curtain + AboutPill + useSplash + WebGPU gate)
shipped in PR #178 plus the in-session film-title redesign. Move
its plan file under completed/ and drop the BACKLOG line.

Plan 02 (stub tour) is left in the active queue; Tour CTA currently
dismisses without running.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant