akten_quayola · GestureDrivenField
Gesture Driven Field
Particles advected through a vector field whose structure is driven by a synthetic gesture signal: a chain of sinusoids at integer-related frequencies. The field is curl-mixed with its own curl, then composited onto a long-tailed decay canvas — producing ribboned, swirling streaks reminiscent of Akten's interactive Body Paint installation and his collaboration with Quayola on Forms (2011), which uses extrapolation to visualise gesture-driven dynamics.
Original: https://www.memo.tv/works/bodypaint/
▶ 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
Synthetic gesture g(x, y, t) = sum_k a_k * cos/sin(f_k * x ± f_k * y + phase_k + omega_k * t). Velocity = curl_mix * curl(g) + (1 - curl_mix) * grad(g). Each particle position is updated modulo canvas size and its colour is painted with a 12% alpha and the canvas is decayed towards the background by (1 - decay) per step.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
num_particles | int | 600 | 200–2000 | Number of particles advected each frame. |
dim | int | 512 | 256–1024 | Output canvas side length. |
num_chains | int | 6 | 3–10 | Number of integer-ratio sinusoid chains in the gesture signal. |
gesture_amp | float | 0.7 | 0.2–1.5 | Amplitude scaling of the gesture field. |
curl_mix | float | 0.35 | 0–1 | Mix between curl-of-gesture (swirling) and gradient-of-gesture (directional). |
decay | float | 0.965 | 0.85–0.999 | Per-step retention of previous canvas (longer streaks at higher values). |
Reference
First 60 lines of reference.py. Full source:
library_external/akten_quayola/GestureDrivenField/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class GestureDrivenField:
"""Gesture Driven Field — Memo Akten, *Body Paint* / *Forms* lineage.
Akten's Body Paint (2009) interprets audience movement into fluid
velocity; his collaboration with Quayola, *Forms* (2011), generalises
the gesture → vector field coupling. Here the gesture signal is
synthetic: a sum of sinusoids at small-integer frequencies, exactly
the kind of "complex signal broken down into its basic elements at
different frequencies" Akten describes in his SHM writings. The
field is the spatial gradient of that scalar gesture field, and
particles are advected by it, leaving long-lived streaks.
The result is a swirling, ribboned field reminiscent of Akten's
interactive painting installations.
"""
family: ClassVar[str] = "akten_quayola"
sketch: ClassVar[str] = "GestureDrivenField"
def __init__(
self,
num_particles: int = 1500,
dim: int = 512,
num_chains: int = 6,
gesture_amp: float = 2.5,
curl_mix: float = 0.5,
decay: float = 0.985,
seed: int | None = None,
background: tuple[int, int, int] = (10, 8, 18),
**_,
) -> None:
self.num_particles = int(num_particles)
self.dim = int(dim)
self.num_chains = int(num_chains)
self.gesture_amp = float(gesture_amp)
self.curl_mix = float(np.clip(curl_mix, 0.0, 1.0))
self.decay = float(np.clip(decay, 0.8, 0.999))
self.bg_color = np.array(background, dtype=np.float32)
self.reset(seed=seed)
def reset(self, seed: int | None = None) -> None:
self.rng = np.random.default_rng(seed)
self.t = 0.0
ratios = np.array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], dtype=np.float32)
idx = self.rng.integers(0, len(ratios), size=self.num_chains)
self.freqs = ratios[idx]
self.phases = self.rng.uniform(0.0, np.pi * 2.0, size=self.num_chains).astype(np.float32)
self.amps = self.rng.uniform(0.4, 1.0, size=self.num_chains).astype(np.float32)
self.positions = self.rng.uniform(0.0, 1.0, size=(self.num_particles, 2)).astype(np.float32)
self.hues = self.rng.uniform(0.0, 1.0, size=self.num_particles).astype(np.float32)
self.canvas = np.tile(self.bg_color, (self.dim, self.dim, 1))
def step(self, n: int = 1) -> None: Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/akten_quayola/GestureDrivenField/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from akten × quayola
Lissajous 3D
akten_quayola · Lissajous3D
A three-dimensional Lissajous figure rendered as a single precision line drawing on a deep field.
Mechanical Flower Spline
akten_quayola · MechanicalFlowerSpline
A 2D petal-radius spline r(θ) = r0 + A*cos(p*θ + δ) + B*cos(q*θ) swept 360° around a vertical Y axis to form a procedural flower-like 3D surface, then orthographically projected and depth-shaded.
Pleated Fabric
akten_quayola · PleatedFabric
A textile grid whose vertical coordinate follows z = A * envelope(y) * sin(2π f x + phase(t)), projected obliquely onto a 2D canvas so the folds read as parallel ridges of light.
Simple Harmonic Motion
akten_quayola · SimpleHarmonicMotion
A 100x100 grid of damped harmonic oscillators driven by a periodic central impulse.
Strata Landscape
akten_quayola · StrataLandscape
A geological landscape rendered as N horizontal strata stacked vertically, each band displaced by a slowly growing sinusoid and shaded with its own hue.
Wave Interference
akten_quayola · WaveInterference
N drifting point sources emit circular sinusoidal waves whose superposition is tone-mapped into a stormy ocean-like field.