Guides
Chaining shaders
Chaining shaders is where ShaderPad’s internal texture handling becomes especially useful.
What “Chaining” Means
One ShaderPad instance renders into an internal texture, and another ShaderPad samples that output.
const passA = new ShaderPad(fragmentA, { canvas: new OffscreenCanvas(256, 256) })
const passB = new ShaderPad(fragmentB, { canvas })
passB.initializeTexture('u_firstPass', passA)
Offscreen And Headless Usage
You do not need an HTML canvas for every pass.
const offscreen = new ShaderPad(fragmentShaderSrc, {
canvas: { width: 512, height: 512 },
})
That creates an internal OffscreenCanvas and is useful for:
- Intermediate passes
- Preprocessing
- Reduced-resolution buffers
- Texture-format conversion pipelines
draw() Versus step()
Use step() when the pass should advance time, frame count, or history.
Use draw() when the pass should simply render current state without advancing those values.
This distinction matters in multi-pass and feedback workflows.
Why Constructor Texture Options Exist
ShaderPad constructor options accept render-texture settings such as:
internalFormatformattypeminFiltermagFilterwrapSwrapT
These apply to ShaderPad’s internal render targets and history textures.
They matter when you want:
- Float or integer pipelines
- Reduced-channel storage such as
R8 - Precision preservation across passes
- Explicit filtering behavior in chained shaders
Example Pattern
The webcam-bw example demonstrates a good chained workflow:
- First pass renders webcam to a compact grayscale buffer
- Second pass samples that buffer and its history