Orientation: the fragment shader as a per-pixel color function
Learning objectives
- 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
Capstone — one whole task that evidences the objectives
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
Supporting — enrichment, not gating
Part of curricula
- Generative & AI AV Artist — real-time machine-driven performance — Orient the machine collaborator & ship a first ML AV artefact recommended
- Live Visualist — zero to performing live-coded & generative visuals — Reactive & procedural — make it listen, and go to the GPU required
- Shader Artist — real-time GPU craft to a demoscene-grade visual — The fragment shader as a per-pixel instrument required
Unlocks — modules that require this one