SS
02ResearchJul 25, 2026 · 1 min read

Flowing noise fields with a single fragment shader

A practical walkthrough of building the animated green background on this site: simplex noise, fbm, and a fullscreen plane in react-three-fiber.

#webgl#shaders#three.js

The hero background is one mesh — a fullscreen plane with a custom fragment shader. No geometry, no lights, just math per pixel.

The recipe

  1. Render a plane that covers clip space (position.xy straight to gl_Position).
  2. Sample fractal Brownian motion (layered simplex noise) in the fragment shader.
  3. Map the noise value onto a three-stop green gradient.
  4. Drift the sample coordinates over uTime and nudge them with the pointer.

fbm in a nutshell

float fbm(vec2 p){
  float value = 0.0;
  float amp = 0.5;
  for (int i = 0; i < 5; i++){
    value += amp * snoise(p);
    p *= 2.0;      // higher frequency
    amp *= 0.5;    // lower amplitude
  }
  return value;
}

Each octave adds finer detail. Five octaves is plenty for a soft, cloudy field.

Findings

  • DPR matters. Clamp dpr to [1, 1.75]; beyond that the GPU cost jumps with little visual gain.
  • Lerp the pointer. Feeding raw pointer values makes the motion jittery; smoothing with a small lerp factor (0.04) feels alive but calm.
  • Respect reduced motion. Swap the canvas for a static gradient when the user asks for less movement.

The whole effect is a few dozen lines of GLSL. The restraint is in the palette, not the complexity.