akten_quayola · SimpleHarmonicMotion
Simple Harmonic Motion
A 100x100 grid of damped harmonic oscillators driven by a periodic central impulse. Each cell integrates a = -k*x - c*v with spring constant k=1 and damping c=0.05; a shared kick at the centre every 60 steps lets complexity ripple outward. The render maps displacement and velocity to a warm-to-cool palette so a high-frequency local interference pattern emerges over the grid — Memo Akten's recurring demonstration that 'complex behaviour emerges from very simple, fully deterministic rules'.
Original: https://www.memo.tv/works/simple-harmonic-motion/
▶ 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
For every cell (i, j): a = -k*x - c*v (and optionally -coupling * laplacian(x)). Integrate via semi-implicit Euler: v += a*dt; x += v*dt with dt = 0.05. Every impulse_period steps, v[centre, centre] += impulse. Render reads x as colour amplitude and v as motion depth.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
grid_n | int | 100 | 50–200 | Number of SHM cells per side. |
dim | int | 512 | 256–1024 | Output canvas side length. |
spring_k | float | 1 | 0.5–4 | Hookean spring constant. |
damping_c | float | 0.05 | 0–0.4 | Velocity damping coefficient. |
impulse | float | 0.6 | 0.1–2 | Magnitude of the periodic central kick. |
impulse_period | int | 60 | 10–240 | Frames between centre kicks. |
coupling | float | 0 | 0–0.4 | Discrete Laplacian coupling strength between neighbours. |
Reference
First 60 lines of reference.py. Full source:
library_external/akten_quayola/SimpleHarmonicMotion/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class SimpleHarmonicMotion:
"""Simple Harmonic Motion — Memo Akten, 2011–ongoing.
A grid of damped harmonic oscillators. Each cell carries a 1D oscillator
of state ``(x, v)`` obeying ``a = -k*x - c*v`` with spring constant
``k = 1`` and damping ``c`` in (0, 1). Every step integrates a fixed
impulse at the centre of the grid — Akten's recurring metaphor for
"complex behaviour emerging from very simple, fully deterministic rules".
The render maps the displacement ``x`` of every oscillator onto a
perceptually-tuned gradient: zero displacement = warm bone, max
displacement = deep indigo, min = pale ember. The grid is bilinearly
upsampled and lightly tone-mapped so a 100×100 cell field becomes a
crisp square artwork.
Akten writes (memo.tv/works/simple-harmonic-motion): "A number of agents
are created and assigned a simple behaviour … on their own each agent
is monotonous … however the interaction of the different agent's
behaviours create complex, rich, evolving behaviours and compositions".
"""
family: ClassVar[str] = "akten_quayola"
sketch: ClassVar[str] = "SimpleHarmonicMotion"
def __init__(
self,
grid_n: int = 100,
dim: int = 512,
spring_k: float = 1.0,
damping_c: float = 0.04,
impulse: float = 0.6,
impulse_period: int = 8,
coupling: float = 0.18,
seed: int | None = None,
background: tuple[int, int, int] = (16, 12, 24),
**_,
) -> None:
self.grid_n = int(grid_n)
self.dim = int(dim)
self.spring_k = float(spring_k)
self.damping_c = float(damping_c)
self.impulse = float(impulse)
self.impulse_period = max(1, int(impulse_period))
self.coupling = float(np.clip(coupling, 0.0, 1.0))
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.x = self.rng.normal(scale=0.4, size=(self.grid_n, self.grid_n)).astype(np.float32)
self.v = self.rng.normal(scale=0.2, size=(self.grid_n, self.grid_n)).astype(np.float32)
self.t = 0
self.phase = self.rng.uniform(0.0, np.pi * 2.0, size=(self.grid_n, self.grid_n)).astype(np.float32) Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/akten_quayola/SimpleHarmonicMotion/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from akten × quayola
Gesture Driven Field
akten_quayola · GestureDrivenField
Particles advected through a vector field whose structure is driven by a synthetic gesture signal: a chain of sinusoids at integer-related frequencies.
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.
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.