home/ modules/ orient-shaders-as-pixel-functions

Orientation: the fragment shader as a per-pixel color function

  • learner can explain that a fragment shader runs in parallel and maps each pixel coordinate to an RGB color
  • learner can normalize gl_FragCoord to UV space and visualize the coordinate field as a gradient
  • learner can locate the Book of Shaders standard-uniform conventions (u_resolution/u_mouse/u_time) as a reference anchor

Write your first Book-of-Shaders GLSL fragment shader that fills the canvas with a UV-as-RGB gradient driven by u_resolution, and annotate it explaining the per-pixel parallel model.

In a live-visuals rig — Hydra, a Shadertoy tab, or a GLSL layer behind your TidalCycles set — everything you will ever project starts from one idea: the fragment shader is a tiny pure function that the GPU calls once per pixel, millions of times per frame, in parallel. This module builds toward writing that first shader yourself: a canvas-filling gradient where the coordinate field itself becomes the image, annotated in your own words so the mental model sticks before any club-ready patching begins.

The arc is deliberately gentle. Start in the Book of Shaders live editor with its default template already running, and lean on two just-in-time how-tos: “Dividing gl_FragCoord by u_resolution maps pixel coordinates to the [0,1] UV range” gives you the one line that opens nearly every shader you will ever write, and “Mapping UV coordinates directly to RGB channels visualizes the coordinate space as a gradient” turns that abstract space into something you can see and debug. From there, strip the template and rebuild it blank-page for the capstone, pulling the standard-uniform conventions (u_resolution, u_mouse, u_time) from the fact atom rather than from memory.

The required atoms gate the capstone directly: you cannot write the gradient without normalization and the UV-to-RGB mapping, cannot wire it without the standard uniforms, and cannot honestly annotate the parallel model without the pixel-color-function and massively-parallel concepts. The supporting atoms enrich the picture without gating the work: the free PBR textbook is worth bookmarking as a long-term theory anchor, and triangles-as-the-only-GPU-primitive foreshadows what the GPU is actually rasterizing in the vertex-buffer world ahead — but nothing in the capstone depends on either yet.

Walkthrough

The mental model first: a fragment shader is one tiny function the GPU runs once per pixel, in parallel — you don’t loop over pixels, you describe the colour of a pixel and the GPU does millions at once. Paste each shader into The Book of Shaders editor and it runs live. Each step is a complete shader.

1 — every pixel, one colour. The simplest shader: return the same colour for every pixel. gl_FragColor is the output (r, g, b, a). This one function is being run for every pixel simultaneously — that’s the whole GPU idea ([[shader-as-pixel-color-function]], [[gpu-shader-massively-parallel]]).

precision mediump float;
void main() {
  gl_FragColor = vec4(1.0, 0.2, 0.0, 1.0);   // orange, everywhere
}

2 — where am I? normalize the coordinate. gl_FragCoord.xy is the pixel’s position in pixels; dividing by u_resolution maps it to the [0,1] UV range — the one line that opens nearly every shader ([[glsl-coordinate-normalization]], [[glsl-standard-uniforms]]).

precision mediump float;
uniform vec2 u_resolution;
void main() {
  vec2 st = gl_FragCoord.xy / u_resolution;   // 0..1 across the canvas
  gl_FragColor = vec4(st.x, 0.0, 0.0, 1.0);   // red grows left→right
}

3 — the coordinate field is the image. Put st.x in red and st.y in green and you see the coordinate space: black at bottom-left (0,0), red→right, green→up, yellow top-right. You’re visualising the input, the single best shader-debugging move ([[uv-as-rgb]]).

precision mediump float;
uniform vec2 u_resolution;
void main() {
  vec2 st = gl_FragCoord.xy / u_resolution;
  gl_FragColor = vec4(st.x, st.y, 0.0, 1.0);
}

4 — the UV-as-RGB gradient (the capstone). Add a third channel and every pixel’s colour is a pure function of its position — a smooth two-axis gradient computed independently at every pixel, no loops, no state. Annotate it: this runs per-pixel, in parallel; st is where I am; the output is who I am ([[uv-as-rgb]], [[shader-as-pixel-color-function]]):

precision mediump float;
uniform vec2 u_resolution;
void main() {
  vec2 st = gl_FragCoord.xy / u_resolution;   // normalized position, [0,1]
  vec3 color = vec3(st.x, st.y, 0.5);         // x→red, y→green, constant blue
  gl_FragColor = vec4(color, 1.0);            // this pixel's final colour
}

What good looks like — and the mental model that must stick. A clean corner-to-corner gradient means you’ve internalized the two ideas that unlock everything: (1) the shader is a pure per-pixel function — same input position always gives the same colour, and the GPU evaluates it everywhere at once; (2) the coordinate is your raw material — every pattern, shape, and effect you’ll ever write starts by transforming st. If you’re tempted to “draw” or “loop over pixels”, stop — you only ever describe one pixel. (Skill map: live-visualist Domain A3 — the fragment shader as a per-pixel colour function.)

Now make it yours. Swap the channels (st.y, st.x, 0.5) and watch the gradient rotate. Multiply st by a number before using it (st * 2.0) — what happens past 1.0? Use u_mouse / u_resolution for the blue channel to make it interactive. Try gl_FragColor = vec4(vec3(st.x), 1.0) for a pure black→white ramp.

Runnable examples

Generated from the context/ instrument corpus by concept (redistributable idioms only). Do not edit — regenerate with gen-module-examples.mjs.

gradient-ramp

gradient(0.3).out()

hydra-0170 · MIT

[fr, fr*0.5, 1-fr] >> rgb

punctual-0033 · CC0-1.0

Atoms in this module

Required — these gate the capstone

A GLSL fragment shader is a function that maps each pixel's (x,y) coordinate to an output RGB color, run in parallel for every pixel
Concept L1 Foundations G
Dividing gl_FragCoord by u_resolution maps pixel coordinates to the [0,1] UV range
Procedure L1 Foundations G
Mapping UV coordinates directly to RGB channels visualizes the coordinate space as a gradient
Concept L1 Foundations G
GPU shaders run massively in parallel — individual invocations cannot communicate with or observe each other within a pass
Concept L1 Foundations G
The Book of Shaders defines three standard uniforms: u_resolution, u_mouse, and u_time
Fact L1 Foundations G

Supporting — enrichment, not gating

Physically Based Rendering is a free CC-licensed textbook coupling rendering theory with a full implementation
Fact L0 Orientation G
GPUs work exclusively with triangles, lines, and points — all geometry must be decomposed into triangles before drawing
Concept L1 Foundations G