A browser-based WebGL shader composer with a modular effect system, real-time preview, and export to TypeScript, HTML or PNG.
The interface uses Lovable’s Camera Plain Variable font, heart mark and Pulse colour tokens. The font and mark are self-hosted; shader palettes remain independent.
- Modular effects — Build shaders by combining self-contained effect blocks (generators, post-processing, UV transforms)
- Real-time preview — WebGL canvas with play/pause, reset, and adjustable time scale
- Presets — 7 searchable visual presets with palette variants: Sweep, Ripple, Bloom, Contour, Veil, Ribbon and Love
- Generator layering — Scalar generators use contrast-based blending; RGB generators such as Flow Bands use layer opacity
- Code viewer — Read-only CodeMirror 6 editor showing the composed GLSL output
- Export — Generate self-contained TypeScript functions, standalone HTML files, or PNG images at a chosen size
- Save/Load — Persist shader projects to localStorage with autosave
- Share — Copy shareable URLs with encoded shader state
npm install
npm run devOpen the local URL printed by Vite (default http://localhost:5173).
GitHub Actions builds and deploys the site to GitHub Pages after each push to main. The workflow runs npm ci and npm run build; Pages uses the GitHub Actions source.
Production builds use /pulse-studio/ as their asset base. Development stays at /. To check the production build locally:
npm run build
npm run previewOpen http://localhost:4173/pulse-studio/.
Choose Sweep, Ripple, Bloom, Contour, Veil, Ribbon or Love from the sidebar to load a pre-configured combination of effects. Start blank clears the composition. Presets are starting points — you can add, remove, or tweak effects after loading one.
Sweep, Ripple and Bloom use Flow Bands for layered color sheets with edge softness and motion. Sweep's travelling folds change local curvature and spacing. Ripple refracts a continuous colour field through a curved glass surface; its normal, thickness and reflected light stay connected as it moves. Bloom's underside follows its upper edge with a delay. Pace or Evolve at zero preserves the rest composition.
Flow Bands also includes Contour, Veil and Ribbon. Contour opens nested colour bands around a quiet field; Veil bends a translucent vertical sheet; Ribbon turns a free strip through space. Their presets include light and dark palettes tuned in OKLCH. Rotation, Center and Scale position each form around page content. Width changes the spacing or thickness of these three new forms.
Edge Softness controls the width of folds and highlights: lower values give sharper edges. Diffuse Blur → Radius softens the full image separately. All six Flow Bands presets include blur at zero, which skips blur sampling. Nonzero blur adds 21 scene samples per pixel; edge softness adds no scene samples.
Click Add Effect to open the effect catalog. Effects are grouped by category:
- UV Transform — Pixelate, Kaleidoscope, Polar Coordinates, Wave Warp
- Generators — Gradient, Ramp, Flow Bands, Noise, Voronoi, Caustics, Chladni, Domain Warp, Wave, Glow Waves, Spiral, LED Bars, Dot Lattice 3D, Moiré Fields, Starfield, Terrain Field
- Post-Processing — Brightness, Diffuse Blur, Vignette, Film Grain, CRT Scanlines, Dot Grid, ASCII, ASCII Overlay, Dither
Each effect has grouped controls with sliders and editable number values. Effects can be toggled on/off, removed, or reordered within their category. Drag a handle to reorder, or focus it and use the up/down arrow keys. A continuous drag creates one undo step, including when you pause during the drag.
Up to 12 colors can be added. Generators use these to produce the color gradient via a colorRamp() function. Edit colors with the picker or a hex value, and reorder them by dragging their handles or using the up/down arrow keys. When two or more colors are present, a gradient bar with draggable stop handles controls each color's position. The stop handles also support arrow keys. Closely spaced stops keep their precision when a new color is added.
Some presets include color palettes — named variations in the Colours section. Randomise generates gamut-mapped palettes in OKLCH before converting them to export-safe hex values.
Toggle the code viewer with the Code button or Ctrl+E to inspect the composed GLSL fragment shader. The editor loads only when opened. Its output updates live as you add effects and adjust parameters. Drag the panel separator or focus it and use the arrow keys to resize the panel.
The export panel generates production-ready code with all parameter values baked in:
- TypeScript — A single function that mounts a WebGL canvas on a target
<div>and returns a cleanup function - HTML — A standalone page for quick testing
- PNG — The current animation frame at a width and height from 1 to 4096 pixels; changing the aspect ratio recomposes the shader at that size
Code exports retain the selected playback speed and follow prefers-reduced-motion. Pass { animate: true } as the final argument to animate explicitly, or { animate: false, time: 12 } for a still frame at 12 seconds. The optional speed value overrides the exported playback speed. Hidden pages pause animation, and the returned cleanup function releases the canvas and GPU resources. The editor starts paused when reduced motion is enabled; paused canvases redraw only after an edit, reset or resize.
| Shortcut | Action |
|---|---|
Ctrl/Cmd + E |
Toggle code viewer |
Ctrl/Cmd + B |
Toggle controls |
Ctrl/Cmd + S |
Save shader |
Ctrl/Cmd + Z |
Undo |
Ctrl/Cmd + Shift + Z |
Redo |
Space |
Play / Pause |
Shaders are composed at runtime from effect blocks. Each effect is a self-contained GLSL module with $param placeholders that get replaced with instance-scoped uniform names. The composer (src/composer.ts) assembles the final fragment shader by sorting effects by category and order, deduplicating shared utility functions (hash, noise and fbm in 2-D and 3-D, plus drift for slow quasi-periodic motion), and emitting the combined GLSL.
- React 19 — UI layer
- Zustand — State management with undo/redo
- Motion — Animations and physical drag-and-drop reorder
- Vite — Dev server and build
- TypeScript — Type safety
- CodeMirror 6 — Code viewer
- WebGL — Shader rendering
MIT