Shader Lab
01.What a shader is

What a shader is

Arc 1 · Mental Model · Lesson 1 of 35
coordinate signal color
1

Purpose

A shader is one function that runs once per pixel, in parallel across the whole screen, with no knowledge of neighboring pixels or past frames.

Key insight

A painter paints the whole canvas in sequence, remembering what came before. The GPU doesn't work like that. It calls the same function for every pixel simultaneously. Each pixel knows only its own coordinate and the shared uniforms (like time). A pixel cannot see the pixel next to it.

When effects need neighbor information (blur, bloom, edge detection), that requires a second pass that samples the first pass's output as a texture. This is called multi-pass rendering — and it's how shaders get around their in-pixel blindness.

Break it

Drag pixel-size up to 64, then click pause time. Every "pixel" on screen becomes a single solid color, frozen. That one solid value is literally the output of one function call. Now click resume — every block changes together because they all share the time uniform.

Teaches: pixels are isolated in space but synchronized through uniforms. "Per-pixel parallel" is what a shader is.

Direct Claude

This lesson is conceptual — the language of art direction arrives in Lesson 2. Two useful phrases you'll pick up here:

"per-pixel" the shader is independent per pixel; no neighbor reads "multi-pass" second pass reads the first pass's output as a texture; how blur/bloom work
Briefing tip: when an effect needs to "look at neighbors" (blur, ripple, dilation), that's a multi-pass request, not a single shader.
Combines with: Lesson 2 (where the three layers live inside that one per-pixel function).
the fragment shader running above
uniform float u_pixelSize;

void main() {
  // Where on screen is this pixel?
  vec2 uv = gl_FragCoord.xy / u_resolution;

  // Snap UV to a coarse grid (if pixel-size > 1).
  // Every pixel in the same block reads the same snapped position.
  float p = max(1.0, u_pixelSize);
  vec2 snapped = floor(uv * u_resolution / p) * p / u_resolution;

  // Compute a color from the snapped coordinate + time.
  // Every pixel runs this same math independently.
  vec3 col = 0.5 + 0.5 * cos(u_time + snapped.xyx * vec3(12.0, 9.0, 6.5) + vec3(0.0, 2.0, 4.0));

  gl_FragColor = vec4(col, 1.0);
}