Skip to content
Sample of Perlin Noise Flow Field

shiffman_pearson_textbook · perlinFlowField

Perlin Noise Flow Field

A 2-D scalar field of Perlin gradient noise is sampled on a coarse grid; each cell is assigned a heading theta = 2*pi * n. Particles emit at random positions, look up their cell's heading each tick, and step a small velocity along it. Their (prev -> current) segments are stamped onto the canvas with a low-alpha blend, producing the classic Shiffman 'flow-field' organic-ink visualization. Particles that leave the canvas respawn at fresh random positions.

Original: https://natureofcode.com/autonomous-agents/

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
shiffman_pearson_textbook
Source
shiffman · pearson
Evolution
flow_field
Render
trail_accumulation
Complexity
medium
Agents
800
Year
2012
Author
Daniel Shiffman (Nature of Code Ch. 6 'Autonomous Agents', flow-following example); noise by Ken Perlin (1985)

Math essence

For each particle (x, y): theta = 2*pi * perlin(x*scale, y*scale, ...) [with octaves summed at half amplitude each]. Step: (x', y') = (x, y) + (cos theta, sin theta) * speed. Trail: canvas[p] = (1 - alpha) * canvas[p] + alpha * ink. Per-pixel Perlin: shuffled 64-permutation + random unit gradients + Ken-Perlin fade t^3(t(6t - 15) + 10).

Parameters

Name Type Default Range Description
dim int 360 200–1200 Square canvas side length.
num_particles int 800 50–8000 Tracer particle count.
cell_size int 20 4–80 Grid cell size (visual reference; sampling is bilinear).
noise_scale float 0.08 0.005–0.5 Spatial frequency of the noise; lower = larger structures.
octaves int 1 1–4 Number of Perlin octaves summed into the heading.
particle_speed float 1.6 0.2–6 Pixels per tick.
line_alpha float 0.1 0.01–0.5 Trail opacity per stamp.
bg_color tuple 245,240,230 — Background canvas color.
ink_color tuple 35,50,90 — Trail ink color.
seed int null 0–999999

Reference

First 60 lines of reference.py. Full source: library_external/shiffman_pearson_textbook/perlinFlowField/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _fade(t: np.ndarray) -> np.ndarray:
    return t * t * t * (t * (t * 6 - 15) + 10)


def _make_perlin(rng: np.random.Generator, size: int):
    perm = np.arange(size, dtype=np.int32)
    rng.shuffle(perm)
    perm = np.concatenate([perm, perm])
    angles = rng.uniform(0.0, 2.0 * np.pi, size=(size + 1, size + 1))
    grads = np.stack([np.cos(angles), np.sin(angles)], axis=-1).astype(np.float32)
    return perm, grads


def perlin2(x: np.ndarray, y: np.ndarray, perm: np.ndarray, grads: np.ndarray) -> np.ndarray:
    s = grads.shape[0] - 1
    x = np.mod(x, s).astype(np.float32)
    y = np.mod(y, s).astype(np.float32)
    xi = x.astype(np.int32)
    yi = y.astype(np.int32)
    xf = x - xi
    yf = y - yi
    u = _fade(xf)
    v = _fade(yf)
    x1 = np.clip(xi + 1, 0, s)
    y1 = np.clip(yi + 1, 0, s)
    g00 = grads[yi, xi]
    g10 = grads[yi, x1]
    g01 = grads[y1, xi]
    g11 = grads[y1, x1]
    d00 = xf * g00[..., 0] + yf * g00[..., 1]
    d10 = (xf - 1) * g10[..., 0] + yf * g10[..., 1]
    d01 = xf * g01[..., 0] + (yf - 1) * g01[..., 1]
    d11 = (xf - 1) * g11[..., 0] + (yf - 1) * g11[..., 1]
    nx0 = d00 + u * (d10 - d00)
    nx1 = d01 + u * (d11 - d01)
    return nx0 + v * (nx1 - nx0)


class PerlinFlowField:
    """Perlin-noise flow field following Shiffman, Nature of Code Ch. 6 / Coding Train.

    A scalar noise field n(x, y) is sampled on an integer grid of step size
    ``cell_size``; the per-cell heading is ``theta = 2*pi * n``. Particles emit
    at random positions, sample the heading at their current cell by bilinear
    interpolation, and step a small velocity. Trail segments are accumulated
    onto the canvas with a low-alpha blend. When a particle leaves the canvas
    it respawns at a fresh random position. The step(n) call advances the
    simulation n ticks; render() returns the running canvas.

    The flow-field is the canonical Nature of Code example: Perlin's gradient
    noise (1985) drives a non-divergent, smoothly varying 2-D vector field
    that produces the classic organic ink-trail look.
    """

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/shiffman_pearson_textbook/perlinFlowField/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from shiffman · pearson

Sample of Genetic Algorithm (Evolve Toward Target String)

Genetic Algorithm (Evolve Toward Target String)

shiffman_pearson_textbook · geneticAlgorithmString

A textbook genetic algorithm that evolves a population of binary strings toward a target ASCII string (default 'HELLO WORLD!').

View →
Sample of Lindenmayer L-System (Textbook Formulation)

Lindenmayer L-System (Textbook Formulation)

shiffman_pearson_textbook · lindenmayerTextbook

Lindenmayer L-system string rewriting with a 2-D turtle interpreter, the canonical textbook formulation used in both Shiffman's Nature of Code Ch.

View →
Sample of Mandelbrot Set (Escape-Time Fractal)

Mandelbrot Set (Escape-Time Fractal)

shiffman_pearson_textbook · mandelbrotSet

The Mandelbrot set rendered by escape-time iteration of z = z^2 + c on a window of the complex plane.

View →
Sample of Random Walk / Drunkard's Walk

Random Walk / Drunkard's Walk

shiffman_pearson_textbook · randomWalkDrunkard

Many random walkers each start at the canvas center and take a stochastic 2-D step every tick.

View →
Sample of Reynolds Boids (Separation / Alignment / Cohesion)

Reynolds Boids (Separation / Alignment / Cohesion)

shiffman_pearson_textbook · boidsClassic

Reynolds' classic boids flocking model.

View →
Sample of Stochastic Recursive Fractal Tree

Stochastic Recursive Fractal Tree

shiffman_pearson_textbook · recursiveTree

Stack-based stochastic fractal tree from Shiffman's Nature of Code Ch.

View →

See all shiffman_pearson_textbook artworks →