audio_reactive · LiebermanDailySketch
Daily Sketch Curve Morph (Synthetic Gesture)
A parametric polar / hypotrochoid curve whose three radii (R, r, d) are continuously morphed by independent sin-wave chains — Zach Lieberman's signature 'use mathematical functions like sin() and tan() in place of randomness' rule from his Daily Sketches project. The trail canvas rotates the line each step to evoke the AR / rotation experiments from his openFrameworks sketches (notably the *Audio in Space* ARKit series). Each chain is its own frequency band, so the curve 'wiggles in three different ways at once' — one of his signature compositional moves.
Original: http://zach.li/
▶ 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
theta = linspace(0, 12π, N). R, r, d each = base + Σ amp_k * sin(2π freq_k * t + phase_k) for their own chain. x = (R + r*cos(3θ))*cos(θ); y = (R + r*cos(3θ))*sin(θ) + d*sin(7θ + 0.7). Rotate (x, y) by _rot about centre, rasterize to canvas. canvas *= trail_decay each step; ink = line_color * stroke_alpha, with 1-pixel halo to either side.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 400 | 200–800 | Square canvas side length in pixels. |
num_points | int | 600 | 200–2000 | Number of curve samples per frame. |
base_R | float | 0.42 | 0.05–0.95 | Outer radius base. |
base_r | float | 0.18 | 0.01–0.6 | Inner radius base. |
base_d | float | 0.32 | 0.01–0.9 | Vertical warp base. |
R_freq | tuple | 0.21,0.43,0.91 | — | Sin-chain frequencies for the outer radius. |
r_freq | tuple | 0.31,0.83,1.7 | — | Sin-chain frequencies for the inner radius. |
d_freq | tuple | 0.11,0.67,2.3 | — | Sin-chain frequencies for the vertical warp. |
R_amp | tuple | 0.05,0.04,0.03 | — | Sin-chain amplitudes for the outer radius. |
r_amp | tuple | 0.06,0.05,0.04 | — | Sin-chain amplitudes for the inner radius. |
d_amp | tuple | 0.08,0.06,0.05 | — | Sin-chain amplitudes for the vertical warp. |
morph_speed | float | 1 | 0.05–4 | Time multiplier for the sin-chain t. |
rotation_speed | float | 0.18 | -0.5–0.5 | Per-step canvas rotation (radians). |
line_color | tuple | 245,240,230 | — | Ink colour. |
bg_color | tuple | 12,12,18 | — | Background colour. |
trail_decay | float | 0.96 | 0.7–0.999 | Per-step multiplicative fade of the canvas. |
stroke_alpha | float | 0.65 | 0.05–1 | Per-pixel ink intensity. |
seed | int | null | 0–999999 | RNG seed (initial sin-chain phases). |
Reference
First 60 lines of reference.py. Full source:
library_external/audio_reactive/LiebermanDailySketch/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class LiebermanDailySketch:
"""Lieberman-style daily-sketch aesthetic: a parametric curve
whose parameters morph continuously under a synthetic "gesture"
signal (a chain of sin waves at different frequencies, mimicking
mouse / pen motion).
Implements a polar-rose / hypotrochoid family whose radii
(R, r, d) and phase offsets are driven by independent sin
chains. Each chain has its own frequency band — so the curve
"wiggles in three different ways at once" (one of Zach
Lieberman's signature rules from his *Daily Sketches* project:
"use mathematical functions like sin() and tan() in place of
randomness"). The trail canvas rotates the line each step to
evoke the AR / rotation experiments from his openFrameworks
sketches (notably the *Audio in Space* ARKit series).
"""
family: ClassVar[str] = "audio_reactive"
sketch: ClassVar[str] = "liebermandailysketch"
def __init__(
self,
dim: int = 400,
num_points: int = 600,
base_R: float = 0.42,
base_r: float = 0.18,
base_d: float = 0.32,
R_freq: tuple[float, ...] = (0.21, 0.43, 0.91),
r_freq: tuple[float, ...] = (0.31, 0.83, 1.7),
d_freq: tuple[float, ...] = (0.11, 0.67, 2.3),
R_amp: tuple[float, ...] = (0.05, 0.04, 0.03),
r_amp: tuple[float, ...] = (0.06, 0.05, 0.04),
d_amp: tuple[float, ...] = (0.08, 0.06, 0.05),
morph_speed: float = 1.0,
rotation_speed: float = 0.18,
line_color: tuple[int, int, int] = (245, 240, 230),
bg_color: tuple[int, int, int] = (12, 12, 18),
trail_decay: float = 0.96,
stroke_alpha: float = 0.65,
seed: int | None = None,
) -> None:
self.dim = dim
self.num_points = num_points
self.base_R = base_R
self.base_r = base_r
self.base_d = base_d
self.R_freq = np.array(R_freq, dtype=np.float32)
self.r_freq = np.array(r_freq, dtype=np.float32)
self.d_freq = np.array(d_freq, dtype=np.float32)
self.R_amp = np.array(R_amp, dtype=np.float32)
self.r_amp = np.array(r_amp, dtype=np.float32)
self.d_amp = np.array(d_amp, dtype=np.float32)
self.morph_speed = morph_speed Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/audio_reactive/LiebermanDailySketch/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from audio-reactive
data.matrix Glitch Grid (Binary Cellular Automaton + Beat Faders)
audio_reactive · IkedaGridMatrix
A 32×32 binary cell grid plus a thin frame of beat-fader bars around the edges.
FFT-Spectrum Particle Field (Synthetic Audio)
audio_reactive · PasmaFFTSpectrum
A particle field whose velocity is driven by three FFT-magnitude bands (low / mid / high) computed from a sliding window of synthetic audio.
Reactive Concentric Rings (FFT-Band-Driven)
audio_reactive · PasmaReactiveCircle
N concentric rings around the canvas centre, each driven by a different FFT band (low / mid / high).
SND Grid Sequencer (Multistability Pulse Grid)
audio_reactive · SNDGridSequencer
A 16×16 grid where each cell has its own activation period (inner-loop ticks) and phase offset, modelled after Mark Fell's *Multistability* algorithm: nested inner/outer loops, impulse at each inner-loop wrap, phase-reset by the outer loop.