hobbs_cherniak_penne_deep · HobbsSpirograph
Hobbs Spirograph (Tyler Hobbs — Petal Loops / Elektroanima)
A rotating-circular-arc trail in the spirit of Tyler Hobbs's *Petal Loops* (2020) and *Elektroanima* (2020) — works described by Hobbs as 'looping taken to an excessive level.' M rotating points (default 8) are connected by a closed polyline that morphs each frame as the whole ring rotates by a small angle around a central anchor. The same polyline is drawn every step at slightly different positions, so the canvas accumulates a continuous ribbon of curved traces — the dense rainbow crescent characteristic of mechanical spirograph / hypotrochoid toys, but driven by a per-frame rotation rather than a physical gear ratio. The classic spirograph / hypotrochoid parameterisation lives behind the polyline update: the ring rotates as if it were the centre of a rolling circle, so each point traces a hypotrochoid path; the closed polyline is the polygon that a single hypotrochoid frame would inscribe. The colour band advances slowly with each step, so the ribbon reads as a smooth colour gradient through HSV space.
Original: https://www.tylerxhobbs.com/works/petal-loops
▶ 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 point i has its own angle theta_i that is advanced by dtheta each step. The whole ring's anchor also rotates by dtheta around (cx, cy). The pen position of point i at step t is (cx + r1*cos(dtheta*t) + r2*cos(theta_i + dtheta*t), cy + r1*sin(dtheta*t) + r2*sin(theta_i + dtheta*t)). A closed polyline is drawn through the M points, then the polyline is repeated at the next step. After N steps the canvas is the union of N rotated copies of the M-gon — a continuous ribbon whose outline is a hypotrochoid envelope.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 600 | 200–1500 | Square canvas side length (px). |
num_points | int | 8 | 3–24 | Number of points in the rotating ring (M-gon vertices). |
anchor_r_frac | float | 0.3 | 0–0.45 | Anchor orbit radius as a fraction of dim. |
point_r_frac | float | 0.15 | 0–0.45 | Point-local orbital radius as a fraction of dim. |
inner_r_frac | float | 0.18 | 0–0.45 | Spirograph inner-rolling radius as a fraction of dim. |
pen_r_frac | float | 0.12 | 0–0.45 | Pen distance from inner-circle centre as a fraction of dim. |
outer_speed | int | 5 | 1–30 | Outer-ring rational speed (numerator of petal ratio). |
inner_speed | int | 12 | 1–60 | Inner-ring rational speed (denominator of petal ratio). |
rotate_per_step | float | 0.18 | 0.01–5 | Degrees the whole ring rotates per step. Small = slow ribbon drift. |
num_steps | int | 1200 | 50–5000 | Number of iterations to draw. |
steps_per_frame | int | 4 | 1–50 | Iterations to advance per step() call. |
line_thickness | int | 1 | 1–5 | Line thickness in pixels. |
hue_base | float | 0.55 | 0–1 | Base hue (0-1) of the trail. |
hue_speed | float | 0.001 | 0–0.05 | Hue advance per step. |
saturation | float | 0.65 | 0–1 | HSV saturation. |
value | float | 0.88 | 0–1 | HSV value / brightness. |
alpha | float | 0.18 | 0.01–1 | Per-frame line alpha (low alpha accumulates the trail). |
background | tuple | 245,240,232 | null–null | Background RGB colour (Hobbs cream). |
Reference
First 60 lines of reference.py. Full source:
library_external/hobbs_cherniak_penne_deep/HobbsSpirograph/reference.py
"""HobbsSpirograph — Tyler Hobbs rotating-circular-arc trails (hypotrochoids).
A composition in the spirit of Tyler Hobbs's
*Elektroanima* / *Petal Loops* / *Cranes* family of works
(2019-2020), where a small rotating system of points traces
hypotrochoid curves across the canvas as the whole system
spins. Hobbs calls this "looping taken to an excessive level"
(he posted about Petal Loops on Facebook as a prime example).
The kernel we implement:
1. Place a small ring of M points (default 8) on a circle of
radius r1 around an anchor (cx, cy). Each point also
carries its own local orbital radius r2 (so the trace is a
hypotrochoid, not a plain circle).
2. Each step, advance every point's orbital angle by dtheta
(the small rotation), AND advance the whole ring's anchor
angle by Dtheta (the large rotation). This is the classic
spirograph / hypotrochoid update.
3. Draw a thin coloured polyline through the M points every
K steps. The polyline's vertices rotate rigidly, so the
closed shape morphs each frame.
4. After N iterations, the canvas is a beautiful rotating
hypotrochoid ribbon — a single connected curve drawn many
times in slightly different positions.
A real spirograph produces a *closed* curve when the ratio
r1 / r2 is rational. When the ratio is irrational, the curve
is dense in an annular region. We use the rational case (a
small integer ratio) so the trace closes and reads as a
rotating ribbon; the apparent rotation comes from the slow
anchor spin.
Reference:
- https://www.tylerxhobbs.com/works/petal-loops
- https://www.tylerxhobbs.com/works/elektroanima
- Spirograph / hypotrochoid math: a hypotrochoid is the
parametric curve
x(t) = (R - r) * cos(t) + d * cos((R - r)/r * t)
y(t) = (R - r) * sin(t) - d * sin((R - r)/r * t)
where R is the radius of the outer fixed circle, r is the
radius of the inner rolling circle, d is the distance of the
pen from the centre of the rolling circle.
"""
from __future__ import annotations
from typing import ClassVar
import numpy as np
# ---------------------------------------------------------------------------
class HobbsSpirograph:
"""Hobbs-style rotating-circular-arc trails (hypotrochoid family).
Parameters
----------
dim : int
Square canvas side length (px).
num_points : int Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/hobbs_cherniak_penne_deep/HobbsSpirograph/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from hobbs_cherniak_penne_deep
Cherniak Constellations (Dmitri Cherniak point-cloud + graph)
hobbs_cherniak_penne_deep · CherniakConstellations
A pseudo-random point cloud with connecting lines filtered by distance, producing graph-like emergent forms.
Cherniak Nibbles (Dmitri Cherniak cell-eating cellular automata)
hobbs_cherniak_penne_deep · CherniakNibbles
A cellular-automata growth algorithm in the spirit of Dmitri Cherniak's body of work — small 2D shapes ('nibbles') that grow by selectively removing neighbours.
Hobbs Color-Field Overlay (Tyler Hobbs compositional method)
hobbs_cherniak_penne_deep · HobbsColorFieldOverlay
Hobbs's compositional method of choice: combine TWO independent fields — a Perlin flow field that drives the *trajectory* of a set of line segments, and a Gaussian-blurred colour field that drives the *colour* and *opacity* of those segments.
Hobbs QLIQUE (Tyler Hobbs — QQL dense-streamline tangle)
hobbs_cherniak_penne_deep · HobbsQLIQUE
A dense tangle of curves where every curve is a streamline through a Perlin flow field, in the visual spirit of Tyler Hobbs's 2022 QQL release (with Dandelion Mane).
Penne Imprecise Balance (Aaron Penne stacked-blocks column)
hobbs_cherniak_penne_deep · PenneImpreciseBalance
A column of stacked rectangular blocks where each block is rotated by a seed-derived angle.
Penne Ringers (Aaron Penne concentric ring extrusion)
hobbs_cherniak_penne_deep · PenneRingers
Penne's take on the *Ringers* idiom (best known from Cherniak's Art Blocks release, 2021): concentric rings extruded along the Z axis, rotated about a common axis, projected to 2D.