Components
React
The shaderpad/react export is a small React wrapper around the core ShaderPad constructor. It renders one managed <canvas>, handles autosize and managed playback by default, and gives you direct access to the underlying instance when you need it.
If you want the exact prop and ref reference, read the React API page.
Example
'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>
);
}
Common Patterns
Extra plugins and options
The autosize plugin is included by default. 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>
);
}
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}.
onInit and onBeforeStep
Use onInit for setup such as custom uniforms or textures. Use onBeforeStep for per-frame updates and to return optional StepOptions.
<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],
});
}}
/>
Texture children
React supports declarative texture children with data-texture attributes.
<ShaderPad shader={shader}>
<img data-texture="u_frame" src="/frame.png" alt="" />
<video data-texture="u_webcam" src="/camera.mp4" muted playsInline />
<canvas data-texture="u_overlay" width={512} height={512} />
</ShaderPad>
Texture option props use the data-texture-* prefix:
<video
data-texture="u_trail"
data-texture-history={24}
data-texture-preserve-y={false}
src="/trail.mp4"
muted
playsInline
autoPlay
loop
/>
Nested <ShaderPad> children are managed by the parent and can be used for multipass rendering:
<ShaderPad shader={compositeShader}>
<ShaderPad shader={passShader} data-texture="u_pass" />
</ShaderPad>
For live sources such as video, canvas, and nested <ShaderPad>, the wrapper refreshes the texture before each rendered frame.
Playback
The wrapper autoplays by default, and automatically pauses playback when offscreen. Disable either behavior with their corresponding props:
<ShaderPad shader={shader} autoplay={false} autopause={false} />
autopause only applies to autoplay. If autoplay={false} and you call ref.current?.play(), that playback is yours to pause or resume.
Core and plugin events
For events that are not represented by React props, use the underlying instance and normal shader.on(...) subscriptions.
'use client';
import { useEffect, useRef, useState } from 'react';
import ShaderPad from 'shaderpad/react';
export default function EventExample() {
const shaderRef = useRef<React.ElementRef<typeof ShaderPad>>(null);
const [ready, setReady] = useState(false);
useEffect(() => {
const shader = shaderRef.current?.shader;
if (!shader) return;
const handleResize = (width: number, height: number) => {
console.log('autosize', width, height);
};
shader.on('autosize:resize', handleResize);
return () => shader.off('autosize:resize', handleResize);
}, [ready]);
return <ShaderPad ref={shaderRef} shader={shader} onInit={() => setReady(true)} />;
}
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>
</>
);
}
Unstable props can cause a rebuild
The wrapper creates a new ShaderPad instance when core setup props such as these change:
shadercursorTargetpluginsoptionsautosize
Keep plugins, options, and custom autosize values stable unless you want a fresh instance. Callback props and playback props update without recreating the instance.
For more detailed coverage, read the React API page.