anadol_webgpu · dreamscapeField
Dreamscape Field (Refik Anadol — Dreams / Nature Dreams)
Inspired by Refik Anadol Studio's Dreams series (Nature Dreams, Urban Dreams, Space Dreams and the MoMA Fluid Dreams algorithm): a smooth low-frequency Perlin noise field drives slow global drift while a finer detail octave adds turbulent perturbation — Anadol's fluid solver aesthetic realised with cheap numpy. N agents follow the 2-octave flow F(p,t) = A1 n1(p*s1 + d(t)) + A2 n2(p*s2 + d'(t)), depositing fading coloured trails on a canvas to produce a slow-evolving data-pigment landscape.
Original: https://www.nvidia.com/en-us/research/ai-art-gallery/artists/refik-anadol/
▶ 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
Each step: v = v*drag + F(pos, t); pos += v with toroidal wrap. F is two octaves of Perlin gradient noise sampled at independent (scale, drift) parameters per octave. The canvas fades geometrically each step and agents additively splat with an HSV rainbow tied to a per-agent phase plus the shared time-drift.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 600 | 200–1500 | Square canvas side length. |
num_agents | int | 4000 | 100–30000 | Number of agents N. |
coarse_scale | float | 0.01 | 0.001–0.1 | Base octave spatial frequency. |
detail_scale | float | 0.055 | 0.005–0.3 | Detail octave spatial frequency. |
coarse_weight | float | 0.55 | 0–2 | Base octave amplitude. |
detail_weight | float | 0.18 | 0–1.5 | Detail octave amplitude. |
flow_speed | float | 1.2 | 0.1–5 | Velocity scale per step. |
drag | float | 0.96 | 0.5–1 | Per-step velocity damping. |
time_drift | float | 0.0025 | 0–0.05 | Field advection speed. |
fade | float | 0.992 | 0.85–1 | Per-step canvas fade. |
Reference
First 60 lines of reference.py. Full source:
library_external/anadol_webgpu/dreamscapeField/reference.py
"""dreamscapeField — Refik Anadol inspired dream flow field.
Inspired by Refik Anadol Studio's *Dreams* series (*Nature Dreams*,
*Urban Dreams*, *Space Dreams*, the *Dreams — F* installation): a
smooth low-frequency noise field drives a global slow drift of agents,
while a high-frequency noise layer adds turbulent detail. Agents
deposit a fading trail on the canvas — the viewer sees a fluid
"data-pigment" landscape like Anadol's GPU-accelerated fluid
simulations, but generated here with cheap numpy.
The mathematical backbone is two-octave Perlin-like gradient noise:
F(x, y, t) = A1 * n1(x*s1 + dx(t), y*s1 + dy(t))
+ A2 * n2(x*s2 + dx(t), y*s2 + dy(t))
where ``n1`` is a coarse 2D Perlin noise (smooth base flow) and ``n2``
is a finer noise (perturbation layer). At each step we advance N
agents with v += F(p, t), v *= drag, p += v.
Reference:
- https://www.nvidia.com/en-us/research/ai-art-gallery/artists/refik-anadol/
(Nature Dreams, Space Dreams — fluid-dynamics inspired work)
- https://refikanadol.com/works/coraldreams/ (Fluid Dreams algorithm)
"""
from __future__ import annotations
from typing import ClassVar
import numpy as np
def _fade(t: np.ndarray) -> np.ndarray:
# Perlin's fade curve: 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:
"""Fast 2D Perlin noise (vectorised) for arrays of (x, y) positions.
Parameters
----------
perm : (512,) array of ints in [0, 255]
Doubled permutation table (Perlin's classic trick).
x, y : (...) arrays of float coordinates (any shape).
Returns
-------
(...) array of float values in roughly [-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)
u = _fade(xf)
v = _fade(yf)
# Hash function of Perlin: choose a gradient (8 directions on 2D).
def grad(hashval: np.ndarray, x: np.ndarray, y: np.ndarray) -> np.ndarray:
h = hashval & 7
# map to one of 8 directions on the unit circle
dirs = np.array(
[(1, 1), (1, 0), (1, -1), (0, -1), (-1, -1), (-1, 0), (-1, 1), (0, 1)], Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/anadol_webgpu/dreamscapeField/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from anadol · webgpu
2D FFT Texture Spectrum (WebGPU butterfly FFT)
anadol_webgpu · fft2dTexture
The WebGPU butterfly 2D FFT pattern: stage by stage, a @compute shader reads two texels per output (input[p] and twiddle-weighted input[q]) and writes the combined result; after log2(N) horizontal stages, transpose, and log2(N) vertical stages, the 2D FFT is complete.
Compute Particle System (WebGPU @compute pattern)
anadol_webgpu · computeParticleSystem
The canonical WebGPU 'compute-to-render' pattern: a @compute shader updates N particles in a storage buffer (one thread per particle, simple Verlet-style integration: v += gravity; v *= drag; p += v; bounce off walls; life++; respawn if life>max), and a render pass consumes the same buffer as vertex data to draw point sprites.
Data Particle Field (Refik Anadol — Machine Hallucinations / AI Data Sculptures)
anadol_webgpu · dataParticleField
Inspired by Refik Anadol Studio's AI Data Sculptures and 'data universe' portraits (e.g.
Latent Walk (Refik Anadol — Unsupervised / Machine Hallucinations)
anadol_webgpu · latentWalk
Inspired by Refik Anadol Studio's Unsupervised — Machine Hallucinations — MoMA (2022): a chain of N points is sampled from a synthetic 64-dimensional latent space (a smoothed random walk) and projected to 2D via a fixed random matrix; the path is integrated step-by-step with spherical-linear interpolation between adjacent chain points, so the rendered trail visualises the path the 'latent space browser' would take through the embedding.
Parallel Reduction (WebGPU workgroup-shared-memory tree reduction)
anadol_webgpu · parallelReduction
The classic WebGPU parallel-reduction pattern: load N values into workgroup-shared memory, workgroupBarrier(), tree-reduce by stride (shared[lid.x] = op(shared[lid.x], shared[lid.x + stride]); stride /= 2), workgroupBarrier(), and emit per-workgroup partials from thread 0.
Tile Blur (WebGPU separable Gaussian tile-shared-memory blur)
anadol_webgpu · tileBlur
The WebGPU separable Gaussian blur primitive: a workgroup of TILE×TILE threads loads a tile+halo of the source image into workgroup-shared memory, workgroupBarrier(), convolves each pixel with a 1D Gaussian along the row, writes to a ping-pong texture; then a second compute pass applies the column-direction Gaussian on the intermediate texture.