KQ-1596 · RING/SHEPHERD

Ring Shepherd

A close look down onto a planetary ring system in Canvas 2D: bands of fine dust bowed round a planet below the frame, dark gaps and thin ringlets between them, shearing past slowly as rings do seen from a moon's orbit. The pointer is a small moon on springs.snap that pushes every point of dust it passes out of a lane, and because each point then rings about its new orbit at the epicyclic frequency while the shear carries it along, both edges of the lane raise scalloped waves and bright crests that trail opposite ways and smooth out behind it as the lane closes. It is a slider for where the moon is: arrow keys steer it, Escape gives it back its own orbit, and with no pointer it circles the field on its own.

KQ-1596 · RING/SHEPHERD

Arrow keys steer the moon through the rings, Shift for bigger steps; Escape gives it back its own orbit.

Basinworks · ring survey

The Coldbrook rings

on its own orbit · moon in a gap

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/ring-shepherd

Props

ringDensity
number
default 0.6
How thickly the dust lies in the bands, 0.1 (a sparse scatter) to 1 (dense, opaque rings).
gapWidth
number
default 0.4
Width of the dark gaps between the bands, 0 (bands touching) to 1 (wide divisions).
wake
number
default 0.6
How hard the moon pushes and how long its wake rings, 0 (a light touch that heals at once) to 1 (a wide lane with long scallops).
bands
number
default 6
How many bands of dust cross the frame, 3 to 9.
color
string
default "oklch(from var(--warn) 0.88 0.03 h)"
The dust's colour: pale ice from the warn token's hue. Drawn as light on a dark page and as a darkened ink on a light one.
moonColor
string
default "oklch(from var(--warn) 0.8 0.05 h)"
The moon's colour, a pigment that reads on both themes; it is lit from the upper left.
moonSize
number
default 6
The moon's radius, px, 3 to 14. The lane it clears scales with it.
shear
number
default 1
How fast the rings shear past, 0 (held) to 2. The middle of the frame rides with the moon; dust inside and outside it drifts opposite ways.
curvature
number
default 0.5
How far the bands bow, as if the planet sat below the frame, 0 (straight) to 1.
autopilot
boolean
default true
With no pointer and no keys, the moon circles the field on its own.
step
number
default 18
Pixels per arrow key; Shift moves three times as far.
interactive
boolean
default true
The pointer and keys steer the moon.
disabled
boolean
default false
No steering by pointer or key; the control leaves the tab order.
paused
boolean
default false
Hold the shear and the moon's own orbit; steering still parts the dust.
seed
number
default 1
Seeds the band layout and the dust's grain, so two ring systems never match.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
label
string
default "Steer the moon"
The accessible name of the moon's control.
onBandChange
(band: number | null) => void
default —
The band under the moon (0 is the outermost), or null while it crosses a gap. Fires on change, and once when it first reads.
onSteerChange
(steering: boolean) => void
default —
The visitor took the moon (true) or gave it back to its own orbit (false).
className
string
default —
Sizes the box; it fills its parent by default (h-full w-full).