Motion GPU supports WebGPU compute shaders through ComputePass and PingPongComputePass. Compute passes are accepted in the same passes prop as render passes, but they always dispatch in a pre-scene phase before the base fragment shader renders.
The pass constructors are framework-agnostic and available from all entrypoints.
The stable public compute API is intentionally narrow: provide WGSL source and a dispatch strategy through ComputePass or PingPongComputePass.
Overview
Compute shaders operate on storage buffers and storage textures rather than rendering pixels. They execute a user-defined WGSL kernel across a configurable grid of workgroups.
The typical workflow:
- Declare storage buffers in
defineMaterial({ storageBuffers }). - Create a compute pass with
new ComputePass({ compute, dispatch }). - Pass it to
FragCanvasvia thepassesprop. - Read/write storage buffers in
useFramecallbacks viastate.writeStorageBuffer()andstate.readStorageBuffer().
Compute-only storage textures with integer formats (*uint, *sint) automatically get fragmentVisible: false because texture_2d<f32> cannot sample integer textures (setting fragmentVisible: true on these formats throws). For float-sampled storage formats, set fragmentVisible: false explicitly to avoid reserving fragment-stage sampler/texture bindings.
ComputePass
A single-dispatch compute pass that runs a WGSL compute shader.
Compute shader contract
The WGSL source must contain:
- A
@compute @workgroup_size(X)(or@workgroup_size(X, Y)/@workgroup_size(X, Y, Z)) attribute. - A function named
compute— e.g.,fn compute(@builtin(global_invocation_id) id: vec3u). - A
@builtin(global_invocation_id)parameter in thecomputefunction signature (not only elsewhere in the module). - Numeric
@workgroup_sizedimensions as integers in valid WebGPU range (1..65535per axis).
The library extracts the workgroup size from the attribute and validates the entrypoint at construction time.
Dispatch modes
The dispatch option controls how many workgroups are launched:
ComputeDispatchContext
Runtime API
PingPongComputePass
An iterative compute pass for simulations that require multiple compute iterations per frame (fluid dynamics, reaction-diffusion, etc.).
Options
Runtime API
Bind group layout
ComputePass shaders use this bind group layout:
fragmentVisible: false affects only fragment-stage bindings (group(0) in the render pipeline). Compute storage bindings in group(2) are still generated and bound normally.
PingPongComputePass uses generated A/B texture bindings at group(2):
Storage buffers are automatically bound in alphabetical order by name. You access them by their declared name directly in WGSL:
Compute + fragment integration
Compute passes and render passes coexist in the same passes array. All enabled compute passes dispatch before the scene render so that storage textures and buffers are up-to-date when the fragment shader reads them:
<FragCanvas {material} passes={[simulate]} />The compute pass runs first, updating the particles buffer. The fragment shader then reads the updated data for visualization.
Render graph behavior
Compute passes have kind: 'compute' in the render graph plan and behave differently from render passes:
- They do not participate in slot routing (
source/target/canvas). - They do not swap ping-pong buffers.
- They execute their compute pipeline before the base scene render.
- Their relative order against other compute passes is preserved.
- Interleaving a compute pass between two render passes in the array does not create a mid-post-process compute step.
- They share the same command encoder and submit queue as render passes.
- Compute-only pipelines render the base scene directly to
canvas; they do not allocate post-process ping-pong textures or run a final blit.
Disabled compute passes (enabled: false) are fully skipped.
Error handling
Compute shader compilation errors are classified as COMPUTE_COMPILATION_FAILED with severity: 'error' and recoverable: true. They go through the same error normalization pipeline as fragment shader errors.
Structured diagnostics for compute compilation failures include:
shaderStage: 'compute'computeSource(original user source)- source mapping entries with
sourceLocation.kind = 'compute'