Pixelation / downscale
Purpose
You can change what each pixel looks up — snapping many neighboring pixels to the same address makes them all read the same color, producing chunky blocks. This is the first and simplest thing the coordinate layer ever does.
Key insight
Every pixel is an independent function call (Lesson 1) asking the scene for a color at its UV. If you round that UV down to the nearest cell of a coarse grid before asking, every pixel inside that cell sends the same address and gets the same answer. The output looks low-resolution, but nothing about the scene itself has changed — only the address each pixel hands in.
This is the simplest lesson in the arc about the coordinate layer's power: transform the address, change the result, even with the rest of the shader untouched.
Break it
Drag chunk slowly from 1 to 128 and back. At every point, notice that the image isn't blurring — it's being replaced by a grid of increasingly large solid squares. Teaches: pixelation isn't low-pass filtering; it's under-sampling. The colors you see at chunk = 40 are not averages of the block — they're one arbitrary pixel inside the block, read 40×40 times. This is why naive downscaling looks harsh; a production pixelation pass usually averages first.
Direct Claude
fract is the primitive this lesson is a special case of).
uniform float u_chunk;
vec3 scene(vec2 uv) {
vec3 col = mix(vec3(0.18, 0.10, 0.28), vec3(0.95, 0.48, 0.32), uv.y);
col = mix(col, vec3(0.25, 0.60, 0.85), smoothstep(0.55, 0.98, uv.y));
float sun = 1.0 - smoothstep(0.09, 0.11, length(uv - vec2(0.5, 0.55)));
col = mix(col, vec3(1.0, 0.93, 0.68), sun);
float mntn = 0.40 + 0.05 * sin(uv.x * 18.0) + 0.08 * sin(uv.x * 5.0 + 2.0);
col = mix(col, vec3(0.10, 0.06, 0.20), step(uv.y, mntn) * step(uv.y, 0.5));
if (uv.y < 0.5) {
float yy = (0.5 - uv.y);
float hz = smoothstep(0.004, 0.0, abs(fract(pow(yy, 0.7) * 8.0 - u_time * 0.25) - 0.5));
float vl = smoothstep(0.004, 0.0, abs(fract((uv.x - 0.5) / max(yy, 0.02) * 4.0) - 0.5));
col = mix(col, vec3(0.95, 0.30, 0.75), max(hz, vl) * 0.9);
}
return col;
}
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
// COORDINATE LAYER — snap the UV to a chunk-sized grid before sampling.
// Every pixel in the same chunk sends the same address and gets the same color.
float p = max(1.0, u_chunk);
vec2 snapped = floor(gl_FragCoord.xy / p) * p / u_resolution;
vec3 col = scene(snapped);
gl_FragColor = vec4(col, 1.0);
}