Shader Playground
Interactive visual experiments with raw GPU shaders.
Live Demo
The Problem
Shaders are everywhere — games, visualizations, even this portfolio's landing page. But learning shaders is hard. The feedback loop is slow, errors are cryptic, and most tutorials assume graphics programming background.
I wanted to build a playground where you can experiment with shaders interactively, see results immediately, and learn through exploration.
The Connection
The connection to my background might seem strange, but it's real:
- Wiring diagrams — Electrical schematics are visual languages that describe flow and transformation. Shaders do the same with data.
- Welding arcs — The blue-white glow of a TIG arc, the way molten metal flows — these are visual phenomena I've studied closely.
- Instrument panels — Analog gauges with their sweeping needles and backlit displays inspired many shader effects.
The Approach
No framework abstraction — this is raw WebGL and WebGPU. The goal is to understand what's actually happening on the GPU.
The playground provides: - Live GLSL editor with syntax highlighting - Uniform controls (sliders, color pickers) - Texture inputs - Frame-by-frame stepping for debugging
Technical Deep Dive
The core is a WebGL context with hot shader reloading. When you edit code, it compiles and links a new shader program, then swaps it without losing state.
Error handling was crucial — GLSL compile errors are notoriously unhelpful. The playground parses error messages and highlights the offending line in the editor.
// Hot shader reloading
function updateShader(fragmentSource: string) {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
const error = gl.getShaderInfoLog(shader);
throw new ShaderCompileError(parseGLSLError(error));
}
// Link new program, preserve uniforms
const newProgram = linkProgram(vertexShader, shader);
copyUniforms(currentProgram, newProgram);
currentProgram = newProgram;
}Hot shader reloading with uniform preservation
What I Learned
What worked well:
What I'd change:
Trade-offs accepted: