home/ modules/ animating-procedural-patterns-with-sine-and-time

Animated procedural patterns with sine, time, and smoothstep

  • learner can drive looping motion with sine and time using bias/gain to map into color range
  • learner can turn time oscillators into spatial patterns via UV coordinates
  • learner can use smoothstep to control thresholds and anti-alias procedural edges
  • learner can layer octaves of sine to add fine detail to a pattern

Produce a looping animated GLSL pattern that combines UV-driven spatial variation, sine-and-time motion, layered octaves, and smoothstep-thresholded edges into a seamless tile.

This module builds the bread-and-butter move of live-coded visuals: a fragment shader that breathes. In a VJ or algorave rig, an animated procedural tile is what fills the screen between bolder moves — it must loop seamlessly (no pops when the projector wraps it), pulse in time, and hold up at any resolution. Everything here runs on a stock Shadertoy-style setup: one fragment shader, iTime, UV coordinates, nothing else.

The arc starts fully supported. First, get a single color channel pulsing: feed time into sine, then apply the bias-and-gain mapping so the −1..+1 oscillation lands cleanly in 0–1 instead of clamping black for half the cycle. Next, swap the constant frequency for a UV coordinate — the moment a time oscillator becomes a spatial pattern is the conceptual pivot of the whole module. From there, two refinement passes: use smoothstep with adjustable limits to carve the smooth sine field into deliberate light/dark regions with anti-aliased edges instead of jagged step cuts, and add a second sine octave at double frequency and half amplitude to break the pattern’s machine-like regularity. The capstone then removes the scaffolding: you design your own tile that must exhibit all four techniques at once and loop without a visible seam.

The required atoms are exactly the capstone’s load-bearing skills — drop any one and the tile fails visibly (black flicker, flat field, jagged edges, or sterile regularity). The supporting atoms widen the palette rather than gate it: aliased high-frequency sine for pseudo-random seeding, the step→smoothstep replacement at SDF boundaries, and 1/x neon falloff are ready-made detours once the core tile works. Note the deliberate split between the two smoothstep atoms: the required smoothstep-anti-aliasing is the general concept the capstone gates — smoothstep as a two-threshold transition that anti-aliases procedural edges — while the supporting smoothstep-antialiasing is a narrower procedure (swapping step() for smoothstep() at an SDF boundary to get fringe and glow effects), useful only if your tile detours through SDF shapes. The two are near-duplicates at the corpus level and are candidates for consolidation into one canonical atom. Bias/gain mapping and smoothstep threshold tuning recur in nearly every edit, so drill them inside the whole task until they are reflexive.

Walkthrough

The bread-and-butter of live visuals: a shader that breathes — an animated procedural tile that loops seamlessly and pulses in time. Paste each into The Book of Shaders editor (u_time is the running clock — Shadertoy calls the same thing iTime). Each is a complete shader.

1 — a channel pulsing in time. Feed u_time into sin, but a raw sine is −1..1 — and negative values clamp to black for half the cycle. The bias-and-gain map *0.5 + 0.5 lands it cleanly in 0..1 ([[sine-animation-time]], [[glsl-sine-bias-gain]]).

precision mediump float;
uniform float u_time;
void main() {
  float v = sin(u_time) * 0.5 + 0.5;   // 0..1, no black half-cycle
  gl_FragColor = vec4(vec3(v), 1.0);
}

2 — time becomes space (the pivot). Swap the constant frequency for a UV coordinate: sin(uv.x * 20.0 + u_time) makes moving stripes — a spatial pattern that also animates. This is the conceptual turn of the whole module ([[glsl-uv-coordinates-spatial-variation]]).

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  float v = sin(uv.x * 20.0 + u_time) * 0.5 + 0.5;
  gl_FragColor = vec4(vec3(v), 1.0);
}

3 — carve clean edges with smoothstep. A raw sine field is a mushy gradient; smoothstep(a, b, v) turns it into deliberate light/dark bands with anti-aliased edges (no jaggies) — two thresholds define the fringe width ([[smoothstep-anti-aliasing]], [[smoothstep-threshold]]).

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  float wave = sin(uv.x * 20.0 + u_time) * 0.5 + 0.5;
  float bands = smoothstep(0.45, 0.55, wave);   // crisp but anti-aliased
  gl_FragColor = vec4(vec3(bands), 1.0);
}

4 — a 2D field. Combine both axes — sin(x) + sin(y) — for an interference weave instead of flat stripes, each axis drifting at its own rate.

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  float v = sin(uv.x * 18.0 + u_time) + sin(uv.y * 18.0 - u_time * 0.7);
  v = v * 0.25 + 0.5;                            // bias/gain the sum into 0..1
  gl_FragColor = vec4(vec3(v), 1.0);
}

5 — octaves break the regularity. A single sine is machine-perfect and sterile. Add a second octave at double frequency and half amplitude and the pattern gains organic detail — the same trick as fBM ([[layered-sine-octaves]] if present).

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  float v = sin(uv.x * 10.0 + u_time);
  v += 0.5 * sin(uv.x * 20.0 + u_time * 1.5);   // 2× freq, 0.5× amp
  v = v * 0.33 + 0.5;
  gl_FragColor = vec4(vec3(v), 1.0);
}

6 — a seamless animated tile (the capstone). All four techniques: UV spatial variation, sine-and-time motion, layered octaves, and smoothstep edges. Multiplying the phase by 6.28318 (2π) keeps it seamless — the pattern wraps without a pop when the projector tiles it:

precision mediump float;
uniform vec2 u_resolution;
uniform float u_time;
void main() {
  vec2 uv = gl_FragCoord.xy / u_resolution;
  float TAU = 6.28318;
  float v = sin(uv.x * TAU + u_time);            // whole-cycle → seamless wrap
  v += 0.5 * sin(uv.y * TAU * 2.0 - u_time * 1.3);
  v = v * 0.33 + 0.5;
  float edge = smoothstep(0.4, 0.6, v);          // carved, anti-aliased
  vec3 col = mix(vec3(0.05, 0.1, 0.2), vec3(0.4, 0.9, 1.0), edge);
  gl_FragColor = vec4(col, 1.0);
}

What good looks like. A tile that loops with no visible pop (that’s the 2π/whole-cycle phase), pulses in musical time (sine of u_time), reads as organic rather than a barcode (the octaves), and has clean edges without jaggies (smoothstep). If it flickers to black, you skipped the bias/gain and half the sine is clamping; if edges are jagged, you used step instead of smoothstep; if it’s sterile, add another octave. This is the between-the-bolder-moves texture that fills a set. (Skill map: live-visualist Domain A3/C — procedural, time-driven shader patterns.)

Now make it yours. Change the octave ratio (try 3.0/0.33). Drive a colour channel with a different phase for chromatic drift. Warp the UV with uv += 0.1 * sin(uv.yx * TAU + u_time) before the pattern. Speed the loop by scaling u_time.

Runnable examples

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

oscillation

let y = height/2 + sin(frameCount * 0.05) * 100

p5live-0004 · CC0-1.0

float rings = abs(sin(length(uv)*20.0 - u_time*2.0));

glsl-0039 · public-domain

Atoms in this module

Required — these gate the capstone

A GLSL sine oscillator needs a bias and gain to map its -1/+1 range to 0-1 for color
Procedure L2 First instrument G
Animating shaders with the sine function and iTime creates smooth, looping motion without discontinuities
Concept L2 First instrument G
GLSL UV coordinates let shaders vary per-pixel, turning time oscillators into spatial patterns
Concept L2 First instrument G
smoothstep() creates smooth transitions between two thresholds, enabling anti-aliased edges in shaders
Concept L2 First instrument G
Smoothstep with adjustable limits controls where a procedural pattern transitions from dark to light
Concept L2 First instrument G
Adding a second sine octave at double frequency and half amplitude adds fine detail to procedural patterns
Concept L2 First instrument G

Supporting — enrichment, not gating

Aliased high-frequency sine waves produce pseudo-random variation suitable for per-instance seeding
Concept L2 First instrument G
Replacing step with smoothstep at an SDF boundary adds anti-aliasing and glow effects
Procedure L2 First instrument G
The 1/x function creates neon glow effects in shaders by producing extreme brightness near zero and a slow falloff
Concept L3 Craft G