#2801·drei

[v11] Stories for the 9 converted WebGPU components that have none

Author: DennisSmolekCreated Sep 1, 2026Updated Sep 2, 2026
Labelswebgpuv11effort:Lagent-ok

The rule this issue now follows

A story for an unconverted component is not a story task — it is part of that component's conversion.

Writing a story against a component that was never really ported produces a red story and no new information: we already know it does not work. So this issue covers only components whose WebGPU implementation is finished and believed ready. For everything else, "write the story" has been moved into the conversion/fix issue for that component, as an acceptance criterion.

Scope: 9 components

src/webgpu/ has 29 components. 17 are already rendered by some story (usually a legacy/core story that routes through PlatformSwitch). Of the 12 that are not, three have been moved out — see the table below. These nine remain:

Component Path
ContactShadows src/webgpu/Staging/ContactShadows
ConvolutionMaterial src/webgpu/Materials/ConvolutionMaterial
DiscardMaterial src/webgpu/Materials/DiscardMaterial
GradientTexture src/webgpu/Textures/GradientTexture
Image src/webgpu/UI/Image
Outlines src/webgpu/Effects/Outlines
Trail src/webgpu/Effects/Trail
Wireframe src/webgpu/Geometry/Wireframe
WireframeMaterial src/webgpu/Materials/WireframeMaterial

One caveat carried in the source rather than in an issue: ContactShadows' color prop is documented as non-functional (ContactShadows.tsx:8-12 — MultiplyBlending on white only supports grayscale). The story should exercise color anyway and record the result; if it is genuinely dead, that is a stub candidate for #2803.

Moved into the conversion issues

Component Now tracked in Why
BlurPass #2811 Still the WebGL implementation. Imports WebGLRenderer/WebGLRenderTarget, not exported from the /webgpu barrel. Nothing to write a story against.
SpotLightMaterial #2663 "legacy works, webgpu is problematic" — the story is how that gets confirmed fixed.
BakeShadows #2665 See the note there: it is 13 lines with no shader, and it is not clear it needs a webgpu/ copy at all.

Also folded in, for components with no src/webgpu/ implementation at all: Text → #2588/#2658, MeshDiscardMaterial → #2660.

Pattern

src/webgpu/Staging/AccumulativeShadows/AccumulativeShadows.stories.tsx is the worked example. The two things that are easy to get wrong:

  • limitedTo="webgpu" is what actually pins the renderer, not renderer={context.globals.renderer}. Setup computes isLegacy = limitedTo === 'legacy' || (limitedTo === null && renderer === 'legacy'), so without limitedTo the toolbar can toggle a src/webgpu/ component onto the WebGL renderer and it will fail. Tag the story webgpuOnly too.
  • A story that references a component's ref type will fail typecheck if that type is not exported. AccumulativeShadows had exactly this — TS4023/TS4082 out of declaration emit, because declaration: true is repo-wide. Export the interface; do not annotate around it.

Prefer primitives over a GLTF in the scene. If a story renders nothing, the cause should unambiguously be the component and not an asset that failed to load.

Verification, and its limit

bash
npx vitest run --config vite.config.mts     # renders every story headlessly

This does not prove WebGPU works. The headless runner has no navigator.gpu, so WebGPURenderer silently falls back to WebGLBackend (three/src/renderers/common/Renderer.js, getFallback). Stars is confirmed to render nothing under real WebGPU (#2786) and it passes this suite. A green run means the component mounts and does not throw. Actual WebGPU verification is a browser with a GPU, and that is Dennis.

Acceptance

Each of the nine has a <Name>.stories.tsx beside it that mounts under limitedTo="webgpu", and either renders or has an issue explaining why not. Do not fix broken components here — record and open. Fixing is #2803.