live_coding_synth · TidalCyclesPattern
TidalCycles Mini-Notation Pattern Visualiser
A pure-numpy port of TidalCycles' rhythm mini-notation, expanded per cycle into a row of (sample, variant) tuples and visualised as a row of pulsing shapes that scroll horizontally. The parser supports the canonical Tidal subset: single events, ~ (rest), [ ] (sub-grouping), < > (step-wise alternation across cycles), *N (repeat), /N (slow down), :N (sample variant) and , (parallel stacks → one row each). The default pattern [bd sn]*2, hh*4, [cp ~ ~ cp] resolves to a 3-row polyrhythm — exactly the kind of four-on-the-floor-plus-clave texture Alex McLean performs in TidalCycles live-coding sets like the Algorave and TOPLAP live streams. Each fired cell is a coloured dot (hue from a 4-stop palette indexed by sample name, shifted by variant) with a 2-px glow halo; the cycle count scrolls the timeline one column per step.
Original: https://tidalcycles.org
▶ 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
parse(pattern) -> cycles[[ev]], steps_per_cycle. For each (r, s, sample, variant): radius = min(row_h, col_w) * 0.36; (cx, cy) = (margin + (s+0.5) * col_w - scroll_x, margin + (r+0.5) * row_h); scroll_x = (tick * 0.6) mod (steps * col_w); hue = HSV2RGB(HSV(palette[sample]) + variant * 0.06); dot(cx, cy, r) = 1 - clip(dist2 / r^2, 0, 1); halo(dist in [r, r+2]) = 0.35; canvas = max(canvas, body*color + halo*color).
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 480 | 256–640 | Output side length in pixels (HxW). |
pattern | str | [bd sn]*2, hh*4, [cp ~ ~ cp] | — | Tidal mini-notation pattern string. Supports sample names, ~ rest, [ ] group, < > alternation, *N repeat, /N slow, :N variant, , parallel. |
n_cycles | int | 4 | 1–16 | Number of cycles to pre-parse (controls the < > alternation window). |
cell_w | int | 18 | 10–32 | Pixel width per timeline cell (display hint). |
cell_h | int | 18 | 10–32 | Pixel height per timeline cell (display hint). |
bg_color | tuple | 12,12,18 | — | Background colour. |
seed | int | null | 0–999999 | RNG seed (reserved). |
Reference
First 60 lines of reference.py. Full source:
library_external/live_coding_synth/TidalCyclesPattern/reference.py
"""TidalCyclesPattern — Alex McLean's TidalCycles rhythm language in numpy.
A minimal Tidal mini-notation parser that expands a pattern string
into a list of (step, sample_name) events, then visualises the
result as a row of pulsing shapes — one shape per fired sample.
Supported mini-notation (a strict subset of TidalCycles):
bd one event
~ rest
bd sn hh cp four events
[bd sn] hh sub-grouping (euclidean-ish)
bd*2 repeat (speeds up by 2)
bd/2 slow down by 2
bd:3 sample variant
bd*2 sn:1 combine
<bd sn hh> step-wise alternation (rotates per cycle)
bd, sn, hh parallel stacks (each becomes its own row)
Pattern expansion follows Tidal's "step → step / speed" rule:
"a*b" -> a expanded to b copies within the same step
"a/b" -> a expanded to 1 copy taking b steps
Visualisation: each row is a timeline of `steps_per_cycle` cells.
Every step shows a small filled circle whose radius scales with
the sample's index, hue is sampled from a 4-stop palette, and a
1-cell glow halo is drawn for the four canonical "beat" samples
(bd, sn, hh, cp). The whole canvas drifts horizontally with the
current cycle count so the pattern rolls like a TR-8.
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import ClassVar
import numpy as np
# ---------------------------------------------------------------------------
# Mini-notation parser
# ---------------------------------------------------------------------------
_TOKEN_RE = re.compile(
r"""
\s+ | # whitespace
(?P<rest>\~) |
(?P<lbrack>\[) |
(?P<rbrack>\]) |
(?P<langle>\<) |
(?P<rangle>\>) |
(?P<comma>,) |
(?P<star>\*) |
(?P<slash>/) |
(?P<colon>\:) |
(?P<number>[0-9]+(?:\.[0-9]+)?) |
(?P<word>[A-Za-z_][A-Za-z0-9_]*) |
(?P<bang>\!) Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/live_coding_synth/TidalCyclesPattern/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from live_coding_synth
Hydra Video Synth (numpy port of Olivia Jack's Hydra)
live_coding_synth · HydraVisualSynth
A pure-numpy port of the core Hydra video-synth API: chains of sources (osc, noise, shape, gradient, solid, voronoi) composed with geometry modifiers (rotate, scale, scroll, kaleid, pixelate, repeat) and color/blend modifiers (invert, posterize, thresh, color, brightness, contrast, luma, saturate, hue, add, diff, mult, blend) — including the signature modulate operator a.modulate(b, scale), which uses b's red and green channels to displace a's x and y coordinates (with modulateRotate, modulateScale, modulatePixelate, modulateKaleid variants).
P5Live sin/cos Spirograph Sketch
live_coding_synth · P5LiveSketch
A pure-numpy port of the canonical p5.js sin/cos live-coding sketch: a spirograph-like cloud of points whose polar coordinates are themselves nested sin/cos chains.
Strudel 16-Step Pattern Visualiser (4x4 grid of sample-typed shapes)
live_coding_synth · StrudelVisualizer
A pure-numpy port of Strudel's signature 4×4 (16-step) pattern grid.
Topolectures (Olivia Jack) — 2D cell grid + text snippets + audio-amplitude pulse
live_coding_synth · TopolecturesOliviaJack
A pure-numpy port of Olivia Jack's Topolectures: a 2D grid of cells, each cell holding a 1–2 character text snippet from a topology-mathematics corpus (sheaf, locale, frame, open, closed, cover, limit, point, net, filter, basis, ideal, prime, ring, mod, field, topos, yoneda, etale, sieve, …) and brightness pulsed by a synthetic audio-amplitude signal.