hodgin_iquilezles · SaturnRings
Saturn Rings (orbital resonance)
Thousands of particles are initialized in an annulus between inner_radius and outer_radius around a central mass, with circular orbital velocities v = sqrt(M/r). Each frame the central inverse-square gravity pulls them inward, a small tangential drift adds ring shimmer, and unstable particles are recycled. The accumulated low-alpha trail builds the layered concentric-ring structure reminiscent of Hodgin's Saturn studies.
Original: https://flight404.com
▶ 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 particle obeys a_central = -M * r_hat / r^2 plus a tangential kick t_drift perpendicular to r_hat. Velocity is integrated and clamped to max_speed; position updates, with particles that leave the annulus being reborn on a fresh circular orbit at a new random radius. The integration preserves stable nearly-circular orbits while the per-particle tangential drift slowly smears each ring into a thin luminous band.
Parameters
| Name | Type | Default | Range | Description |
|---|---|---|---|---|
dim | int | 500 | 200–1000 | Square canvas side length in pixels. |
num | int | 4000 | 500–12000 | Number of orbital particles. |
inner_radius | float | 90 | 20–200 | Inner edge of the allowed annulus. |
outer_radius | float | 230 | 100–480 | Outer edge of the allowed annulus. |
central_mass | float | 1.6 | 0.2–6 | Gravitational mass of the central body. |
tangential_boost | float | 1 | 0.5–2 | Multiplier on the theoretical circular velocity sqrt(M/r). |
eccentricity | float | 0.06 | 0–0.4 | Initial radial jitter as a fraction of orbital velocity. |
radial_drift | float | 0.0006 | 0–0.01 | Standard deviation of the per-frame tangential kick. |
ring_jitter | float | 0.08 | 0–0.5 | Initial relative scatter of orbital velocities. |
max_speed | float | 12 | 4–30 | Speed clamp (px/frame). |
trail_alpha | int | 18 | 4–80 | Stroke alpha (0-255). |
Reference
First 60 lines of reference.py. Full source:
library_external/hodgin_iquilezles/SaturnRings/reference.py
from __future__ import annotations
from typing import ClassVar
import numpy as np
class SaturnRings:
"""Saturn Rings — Robert Hodgin (flight404), inspired by *Saturn* / orbital systems.
Hodgin built several orbital-resonance studies; the most famous is the
*Saturn* sketch in which thousands of particles orbit a central mass in
concentric rings, each ring at a slightly different resonance. Particles
are subject to inverse-square gravitational attraction toward a central
mass plus a tangential impulse that keeps them in roughly circular
orbits; small perturbations (drift + jitter) keep each ring shimmering.
The "interesting" particles are the ones whose initial radius lies
inside an allowed stable annulus. Particles outside the annulus either
spiral in or escape.
"""
family: ClassVar[str] = "hodgin_iquilezles"
sketch: ClassVar[str] = "saturnrings"
def __init__(
self,
dim: int = 500,
num: int = 4000,
inner_radius: float = 90.0,
outer_radius: float = 230.0,
central_mass: float = 1.6,
tangential_boost: float = 1.0,
eccentricity: float = 0.06,
radial_drift: float = 0.0006,
ring_jitter: float = 0.08,
max_speed: float = 12.0,
trail_alpha: int = 18,
ink_color: tuple[int, int, int] = (255, 240, 220),
background: tuple[int, int, int] = (4, 4, 10),
**_,
) -> None:
self.dim = dim
self.num = num
self.inner_radius = inner_radius
self.outer_radius = outer_radius
self.central_mass = central_mass
self.tangential_boost = tangential_boost
self.eccentricity = eccentricity
self.radial_drift = radial_drift
self.ring_jitter = ring_jitter
self.max_speed = max_speed
self.trail_alpha = trail_alpha
self.ink_color = np.array(ink_color, dtype=np.float32)
self.bg_color = np.array(background, dtype=np.float32)
self.reset()
def reset(self, seed: int | None = None) -> None:
self.rng = np.random.default_rng(seed)
cx = self.dim * 0.5 Try running it locally
The reference implementation is self-contained Python with numpy. Install the package and run:
python library_external/hodgin_iquilezles/SaturnRings/reference.py Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.
More from hodgin × iquilezles
Boids Flock (Hodgin Murmuration)
hodgin_iquilezles · BoidsFlock
A 2D flock of boids steered by Craig Reynolds' three classic rules (separation, alignment, cohesion) over a coarse spatial-hash neighbor query.
Fractional Brownian Motion noise
hodgin_iquilezles · FBMNoise
Quilez's canonical fBM: a 2D value-noise base summed over N octaves whose frequency doubles and amplitude is multiplied by G = exp2(-H) per octave.
Magneto Particles (Hodgin Magnetosphere)
hodgin_iquilezles · MagnetoParticles
Particles pulled and pushed by N orbiting magnetic anchors whose charges flip sign over time.
Mulberry32 PRNG (stratified scatter)
hodgin_iquilezles · Mulberry32RNG
Mulberry32 is a tiny 32-bit-state pseudo-random number generator popularised in the demoscene and used pervasively by Quilez and other graphics programmers as the RNG inside procedural sketches.
Smooth-Minimum SDF field
hodgin_iquilezles · SmoothMinSDF
Two animated 2D SDF primitives (a moving circle and a translating slab) are blended with Quilez's quadratic-polynomial smooth-minimum and rendered as a scalar field.
Worley / Cellular Noise
hodgin_iquilezles · WorleyNoise
Quilez's classic 2D Worley noise: a unit grid of cells, each containing one pseudo-random feature point placed by a 2D integer hash.