Guides
React
The shaderpad/react export wraps the normal ShaderPad canvas lifecycle in a React component. It owns the canvas element, enables autosize() by default, pauses and resumes with visibility changes, and still gives you direct access to the underlying ShaderPad instance when you need it.
If you want the full prop and ref reference, read the React API page.
Example usage
'use client';
import { ShaderPad } from 'shaderpad/react';
const shader = `#version 300 es
precision highp float;
in vec2 v_uv;
uniform float u_time;
uniform vec2 u_resolution;
out vec4 outColor;
void main() {
vec2 uv = v_uv * 2.0 - 1.0;
uv.x *= u_resolution.x / u_resolution.y;
float glow = 0.25 / max(length(uv), 0.001);
vec3 color = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0.0, 2.0, 4.0));
outColor = vec4(color * glow, 1.0);
}`;
export default function ReactExample() {
return (
<div style={{ height: 320 }}>
<ShaderPad shader={shader} />
</div>
);
}
Client Components
Use the wrapper from a client component:
'use client';
import { ShaderPad } from 'shaderpad/react';
Common Patterns
Autosize ownership
If you want the wrapper to own resizing, leave autosize alone and pass your other plugins through plugins. If you need to install your own autosize() instance, disable wrapper autosize first with autosize={false}.
Extra plugins and options
Pass extra plugins through plugins and any remaining core constructor options through options.
'use client';
import { ShaderPad } from 'shaderpad/react';
import helpers from 'shaderpad/plugins/helpers';
export default function HistoryExample() {
return (
<div style={{ height: 280 }}>
<ShaderPad
shader={shader}
plugins={[helpers()]}
options={{ history: 8 }}
/>
</div>
);
}
onInit And onBeforeStep
Use onInit for setup such as custom uniforms or textures. Use onBeforeStep for per-frame updates.
<ShaderPad
shader={shader}
onInit={shader => {
shader.initializeUniform('u_accent', 'float', [0.0, 1.0, 0.5]);
}}
onBeforeStep={(shader, time) => {
shader.updateUniforms({
u_accent: [0.4 + 0.4 * Math.sin(time), 1.0, 0.6],
});
}}
/>
Events and visibility
Use events for core or plugin events, and onOnscreenChange when you only care about visibility state.
<ShaderPad
shader={shader}
events={{
updateUniforms: (updates, options) => {
console.log('uniforms', updates, options);
},
'autosize:resize': (width, height) => {
console.log('autosize', width, height);
},
}}
onOnscreenChange={isOnscreen => {
console.log('visible', isOnscreen);
}}
/>
Imperative refs
Use a ref when you want direct control over playback or the underlying ShaderPad instance.
'use client';
import { useRef } from 'react';
import { ShaderPad } from 'shaderpad/react';
export default function RefExample() {
const shaderRef = useRef<React.ElementRef<typeof ShaderPad>>(null);
return (
<>
<button type="button" onClick={() => shaderRef.current?.pause()}>
Pause
</button>
<button type="button" onClick={() => shaderRef.current?.play()}>
Play
</button>
<div style={{ height: 280 }}>
<ShaderPad ref={shaderRef} shader={shader} />
</div>
</>
);
}
When the wrapper rebuilds
The wrapper recreates the underlying ShaderPad instance when these configuration-like inputs change:
shaderpluginsoptionsautosizecursorTarget
Keep plugins arrays, options objects, and custom autosize objects stable unless you intend to reconfigure the instance. Callback props and events handlers stay live without forcing a rebuild.
The full prop list, ref methods, defaults, and runtime behavior are documented on the React API page.