Author

Steve Trettel

Published

January 2026

1 Day 1 Code

This appendix provides complete, standalone code for each shader referenced in Day 1. Each listing can be copied directly into Shadertoy and run immediately.

1.1 red

The simplest shader: every pixel is red.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

1.2 half-plane-pixels

Dividing the screen using raw pixel coordinates, before we learn the coordinate transformation.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec3 color;
    if (fragCoord.x < iResolution.x / 2.0) {
        color = vec3(1.0, 0.0, 0.0);  // red on left
    } else {
        color = vec3(0.0, 0.0, 1.0);  // blue on right
    }
    
    fragColor = vec4(color, 1.0);
}

1.3 coordinates

Visualizing the coordinate system as color.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    fragColor = vec4(uv.x, uv.y, 0.0, 1.0);
}

1.4 half-plane

Dividing the plane into two regions based on y-coordinate.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float L = p.y;
    
    vec3 color;
    if (L < 0.0) {
        color = vec3(1.0, 0.0, 0.0);  // red below
    } else {
        color = vec3(0.0, 0.0, 1.0);  // blue above
    }
    
    fragColor = vec4(color, 1.0);
}

1.5 circle

Filled circle centered at the origin.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float d = length(p);
    float r = 1.0;
    float f = d - r;
    
    vec3 color;
    if (f < 0.0) {
        color = vec3(1.0, 1.0, 0.0);  // yellow inside
    } else {
        color = vec3(0.1, 0.1, 0.3);  // dark blue outside
    }
    
    fragColor = vec4(color, 1.0);
}

1.6 circle-ring

Circle outline (ring) centered at the origin.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float d = length(p);
    float r = 1.0;
    float eps = 0.1;
    float f = abs(d - r) - eps;
    
    vec3 color;
    if (f < 0.0) {
        color = vec3(1.0, 1.0, 0.0);  // yellow ring
    } else {
        color = vec3(0.1, 0.1, 0.3);  // dark background
    }
    
    fragColor = vec4(color, 1.0);
}

1.7 circle-pulsing

Circle with radius that oscillates over time. Introduces iTime.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float d = length(p);
    float r = 1.0 + 0.5 * sin(iTime);  // radius oscillates between 0.5 and 1.5
    float f = d - r;
    
    vec3 color;
    if (f < 0.0) {
        color = vec3(1.0, 1.0, 0.0);  // yellow inside
    } else {
        color = vec3(0.1, 0.1, 0.3);  // dark background
    }
    
    fragColor = vec4(color, 1.0);
}

1.8 parabola

The parabola \(y = x^2\) rendered as an implicit curve.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float F = p.y - p.x * p.x;
    float eps = 0.1;
    
    vec3 color;
    if (abs(F) < eps) {
        color = vec3(1.0, 1.0, 0.0);  // yellow curve
    } else {
        color = vec3(0.1, 0.1, 0.3);  // dark background
    }
    
    fragColor = vec4(color, 1.0);
}

1.9 lemniscate-naive

Lemniscate of Bernoulli with naive thresholding (non-uniform thickness).

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float a = 1.5;
    float r2 = dot(p, p);
    float F = r2 * r2 - a * a * (p.x * p.x - p.y * p.y);
    
    float eps = 0.15;
    
    vec3 color;
    if (abs(F) < eps) {
        color = vec3(1.0, 1.0, 0.0);
    } else {
        color = vec3(0.1, 0.1, 0.3);
    }
    
    fragColor = vec4(color, 1.0);
}

1.10 lemniscate-gradient

Lemniscate with gradient correction for uniform thickness.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float a = 1.5;
    float r2 = dot(p, p);
    float F = r2 * r2 - a * a * (p.x * p.x - p.y * p.y);
    
    vec2 grad = vec2(
        4.0 * p.x * r2 - 2.0 * a * a * p.x,
        4.0 * p.y * r2 + 2.0 * a * a * p.y
    );
    
    float dist = abs(F) / max(length(grad), 0.01);
    float eps = 0.05;
    
    vec3 color;
    if (dist < eps) {
        color = vec3(1.0, 1.0, 0.0);
    } else {
        color = vec3(0.1, 0.1, 0.3);
    }
    
    fragColor = vec4(color, 1.0);
}

1.11 lemniscate-animated

Cassini ovals animated through the lemniscate transition.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    // Cassini oval parameters
    float c = 1.0;  // half-distance between foci
    float a = 0.8 + 0.4 * sin(iTime * 0.5);  // animate through transition
    
    // Implicit equation: (x² + y²)² - 2c²(x² - y²) = a⁴ - c⁴
    float r2 = dot(p, p);
    float c2 = c * c;
    float a4 = a * a * a * a;
    float c4 = c2 * c2;
    float F = r2 * r2 - 2.0 * c2 * (p.x * p.x - p.y * p.y) - (a4 - c4);
    
    // Gradient
    vec2 grad = vec2(
        4.0 * p.x * r2 - 4.0 * c2 * p.x,
        4.0 * p.y * r2 + 4.0 * c2 * p.y
    );
    
    float dist = abs(F) / max(length(grad), 0.01);
    float eps = 0.05;
    
    vec3 color;
    if (dist < eps) {
        color = vec3(1.0, 1.0, 0.0);
    } else {
        color = vec3(0.1, 0.1, 0.3);
    }
    
    fragColor = vec4(color, 1.0);
}

1.12 circle-mouse

Circle that follows the mouse position.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    // Normalize fragment coordinate
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    // Normalize mouse coordinate the same way
    vec2 mouse = iMouse.xy / iResolution.xy;
    mouse = mouse - vec2(0.5, 0.5);
    mouse.x *= iResolution.x / iResolution.y;
    mouse = mouse * 4.0;
    
    // Circle centered at mouse
    float d = length(p - mouse);
    float r = 0.5;
    
    vec3 color;
    if (d < r) {
        color = vec3(1.0, 0.9, 0.2);
    } else {
        color = vec3(0.1, 0.1, 0.3);
    }
    
    fragColor = vec4(color, 1.0);
}

1.13 sun-earth

Sun at mouse click position with orbiting earth.

vec2 normalize_coord(vec2 coord) {
    vec2 uv = coord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    return uv * 4.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 p = normalize_coord(fragCoord);
    
    // Sun follows mouse position
    vec2 sun = normalize_coord(iMouse.xy);
    
    // Earth orbits the sun
    float orbit_radius = 0.8;
    vec2 earth = sun + orbit_radius * vec2(cos(iTime), sin(iTime));
    
    // Draw sun (larger, yellow)
    float d_sun = length(p - sun);
    // Draw earth (smaller, blue)
    float d_earth = length(p - earth);
    
    vec3 color = vec3(0.02, 0.02, 0.05);  // dark background
    if (d_sun < 0.3) {
        color = vec3(1.0, 0.9, 0.2);  // yellow sun
    }
    if (d_earth < 0.15) {
        color = vec3(0.2, 0.5, 1.0);  // blue earth
    }
    
    fragColor = vec4(color, 1.0);
}

1.14 folium-mouse

Folium of Descartes with mouse-controlled level set.

vec2 normalize_coord(vec2 coord) {
    vec2 uv = coord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    return uv * 4.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 p = normalize_coord(fragCoord);
    
    // Fixed parameter a
    float a = 1.5;
    
    // Map mouse x to level set value c in [-2, 2]
    float c = mix(-2.0, 2.0, iMouse.x / iResolution.x);
    
    // Folium of Descartes: x³ + y³ - 3axy = c
    float F = p.x*p.x*p.x + p.y*p.y*p.y - 3.0*a*p.x*p.y - c;
    
    // Gradient: ∇F = (3x² - 3ay, 3y² - 3ax)
    vec2 grad = vec2(3.0*p.x*p.x - 3.0*a*p.y, 3.0*p.y*p.y - 3.0*a*p.x);
    float dist = abs(F) / max(length(grad), 0.01);
    
    vec3 color;
    if (dist < 0.05) {
        color = vec3(1.0, 1.0, 0.0);
    } else {
        color = vec3(0.1, 0.1, 0.3);
    }
    
    fragColor = vec4(color, 1.0);
}

1.15 elliptic-curve

Single elliptic curve with mouse-controlled parameters. Colors by topology: gold (one component), blue (two components), red (singular).

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    // Mouse controls (a, b) parameters
    float a = mix(-2.0, 1.0, iMouse.x / iResolution.x);
    float b = mix(-2.0, 2.0, iMouse.y / iResolution.y);
    
    // Discriminant: 4a³ + 27b²
    float disc = 4.0 * a * a * a + 27.0 * b * b;
    
    // Elliptic curve: y² = x³ + ax + b
    float F = p.y * p.y - p.x * p.x * p.x - a * p.x - b;
    vec2 grad = vec2(-3.0 * p.x * p.x - a, 2.0 * p.y);
    float dist = abs(F) / max(length(grad), 0.01);
    
    vec3 bg = vec3(0.05, 0.05, 0.1);
    vec3 color = bg;
    
    if (dist < 0.05) {
        // Color by topology
        if (abs(disc) < 0.3) {
            color = vec3(1.0, 0.2, 0.2);   // red for singular
        } else if (disc > 0.0) {
            color = vec3(1.0, 0.85, 0.3);  // gold for one component
        } else {
            color = vec3(0.3, 0.5, 0.8);   // blue for two components
        }
    }
    
    fragColor = vec4(color, 1.0);
}

1.16 elliptic-family

Family of elliptic curves with mouse-controlled parameters. Gold for one component, blue for two components, red for singular. Curves fade with distance from center.

vec2 normalize_coord(vec2 coord) {
    vec2 uv = coord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    return uv * 4.0;
}

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 p = normalize_coord(fragCoord);
    
    // Mouse picks (a, b) in parameter space
    float a = mix(-2.0, 1.0, iMouse.x / iResolution.x);
    float b_center = mix(-2.0, 2.0, iMouse.y / iResolution.y);
    
    vec3 color = vec3(0.05, 0.05, 0.1);
    
    vec3 oneComponent = vec3(1.0, 0.85, 0.3);   // gold
    vec3 twoComponent = vec3(0.3, 0.5, 0.8);    // blue
    vec3 singularColor = vec3(1.0, 0.2, 0.2);   // red
    
    for (int j = -15; j <= 15; j++) {
        float b = b_center + float(j) * 0.15;
        
        float dist_from_center = abs(float(j));
        
        // Discriminant: 4a³ + 27b²
        float disc = 4.0 * a * a * a + 27.0 * b * b;
        
        float F = p.y * p.y - p.x * p.x * p.x - a * p.x - b;
        vec2 grad = vec2(-3.0 * p.x * p.x - a, 2.0 * p.y);
        float dist = abs(F) / max(length(grad), 0.01);
        
        float thickness = 0.05 / (1.0 + dist_from_center * 0.8);
        
        // Color by topology
        vec3 curveColor;
        if (abs(disc) < 0.3) {
            curveColor = singularColor;
        } else if (disc > 0.0) {
            curveColor = oneComponent;
        } else {
            curveColor = twoComponent;
        }
        
        float brightness = 1.0 / (1.0 + dist_from_center * 0.4);
        curveColor *= brightness;
        
        if (dist < thickness) {
            color = curveColor;
        }
    }
    
    fragColor = vec4(color, 1.0);
}

1.17 grid-circles

Grid of circles with square cells.

void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    vec2 p = uv * 4.0;
    
    float aspect = iResolution.x / iResolution.y;
    float N = 5.0;  // number of columns
    float L = (4.0 * aspect) / N;  // cell size
    
    vec2 cell_id = floor(p / L);
    vec2 cell_p = mod(p + vec2(L/2.0, L/2.0), L) - vec2(L/2.0, L/2.0);
    
    // Checkerboard background
    float checker = mod(cell_id.x + cell_id.y, 2.0);
    vec3 bg = mix(vec3(0.15, 0.15, 0.25), vec3(0.25, 0.15, 0.15), checker);
    
    // Circle in each cell
    float d = length(cell_p);
    float r = L * 0.35;
    
    vec3 color;
    if (d < r) {
        color = vec3(1.0, 1.0, 0.0);
    } else {
        color = bg;
    }
    
    fragColor = vec4(color, 1.0);
}

1.18 Notes

Coordinate Setup

Most shaders use this standard coordinate setup:

vec2 uv = fragCoord / iResolution.xy;   // normalize to [0,1]
uv = uv - vec2(0.5, 0.5);               // center origin
uv.x *= iResolution.x / iResolution.y;  // aspect correction
vec2 p = uv * 4.0;                      // scale to [-2, 2] range

Helper Function

For shaders using mouse input, we define:

vec2 normalize_coord(vec2 coord) {
    vec2 uv = coord / iResolution.xy;
    uv = uv - vec2(0.5, 0.5);
    uv.x *= iResolution.x / iResolution.y;
    return uv * 4.0;
}

Gradient Correction

For implicit curves \(F(x,y) = 0\) with uniform thickness:

float dist = abs(F) / max(length(grad), 0.01);

where grad is \(\nabla F\) computed analytically.