glsl-helpers-react
v2.1.2
Published
React GLSL canvas component with Shadertoy-compatible uniforms, WebGL2 support, and extended texture helpers. Fork of shadertoy-react.
Maintainers
Readme
glsl-helpers-react
React GLSL canvas with Shadertoy-compatible uniforms and extended helpers.
Fork notice: This project is a maintained fork of mvilledieu/shadertoy-react. The prior npm package for this fork was
shadertoy-react-19. Version 2.x ships asglsl-helpers-reactwith a new primary API (GlslCanvas) while keeping a deprecatedShadertoyReactalias.
What's new in 2.x
GlslCanvas— new primary component export- WebGL2 / GLSL 3.00 — auto-detect or force via
webgl="auto" | "1" | "2" - React 19 support
- TypeScript definitions — props IntelliSense via
index.d.ts - Reactive props —
textures,fs,defines, and shader schema updates without remounting definesprop — inject#defineconstants from ReactsrcSettextures — responsive image density like<img srcSet />iChannelTime— per-channel playback time (videos sync tocurrentTime)- Extended textures — camera, data, cube maps, keyboard input
- Multi-pass rendering — Shadertoy-style buffer passes via
passesprop persistentTime— opt-iniPersistentTimeuniform that survives page refresh
Documentation
- Contributing
- Reporting issues
- Roadmap
- Roadmap specs (implementation + review)
- Changelog
- Migration guide (2.0)
- Textures
- Multi-pass rendering
- Uniforms
- Troubleshooting
Install
npm install glsl-helpers-reactQuick start
import React from "react";
import GlslCanvas from "glsl-helpers-react";
const fs = `
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
fragColor = vec4(0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0.0, 2.0, 4.0)), 1.0);
}
`;
export default function App() {
return (
<div style={{ width: "100vw", height: "100vh" }}>
<GlslCanvas fs={fs} />
</div>
);
}Playground
One shader, zero clone — edit an annotated .frag in the browser (Shadertoy syntax, built-in uniforms, iPersistentTime).
Source: sandbox/playground
Demo
Full 15-tile demo grid (expanded from upstream examples/) — mouse, textures, multi-pass, camera, keyboard, …
Deploy after examples/ changes: npm run publish-demo (see CONTRIBUTING). Run locally: npm start in the repo root.
Demo sandbox
Fullscreen router demo matching upstream CodeSandbox Demos — + More menu, one shader per route (Basic, Textures, Custom Uniforms, built-in uniform showcases).
Source: sandbox/demo-sandbox
Migration from shadertoy-react
| Before | After |
|---|---|
| import X from 'shadertoy-react' | import GlslCanvas from 'glsl-helpers-react' |
| <ShadertoyReact fs={fs} /> | <GlslCanvas fs={fs} /> |
| npm: shadertoy-react-19 | npm: glsl-helpers-react |
Legacy import (deprecated):
import { ShadertoyReact } from "glsl-helpers-react";Props
| Prop | Type | Description |
|---|---|---|
| fs | string | Fragment shader (Shadertoy or classic GLSL syntax) |
| vs | string | Optional vertex shader |
| passes | PassProps[] | Multi-pass pipeline (see below) |
| textures | TextureProps[] | Input channels (iChannel0, …) |
| uniforms | object | Custom uniforms |
| defines | object | #define constants injected into the shader |
| clearColor | [r,g,b,a] | WebGL clear color (default [0,0,0,1]) |
| precision | lowp \| mediump \| highp | GLSL float precision |
| devicePixelRatio | number | Canvas pixel density (default 1) |
| webgl | auto \| 1 \| 2 | WebGL version selection |
| lerp | 0–1 | Mouse position smoothing |
| style | CSSProperties | Canvas inline style |
| contextAttributes | WebGLContextAttributes | Passed to getContext |
| onDoneLoadingTextures | function | Called when all textures are loaded |
| persistentTime | boolean \| object | Opt-in epoch time via iPersistentTime (survives refresh) |
Built-in uniforms
Shadertoy-compatible uniforms are injected automatically when referenced in your shader:
iTime,iTimeDelta,iFrame,iResolution,iDate,iMouseiChannel0…iChannelN,iChannelResolution,iChannelTimeiDeviceOrientation(extension)iPersistentTime(extension; requirespersistentTimeprop)#define DPRfromdevicePixelRatio
Unused uniforms skip event listeners and GPU uploads.
Persistent time (persistentTime)
// Continues across page refresh (localStorage)
<GlslCanvas fs={fs} persistentTime />
// Custom epoch and shared storage key
<GlslCanvas
fs={fs}
persistentTime={{
epoch: "2026-01-01T00:00:00Z",
storageKey: "my-app:shader-clock",
shared: true,
}}
/>Use iPersistentTime in the shader for wall-clock phase; iTime remains session time since mount. See Uniforms.
Custom uniforms
<GlslCanvas
fs={fs}
uniforms={{
uScroll: { type: "1f", value: scrollY },
uMatrix: { type: "Matrix2fv", value: [0, 1, 2, 3] },
}}
/>Supported types: 1f, 2f, 3f, 4f, 1fv–4fv, 1i–4i, 1iv–4iv, Matrix2fv, Matrix3fv, Matrix4fv.
#define from props
<GlslCanvas fs={fs} defines={{ PI: "3.14159", FEATURE_FLAG: 1 }} />Textures
// Image or video URL
{ url: "./texture.png" }
// Responsive srcSet (1x, 2x, 3x)
{ url: "./a.png", srcSet: { 1: "./a.png", 2: "./[email protected]", 3: "./[email protected]" } }
// or: srcSet: "a.png 1x, [email protected] 2x"
// Camera feed (requires HTTPS and user permission)
{ type: "camera", facingMode: "user", width: 640, height: 480 }
// Raw data texture (rgba32f requires WebGL2 or OES_texture_float)
{ type: "data", width: 256, height: 256, data: uint8Array, format: "rgba8" }
// Cube map (6 face URLs: +X, -X, +Y, -Y, +Z, -Z)
{ type: "cube", urls: [px, nx, py, ny, pz, nz] }
// Keyboard input (Shadertoy-style 256×3 data texture)
{ type: "keyboard" }Import filter/wrap constants:
import GlslCanvas, { LinearFilter, RepeatWrapping } from "glsl-helpers-react";Multi-pass rendering
<GlslCanvas
passes={[
{ fs: bufferShaderA, target: "bufferA" },
{ fs: bufferShaderB, inputs: ["bufferA"], target: "bufferB" },
{ fs: finalShader, inputs: ["bufferA", "bufferB"] },
]}
/>Each pass renders to an internal framebuffer (target) or to the screen (last pass). Buffer outputs are wired to iChannel0, iChannel1, … in subsequent passes via inputs.
Limitations: One framebuffer per target name (no automatic ping-pong). Self-feedback shaders read the previous frame's buffer. See Multi-pass.
WebGL2 / GLSL 3.00
Set webgl="2" or webgl="auto" (default). Shadertoy syntax is rewritten automatically (gl_FragColor → fragColor, texture2D → texture). You can also author shaders with #version 300 es directly.
How it works
A full-viewport quad is rendered with WebGL. Canvas size follows the parent element (100% × 100% by default, overridable via style). Uniforms and textures referenced in the shader source are detected at compile time — unused inputs do not register listeners or GPU state.
Roadmap status
Current line: 2.1.2 on test/sandbox-playground — pending merge to main and npm publish. Full backlog: roadmap · spec index.
Shipped (2.x)
| Feature | Status |
|---|---|
| Module / props IntelliSense | Done (2.x) |
| Dynamic texture reload on prop change | Done (2.x) |
| Responsive srcSet textures | Done (2.x) |
| #define from props | Done (2.x) |
| Camera feed texture | Done (2.x) |
| Data texture | Done (2.x) |
| WebGL2 / GLSL 3.00 | Done (2.x) |
| Keyboard input texture | Done (2.x) |
| iChannelTime | Done (2.x) |
| Cube texture | Done (2.x) |
| Multi-pass rendering | Done (2.x) |
| Persistent time (iPersistentTime) | Done (2.x) |
| Demo grid scroll UX + jump nav | Done (2.1.0) |
| Three-tier demos (playground / sandbox / grid) | Done (2.1.1–2.1.2) |
| Canvas sizing + texture flipY + multi-pass channels | Done (2.1.2, branch) |
| Playwright visual regression CI | Done (2.1.2, branch) |
Next
| Version | Feature | Review spec |
|---|---|---|
| 2.1.2 | Release merge + npm + GitHub Pages | release review · changelog 2.1.2 |
| 2.1.3 | SECURITY.md | review |
| 2.1.3 | Deprecate shadertoy-react-19 on npm | review |
| 2.1.3 | ESM exports map | review |
| 2.1.4 | Dependabot + changelog CI guard | Dependabot review |
| 2.1.4 | Unit tests (shader preprocessor) | review |
| 2.1.5 | Framework cookbooks (Next/Vite/Remix) | review |
| 2.2.0 | Framework-agnostic core | review |
License
MIT — see LICENSE. Original work © Morgan Villedieu; fork maintenance © Henrique Stelzer de Oliveira.
Shader examples in examples/src/shaders/ may carry separate licenses (e.g. CC BY-NC-SA from Shadertoy) noted in file headers. Those licenses apply to shader source only, not the npm package.
Attribution
Based on shadertoy-react by Morgan Villedieu. Shadertoy uniform conventions follow Shadertoy.
