The Value Pipeline
Generate, normalize, shape, map
The most universal composition pattern in creative coding is the value pipeline: generate a sequence of raw values, normalize them to the 0–1 range, shape the distribution with an easing curve, then map the result onto your target range.
Each step has a single job. Linspace generates evenly spaced numbers — say 0 through 10. Normalize squashes them into 0–1, making the data range-agnostic. Ease reshapes the linear ramp into a curve — here a quadratic ease-in that compresses values toward the low end. Finally, lerp maps the shaped 0–1 values onto a target range — pixel positions, opacities, stroke widths, whatever your design needs.
This is the backbone of nearly every procedural pattern. Spacing that accelerates toward an edge, opacity that fades out with a soft curve, stroke widths that taper — they all follow this four-step chain. Once you internalize it, you'll see it everywhere.
Spacing that accelerates toward an edge, opacity that fades out with a soft curve, stroke widths that taper — they all follow this four-step chain.
The Four Stages
- 01 Linspace
Generates the raw sequence. “I need 10 items labeled 0 through 10.” These are your loop indices or grid coordinates.
- 02 Normalize
Squashes the data into a standard 0.0 to 1.0 format. This makes the data range-agnostic. It doesn’t matter if your input was 0–10 or 500–1000; it’s now a percentage.
- 03 Ease
The artistic soul of the pipeline. By applying a power function (like t²) to the normalized value, you cluster numbers towards 0 or 1, creating organic rhythm from linear data.
- 04 Lerp (Linear Interpolate)
The projection phase. Takes the shaped 0–1 value and projects it onto your final design constraints (screen width, color channels, rotation degrees).
const count = 10;
for (let i = 0; i < count; i++) {
// 1. Linspace — generate raw sequence
const val = i;
// 2. Normalize — squash to 0–1
let t = (val - 0) / (count - 1);
// 3. Ease — shape the curve (Quadratic In: t²)
t = t * t;
// 4. Lerp — project onto target range
const x = 20 + t * (800 - 20);
}