Skip to content

fix(webgl): degrade gracefully when the browser has no WebGL - #282

Merged
sktbrd merged 1 commit into
mainfrom
fix/webgl-fallback
Aug 23, 2026
Merged

fix(webgl): degrade gracefully when the browser has no WebGL#282
sktbrd merged 1 commit into
mainfrom
fix/webgl-fallback

Conversation

@sktbrd

@sktbrd sktbrd commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Users browsing with hardware acceleration disabled got "This page couldn't load" on every route, not just the pages with 3D. MiniTV renders from the root layout, so its three.js canvas mounts everywhere; when getContext("webgl") returns null, new WebGLRenderer() throws and React unwinds the whole tree into Next.js' global error screen.
  • Adds a cached WebGL support probe plus a WebGLGuard that pairs it with an error boundary, and applies it to every WebGL mount point. The fallback is silent — the scene doesn't render, everything around it does.
  • No new user-facing copy, so no i18n changes.

Changes

  • src/lib/webgl.ts — cached probe (webgl2 → webgl → experimental-webgl). Releases the probe context via WEBGL_lose_context so it doesn't consume one of the browser's ~16 slots.
  • src/components/webgl/WebGLGuard.tsx — probe + error boundary. The probe handles the common case before three.js/ogl construct anything; the boundary handles context loss, driver crashes, exhausted context slots, and shaders that won't compile on a given machine.
  • src/components/tv/Gnar3DTVScene.tsx — guarded (covers both MiniTV and the TV hero).
  • src/components/nogglesrails/NogglesRailsGlobe.tsx, src/components/lootbox/AnimatedChest3D.tsx — guarded.
  • src/components/tv/FaultyTerminal.tsx — guarded inside its effect rather than by wrapping, since ogl builds its renderer there and the component's own output is just a container div.
  • src/lib/webgl.test.ts, tests/e2e/webgl-fallback.spec.ts — regression coverage.

Test plan

  • pnpm test — 148 passed (7 new unit cases covering the null-context, throwing-getContext, webgl1-fallback, context-release and caching branches).
  • pnpm exec tsc --noEmit clean; pnpm lint clean apart from one pre-existing warning in BountiesView.tsx; prettier --check passes.
  • Drove a real Chromium with getContext stubbed to return null for all WebGL ids. Before (fix stashed): homepage shows "This page couldn't load" with Error creating WebGL context. After: homepage renders fully with zero page errors, verified at 1440x900 and 390x844. The TV set itself keeps playing — GnarsTVSet is DOM/video, not WebGL.
  • Regression check with WebGL working: 3 canvases mount, no page errors — the guard costs nothing on healthy machines.

Note: Playwright's headless shell has no WebGL at all, so webgl-fallback.spec.ts passes headless for the right reason, but the WebGL-working path only exercises under --headed and was verified separately rather than committed as a headed CI test.

Generated with Claude Code

The MiniTV renders from the root layout, so its three.js canvas mounts on
every route. On a browser with hardware acceleration off (also: sandboxed
contexts, blocklisted drivers, embedded webviews) getContext returns null,
WebGLRenderer throws, and with nothing catching it React unwound the whole
tree into Next.js' "This page couldn't load" screen. A decorative 120px
television was taking the site down for those users.

Adds a cached support probe and a guard component pairing that probe with
an error boundary — the probe catches the common case before three.js/ogl
construct anything, the boundary catches context loss, driver crashes,
exhausted context slots and shaders that won't compile on a given machine.
Applied to all four WebGL mount points. The fallback is silent: the scene
does not render, everything around it does.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated (UTC)
gnars-shadcn Ignored Ignored Aug 21, 2026 12:40am
hackertestdao Ignored Ignored Aug 21, 2026 12:40am

@sktbrd
sktbrd merged commit f7cde44 into main Aug 23, 2026
4 checks passed
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