MotionGPU renders fullscreen fragment shaders written in WGSL (WebGPU Shading Language). This page covers the WGSL concepts you need for effective shader authoring, the conventions MotionGPU imposes, and common visual patterns.
The fragment contract
Every material must declare exactly this function:
uv— normalized coordinates from(0, 0)at the bottom-left to(1, 1)at the top-right.- Return value — an RGBA color. The alpha channel is typically
1.0for opaque output.
If this signature is missing, defineMaterial throws immediately.
Shader output is treated as linear color. In the default SDR path values are presented with the configured color.outputEncoding. When FragCanvas enables color.toneMapping, color.dynamicRange, or a custom color.workingFormat, the scene and post-process graph run through an internal working format first. Khronos PBR Neutral expects non-negative linear Rec.709 HDR values and is applied by the private final presentation pass after all render passes.
Coordinate space
This is the standard GPU convention (Y-up), not the DOM convention (Y-down). When converting pointer coordinates manually, flip Y: 1.0 - (clientY - top) / height. If you use usePointer(), state.current.uv already uses this Y-up orientation.
The final presentation pass keeps this public uv contract unchanged. Internally it samples render-target textures in framebuffer coordinates, so enabling color does not flip the shader output.
Built-in bindings
Motion GPU injects the frame uniforms plus any user uniforms/textures you declare. You do not declare these bindings yourself.
Frame uniforms (always available)
These are injected by the renderer and updated every frame:
User uniforms
Any uniform you declare in defineMaterial({ uniforms: { ... } }) becomes a field on the motiongpuUniforms struct:
Here uTime and uIntensity are both f32 fields on motiongpuUniforms.
User textures
Textures declared in the material become texture_2d<f32> bindings with an associated sampler. You sample them with a generated helper:
For each texture named uFoo, the shader gets:
uFoo: texture_2d<f32>— the texture bindinguFooSampler: sampler— the associated sampler
WGSL quick reference
If you are new to WGSL, here are the most common types and functions used in fragment shaders:
Scalar and vector types
Common math functions
Common shader patterns
UV gradient
The simplest shader maps UV coordinates directly to colors:
Animated sine wave
Radial glow
Circle SDF (Signed Distance Field)
Aspect-ratio correction
The UV space is always [0..1] × [0..1], which can stretch non-square canvases. To get square pixels:
Color output and presentation
By default, FragCanvas uses sRGB output encoding (color.outputEncoding: 'srgb'). This means the renderer applies a linear-to-sRGB conversion to your fragment output automatically on the standard SDR path.
If you are doing your own color management and want raw linear output, set color={{ outputEncoding: 'linear' }} on FragCanvas. Note that changing this triggers a renderer rebuild since it changes the pipeline signature.
color.canvasColorSpace is a separate WebGPU canvas configuration option. It selects the canvas presentation space such as 'srgb' or 'display-p3'; it does not replace the final value encoding step.
When a color presentation pipeline is active, output conversion moves to the private final presentation pass. This keeps tone mapping and SDR/HDR presentation after all render passes instead of baking it into the scene shader.