API Reference
Plugins
ShaderPad plugins are plain functions. They run during construction, before the final fragment shader is compiled, so they can change both JavaScript behavior and the GLSL source seen by ShaderPad.
If you want a real example before reading an API checklist, start with the autosize plugin source. It is small, readable, and shows the normal shape of a plugin: reading shader.canvas, reacting to lifecycle events, emitting a namespaced event, and cleaning up on destroy.
For more examples, browse the full plugins source folder.
Small Example
import type { Plugin } from 'shaderpad';
function pulse(): Plugin {
return (shader, { injectGLSL, emit }) => {
injectGLSL(`uniform float u_pulse;\n`);
shader.on('_init', () => {
shader.initializeUniform('u_pulse', 'float', 0);
});
shader.on('beforeStep', (time: number) => {
shader.updateUniforms({ u_pulse: 0.5 + 0.5 * Math.sin(time) });
emit('pulse:update', time);
});
};
}
This is the normal pattern:
- Use
injectGLSL()to add uniforms, helper functions, or constants. - Use
shader.on(...)for setup, per-frame work, and cleanup. - Use
emit(...)for custom namespaced events such aspulse:update.
What A Plugin Gets
Import Plugin, PluginContext, and ShaderPadEventName from shaderpad.
PluginContext exposes:
| Member | Use it for |
|---|---|
injectGLSL(code) | Inserting GLSL before shader compilation |
emit(name, ...args) | Emitting plugin events such as myPlugin:ready |
updateTexture(name, source, historySlots?) | Writing plugin-owned textures without firing public updateTextures |
Use shader.canvas and shader.gl directly when a plugin needs the backing canvas or raw WebGL access.
When updateTexture(...) writes to a history-backed texture, historySlots wraps automatically. On non-history textures it is ignored, and the last written slot becomes the frame-offset uniform.
Lifecycle Hooks
These are the supported hook names for shader.on(...):
_initinitializeTextureupdateTexturesinitializeUniformupdateUniformsbeforeStepafterStepbeforeDrawafterDrawupdateResolutionplaypauseresetdestroy
The hooks most plugins actually need are:
_initfor setup after ShaderPad has initialized its internals.beforeSteporbeforeDrawfor ongoing work.destroyfor cleanup.
Conventions
- Keep custom events namespaced, such as
autosize:resizeormyPlugin:ready - Plugin installation order is stable:
plugins[]order controls installation, handler order, and GLSL injection order - If you mutate shared GL state through
shader.gl, restore it before returning
If you want to see how first-party plugins use the same public surface, the best starting points are:
- autosize.ts for lifecycle, events, and cleanup.
- helpers.ts for pure GLSL injection.
- face.ts if you need a larger example that publishes plugin-owned textures.