Most marketing sites look alike because they’re assembled from the same parts. A real-time visual, drawn by the visitor’s own graphics chip, is one of the few things a competitor can’t copy by buying your theme. As of October 2026, every major browser engine ships WebGPU, the web’s new graphics standard, on some devices. None ships it on all of them. This guide answers three questions for 2027: who actually gets the fast path, how to build it into an Astro site without slowing the page or shutting anyone out, and what it looks like in production on our own site.

I’m not neutral here: building websites and interactive work is what I sell, and every page of this site runs the system described below.

Why This Is a 2027 Decision

The pieces have shipped. Chrome 113 brought WebGPU to Windows, macOS and ChromeOS in 2023 (Chrome). On September 15, 2025, Safari 26 shipped it on macOS, iOS, iPadOS and visionOS (WebKit). Firefox enabled it on Windows in version 141, on July 22, 2025 (Firefox).

The gaps are just as real. Baseline, the project that tracks when a feature works across the major browsers, still lists WebGPU as “limited availability”: since January 2026, Firefox has been the last browser holding it back (web-features). The specification is a W3C Candidate Recommendation Draft, dated September 15, 2026 (W3C). And Interop 2026, this year’s shared priority list for browser makers, includes cross-document view transitions, scroll-driven animations and the Navigation API, but not WebGPU (web.dev).

So the plan for 2027 is simple. WebGPU is the fast path. WebGL 2, the standard before it, is the floor: Chrome has had it since version 56, Firefox since 51 and Safari since 15 (caniuse). Build for both from day one.

Who Gets WebGPU Today

“Supports WebGPU” depends on the browser, the operating system and the graphics chip. Here’s the picture on October 19, 2026, from release notes, the gpuweb implementation status page (last edited October 2, 2026) and caniuse. Every row can fall back to WebGL 2.

Browser and platform WebGPU on by default Since
Chrome and Edge, desktop (Windows, macOS, ChromeOS) Yes Chrome 113, 2023
Chrome, Android 12 and later Yes, on Qualcomm and ARM graphics; other chips being added Chrome 121, January 2024
Chrome, Linux Intel Gen12 and later; NVIDIA on Wayland Chrome 144, January 2026; Chrome 147
Chrome and Edge, Windows on ARM No, behind a flag
Safari, macOS 26 Tahoe or later Yes Safari 26, September 2025
Safari, older macOS No
Safari, iOS and iPadOS 26 or later Yes Safari 26, September 2025
Firefox, Windows Yes Firefox 141, July 2025
Firefox, Apple Silicon Macs Yes Firefox 145 on Tahoe; Firefox 147 on all supported macOS versions, January 2026
Firefox, Linux No, Nightly builds only
Firefox, Android No, behind a flag

Two rows catch people out. Safari turns WebGPU on by default only on macOS 26 Tahoe or later, according to caniuse, so a Mac that hasn’t upgraded gets your fallback. And Firefox 158, released October 13, 2026, still doesn’t enable it on Linux or Android (MDN). The gpuweb page says Mozilla expects to ship on Linux in 2026. That’s a plan, not something to build on.

three.js in Late 2026: One Codebase, Two Backends

three.js is the JavaScript 3D library this guide is about. Its docs call WebGPURenderer “the new alternative of WebGLRenderer.” It tries WebGPU first and falls back to WebGL 2 when the browser doesn’t support WebGPU (three.js). In the r186 source, the switch happens when WebGPU fails to start, for example when no graphics adapter is available (source).

You write shaders, the small programs that run on the graphics chip, once, in TSL: “a Node-based shader abstraction, written in JavaScript” that outputs code for either backend (TSL). That includes compute passes, general-purpose work done on the graphics chip. On the WebGL 2 fallback, three.js emulates compute with an older technique called transform feedback, with limits (source). It also requests WebGPU’s compatibility level by default (source), the restricted subset Chrome 146 began supporting on older Android hardware (Chrome).

The caveat is maturity. On October 29, 2025, three.js maintainer Don McCurdy wrote that “WebGPURenderer is currently experimental, including the WebGL fallback/forcing feature” (three.js forum). The docs no longer carry that label, but the renderer still changes from release to release. r186, published on September 8, 2026 (npm), removed PCFSoftShadowMap from WebGPURenderer, one of several changes in the migration guide.

My advice: build on WebGPURenderer, pin the exact version, and read the migration guide before every upgrade.

Pick the Lightest Tool That Does the Job

three.js earns its place when a visual has to respond, simulate or carry over from page to page. Most requests to make a site “feel alive” don’t need it.

  • CSS and view transitions. Cross-document view transitions animate between pages with a few lines of CSS. Chrome 126 and Safari 18.2 support them; Firefox doesn’t (caniuse).
  • Lottie. The dotLottie web player renders vector animation through Canvas, WebGL 2 or an experimental WebGPU backend, and can run in a Web Worker, off the main thread (dotlottie-web).
  • Rive. Interactive vector animation with MIT-licensed runtimes (npm). On October 19, 2026, its pricing page said free-plan exports play a Rive splash screen (Rive).
  • Spline. A no-code 3D design tool. The same day, its pricing page showed free web exports with a watermark and self-hosted export on Enterprise only (Spline).
  • Unicorn Studio. No-code WebGL effects. Its SDK keeps at most 14 live WebGL contexts on desktop and 8 on Android, and its license limits it to Unicorn Studio projects (Unicorn Studio).
  • GSAP. The animation library Webflow acquired on October 15, 2024 (GSAP). Since April 29, 2025, it has been free, plugins included, even for commercial use (GSAP). Free isn’t open source: Webflow’s license bars its use in no-code visual animation builders that compete with Webflow, without written consent, and Webflow can update the terms (license).

If the job is a page transition or a looping illustration, stop here. If it’s a brand system that responds to scroll and navigation, read on.

Putting three.js Into Astro

Astro sends finished HTML and ships no JavaScript unless you add a script or opt a component in; it calls those components islands (Astro). For three.js you have two routes.

A plain script. A <script> in an .astro component is bundled as a module and included once per page (Astro). Load the heavy engine with a dynamic import() only when the page needs it. No framework, no hydration, and you own the render loop. For site-wide or decorative visuals, I think this is the right default. It’s what we use.

A framework island. If the 3D piece is a real component, like a product configurator, and your team already works in React, Svelte or Vue, use an island with client:visible, which loads it when it scrolls into view, or client:idle, which waits until the page has loaded (Astro). React Three Fiber 9.8.2 accepts an async renderer factory, so it can run WebGPURenderer (R3F). Its version 10, with a dedicated WebGPU entry point, was still in alpha on October 17, 2026 (npm). Threlte, for Svelte, ships a @threlte/core/webgpu entry for TSL (Threlte). On Vue with TresJS, confirm the WebGPU path before you commit.

For polish between pages, prefer native cross-document view transitions. Astro’s docs note that its <ClientRouter /> turns a site into a single-page app, with drawbacks like reinitializing scripts and state after each navigation (Astro).

Protect Core Web Vitals

Google’s Core Web Vitals measure loading, responsiveness and visual stability. A visual can hurt all three.

  • Loading. Largest Contentful Paint (LCP) should be 2.5 seconds or less. It considers images, video, background images and blocks of text; <canvas> isn’t on the list (web.dev). Your visual can’t be the LCP element, but its download can compete with the one that is. Keep a real image or headline first, and load the engine after it.
  • Responsiveness. Interaction to Next Paint (INP) should be 200 milliseconds or less, and long tasks on the main thread are a common cause of delay (web.dev). Don’t move thousands of particles in JavaScript every frame. Put that work on the graphics chip.
  • Stability. Cumulative Layout Shift (CLS) should be 0.1 or less (web.dev). A fixed-position canvas behind the content never moves the layout.

Motion Is the Accessibility Risk, Not 3D

WCAG 2.2 Success Criterion 2.2.2, Pause, Stop, Hide, is Level A. It applies to moving content that starts automatically, lasts more than five seconds and is presented alongside other content (W3C). W3C’s explanation counts motion that starts when you scroll it into view as starting automatically, and it makes no exception for decoration.

If your visual is covered, you have two compliant options:

  • Stop within five seconds. Let the motion settle into a still frame.
  • Offer a control. Give people a way to pause, stop or hide it. W3C recommends one control for all the moving content on a page.

The exception is motion that is essential to the activity. A brand flourish rarely is.

Honoring prefers-reduced-motion, the device setting that asks for less motion, is good practice, and every browser has supported it since January 2020 (MDN). Do it everywhere. But it isn’t one of the techniques W3C lists for 2.2.2. W3C lists it, as technique C39 (W3C), under 2.3.3 Animation from Interactions, a Level AAA criterion that names parallax scrolling as often non-essential (W3C).

Two basics complete the picture: hide the canvas from screen readers with aria-hidden, and never let a visual delay or cover the copy.

What We Run on Our Own Site

This site runs one particle field across every page, built on three.js r186 and Astro 7. Sections opt in with an attribute that names a shape, and the particles re-form as you scroll from one to the next. Here’s how it behaves.

It picks a tier for each device.

  • A one-line script in the page head turns the field on only if the browser exposes WebGPU or WebGL 2. Without JavaScript, or without either, the field never starts and sections keep their ordinary CSS backgrounds.
  • A probe first opens a throwaway WebGL 2 context with failIfMajorPerformanceCaveat, which fails when there’s no hardware graphics chip (MDN). If it fails, the field goes straight to WebGL 2 with far fewer particles.
  • Otherwise the renderer tries WebGPU and falls back to WebGL 2 on its own. It asks for powerPreference: 'low-power', which MDN recommends whenever an app runs well with it, because it “can significantly improve battery life on portable devices” (MDN).
  • A watchdog times 40 frames after start-up. If they average slower than 25 frames per second, the field stops animating and draws still frames instead.

It sizes itself by device class. 36,000 particles on desktops, 14,000 on small screens and touch devices, and 5,000 where graphics are drawn in software. Pixel density is capped as well.

The simulation runs on the graphics chip. One TSL compute pass moves every particle each frame, on springs tuned to settle without wobble. The main thread updates a handful of values per frame, and a new shape is a single buffer upload.

It stops when you can’t see it. Browsers pause animation frames in background tabs (MDN), but not when a canvas scrolls out of view. The field animates only while it’s in use on screen, the tab is visible, motion is allowed and the device is keeping up. When its sections scroll away, it stops drawing.

Reduced motion gets a finished picture. With the device’s reduced-motion setting on, each shape is drawn once, settled in place. The hand-off between pages, the scroll-linked effects and our page transitions all switch off.

It carries over between pages. Before you move to another page on the site, the field freezes and reads its particles back from the graphics chip. The positions go into the tab’s session storage, packed as 16-bit numbers, and nothing leaves the browser. The next page draws them on a plain 2D canvas before its first paint. If that page has a shape, the GPU engine picks up from the same positions; if not, the dots scatter and fade. A snapshot older than six seconds, or from a different window size, is ignored. The rest of the page morphs with native view transitions, but the field doesn’t depend on them, which matters in Firefox.

The homepage starts from city lights. At build time, a script finds 8,112 lit windows in our Boston skyline photo. The particles start on those windows and lift off into the first shape as you scroll. The photo itself never moves.

The engine loads only when it’s used. The GPU engine, meaning three.js itself, the WebGPU renderer, TSL and our simulation, is about 300 KB gzipped in our build, and arrives by dynamic import only when the page shows the field, after the visitor’s first scroll, tap, key press or pointer movement. The field’s own loader, which every page runs up front, is about 11 KB before compression.

It has automated tests. Our browser tests check that the field animates beside its sections and stops when they scroll away, that the next page draws the hand-off before its first paint, that reduced motion never hides copy, and that the hero heading paints without an entrance animation, plus accessibility checks. One honest gap: they run in Chromium only.

On one machine, in headless Chrome with no throttling, our homepage’s largest contentful paint was the skyline photo at desktop and phone sizes, layout shift was zero, and the field ran on WebGPU. Forced onto WebGL 2, it ran there too. That’s a lab check. We don’t run analytics, so we collect no field data of our own.

A Build Recipe

  1. Design the still frame first. Decide what the visual shows with motion off, on a slow device and with no GPU. That frame is your real minimum.

  2. Keep real content as the hero. A photo or headline should be your LCP element. Put the canvas behind it: fixed position, pointer-events: none, aria-hidden="true".

  3. Gate it in the head, so browsers without JavaScript or graphics keep the static design. Style the canvas only under this class:

    <script is:inline>
      if ('gpu' in navigator || 'WebGL2RenderingContext' in window)
        document.documentElement.classList.add('has-field');
    </script>
    
  4. Load three.js on demand. Ship one small module script, and bring in the engine with dynamic import() only on pages that use it.

  5. Probe, then start the renderer. A sketch of what ours does:

    const { WebGPURenderer } = await import('three/webgpu');
    const probe = document.createElement('canvas')
      .getContext('webgl2', { failIfMajorPerformanceCaveat: true });
    const renderer = new WebGPURenderer({
      canvas, alpha: true, antialias: false,
      powerPreference: 'low-power', forceWebGL: !probe,
    });
    await renderer.init(); // WebGPU, or WebGL 2 if WebGPU can't start
    
  6. Set particle counts by device class, and cut them hard when the probe fails.

  7. Put per-particle work in a TSL compute pass. The main thread should only set a few values per frame.

  8. Run the loop only when it matters: in view (an IntersectionObserver), tab visible, motion allowed. Use the frame timestamp so speed doesn’t depend on the screen’s refresh rate (MDN).

  9. Add a watchdog that switches slow devices to still frames.

  10. Choose your 2.2.2 option, a still frame within five seconds or a pause control, and honor prefers-reduced-motion too, with a settled frame rather than a blank.

  11. Treat page transitions as decoration. Use native cross-document view transitions, and never depend on them.

  12. Pin three to an exact version, and read the migration guide before upgrading.

  13. Test every tier on purpose: WebGPU, forced WebGL 2 (we use a ?field=webgl switch in the URL), reduced motion, no JavaScript, and automated accessibility checks.

The Short Version

Before you sign off on a visual, check that you have:

  • A designed still frame for reduced motion, slow devices and no GPU.
  • A real image or headline as the LCP element, with the engine loaded after it.
  • WebGPU, WebGL 2 and still-frame tiers, each tested.
  • Animation that stops off screen.
  • A decided approach to WCAG 2.2.2, plus reduced-motion support.
  • An exact three.js version, and an owner for upgrades.

To see how the rest of this site is built, start with our site walkthrough. If you want a visual like this on yours, start on our Connect page.