art_blocks · HobbsFlowField
Hobbs Flow Field (Tyler Hobbs — Incomplete Control / Fidenza)
The canonical perlin-noise flow-field algorithm described by Tyler Hobbs in his 2020 essay 'Flow Fields', and the algorithmic backbone of his Art Blocks Curated works *Incomplete Control* (Bright Moments, 2021) and *Fidenza* (Art Blocks, 2021). A grid of angles covering the canvas plus a generous margin is initialised from 2D Perlin noise so neighbouring cells have smooth, continuous distortion (Hobbs' 'continuous' case, which guarantees non-crossing curves). N agents advance one step per frame by `step_length * (cos(angle), sin(angle))` from the cell they currently occupy, depositing low-alpha coloured segments. With ~1500 agents and step ~1.6 px the canvas fills in roughly a thousand frames. The HSL-cycling colour trail on a soft cream background echoes the muted, hand-printed feel of *Incomplete Control*.
Original: https://www.tylerxhobbs.com/words/flow-fields
▶ 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.
Math essence
Build G[i, j] = 2*pi * P(i*s, j*s) over a (rows, cols) grid with margin >=50%. Spawn N agents with uniform-random starting positions. At each step: x_{t+1} = x_t + L*cos(G[floor(x)], floor(y)]), y_{t+1} = y_t + L*sin(G[floor(x), floor(y)]). Each segment painted with alpha ~0.06 onto a neutral canvas, accumulating into the dense, non-crossing trail that defines the Hobbs aesthetic.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 600 | 200–1500 | Square canvas side length (px). |
num_agents | int | 1500 | 100–10000 | Number of agents following the flow (Hobbs recommends ~1500–5000). |
resolution_frac | float | 0.012 | 0.002–0.05 | Grid cell size as fraction of dim (Hobbs: ~0.005–0.015). |
margin_frac | float | 0.5 | 0–1.5 | Extra margin beyond canvas, fraction of dim, so out-of-bounds agents curve back in (Hobbs: >=0.5). |
noise_scale | float | 0.085 | 0.01–0.5 | Perlin noise spatial frequency; larger = finer features. |
noise_octaves | int | 2 | 1–6 | Number of Perlin octaves to sum (fBm). |
noise_persistence | float | 0.55 | 0.1–0.9 | Amplitude ratio between successive octaves. |
step_length | float | 1.6 | 0.1–12 | Per-step pixel advance along the cell's field angle. |
steps_per_call | int | 50 | 1–1000 | Default step() batch size. |
hue_base | float | 0.55 | 0–1 | Base hue (0–1) for the trail colour cycle. |
hue_range | float | 0.012 | 0–0.5 | Hue spread around hue_base for each agent. |
alpha | float | 0.06 | 0.005–0.4 | Per-segment trail alpha. Lower = slower build-up. |
background | tuple | 245,240,232 | null–null | Background RGB colour (Hobbs' Incomplete Control cream). |
Reference
First 60 lines of reference.py. Full source:
library_external/art_blocks/HobbsFlowField/reference.py
"""HobbsFlowField — Tyler Hobbs perlin-noise flow-field agent simulation.
Inspired by Tyler Hobbs' *Incomplete Control* (Bright Moments / Art Blocks
2021) and *Fidenza* (Art Blocks 2021), the defining works of the modern
Art-Blocks era. Hobbs' canonical "flow field" algorithm is described in
his 2020 essay "Flow Fields" (https://www.tylerxhobbs.com/words/flow-fields):
"Flow fields are based around a grid. Roughly speaking, this grid
covers the whole image/canvas. At each point in the grid, you store
an angle. ... When you initialize the grid, you need to pick a
resolution. ... About 90% of the time, people use Perlin noise to
initialize the vectors."
The algorithm is:
1. Build a grid G of floating-point angles covering the canvas plus
a generous margin (so agents that wander out can curve back in).
2. Initialize each cell with the angle implied by Perlin noise:
angle(c, r) = 2*pi * noise(c * scale, r * scale)
This is the "continuous distortion" case that gives non-crossing,
organic curves — Hobbs' signature.
3. Spawn N agents at uniformly-random starting positions.
4. Each step, every agent advances along its current cell's angle
by `step_length` pixels and deposits a coloured segment. With
`low_alpha` (e.g. 0.05–0.10) and ~1500 steps the canvas fills.
Here we collapse the implementation to a numpy analogue that uses the
same construction pattern as Hobbs' pseudocode: vectorised Perlin noise
gives the grid, and one matrix multiply + cumulative sum per step
advances all N agents simultaneously. The HSL-cycling colour scheme
follows Hobbs' "Incomplete Control" palette — soft, neutral backgrounds
with occasional vivid colour rectangles, painted as a low-alpha trail.
Reference:
- https://www.tylerxhobbs.com/words/flow-fields
- https://www.tylerxhobbs.com/words/fidenza
- https://www.tylerxhobbs.com/works/2021/incomplete-control
- https://www.artblocks.io/collection/fidenza-by-tyler-hobbs
"""
from __future__ import annotations
from typing import ClassVar
import numpy as np
# ---------------------------------------------------------------------------
# Vectorised 2D Perlin noise (the kernel Hobbs uses to initialise the field)
# ---------------------------------------------------------------------------
def _fade(t: np.ndarray) -> np.ndarray:
# Perlin's quintic fade: 6t^5 - 15t^4 + 10t^3
return t * t * t * (t * (t * 6 - 15) + 10)
def _perlin2(perm: np.ndarray, x: np.ndarray, y: np.ndarray) -> np.ndarray:
"""Vectorised 2D Perlin noise. Returns values roughly in [-1, 1]."""
xi = np.floor(x).astype(np.int64) & 255
yi = np.floor(y).astype(np.int64) & 255
xf = x - np.floor(x)
yf = y - np.floor(y) Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/art_blocks/HobbsFlowField/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from art blocks
Cherniak Ringers (Dmitri Cherniak — Ringers)
art_blocks · CherniakRingers
An implementation of Dmitri Cherniak's *Ringers* algorithm (Art Blocks Curated, January 2021, 1,000 NFTs) — one of the most-cited generative-art projects of the NFT era, and the source of *Ringers #879* ('The Goose') and *Ringers #962* (acquired by LACMA).
Chromie Squiggle (Snowfro / Cherniak — Squiggles)
art_blocks · CherniakSquiggles
An implementation of the squiggle-generation kernel used in Snowfro's *Chromie Squiggle* (Art Blocks #0, November 2020) — the on-chain generative-art project that launched the Art Blocks platform itself and was the work Dmitri Cherniak cited (alongside *Genesis*) as his inspiration for Ringers.
Genesis (DCA — Day-Zero Art Blocks)
art_blocks · DcaGenesis
An interpretation of DCA's *Genesis* (Art Blocks #1, November 2020) — one of three Day-Zero collections (alongside Snowfro's Chromie Squiggle and Jeff Davis's Construction Token) that minted in the first 24 hours of the Art Blocks platform.
Hobbs Watercolor Blob
art_blocks · HobbsWatercolorBlob
Layered translucent Gaussian blobs with watercolor-style alpha falloff.
Hobbs Watercolor Edge (Tyler Hobbs — Soft Textures / Watercolor)
art_blocks · HobbsWatercolorEdge
An implementation of Tyler Hobbs' 2017 'watercolor' technique: a recursive polygon-deformation algorithm whose midpoints are jittered by Gaussian noise across many passes, then stacked with low alpha (4% per layer, 30–100 layers total) to produce the soft, ink-bleed look of wet pigment on paper.
Penne 80s Vector (Aaron Penne — outrun perspective wireframe)
art_blocks · Penne80sVector
The 80s-synthwave outrun grid, the visual aesthetic Aaron Penne references in his generative-art practice (notably in *Apparitions* and his broader body of work).