KQ-1398 · MOON/RING

Moon Ring

Images or generated tiles on a tipped elliptical orbit around a centre object: one phase value drives every moon's position, depth scale, far-side softening and z-order, so moons pass behind the planet and back in front of it, while the ring revolves on its own until a visitor touches it. A drag spins it 1:1 and a release projects the throw, snaps to the nearest moon and lands on springs.drift with the release velocity, so a flick coasts several moons round; a click brings a moon round the shortest way on springs.glide, with an optional whoosh. It is a radio group: the front moon is checked and holds the tab stop, arrow keys bring the neighbours round, and Home and End the first and last.

KQ-1398 · MOON/RING

Coldbrook Observatory · Moons

Season 04

Arrow keys bring the next moon round to the front; Home and End the first and last. Drag to spin the ring.

drag, click or use arrows · 6 moons · tilt 20° · drifting 8°/s

Install

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

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

Props

items
{ id: string; label: string; src?: string; alt?: string }[]
default —
The moons. Short of count, generated tiles fill the ring.
count
number
default 6
How many moons circle, 3 to 12.
tilt
number
default 20
How far the orbit tips toward you, degrees: 0 is edge-on, 70 nearly overhead.
speed
number
default 8
Idle revolution, degrees per second; negative turns the other way, 0 holds still.
value / defaultValue
number
default 0
The moon at the front. Controlled rings do not drift.
onValueChange
(index: number, reason: "drift" | "drag" | "press" | "key") => void
default —
A new moon reached the front, with what brought it there.
lean
number
default -8
The orbit's lean in the picture, degrees.
depth
number
default 0.45
How much smaller the far side is, 0 to 0.8.
soften
number
default 2
Blur at the far side of the orbit, px.
shape
"circle" | "rounded"
default "circle"
Moon shape.
moonSize
number
default —
Moon size, px. Fits the stage when left out.
height
number | string
default "clamp(9rem, 30cqw, 12.5rem)"
Height of the stage.
center
ReactNode
default —
What the moons circle. A lit planet when left out.
caption
boolean
default true
Name the front moon under the ring.
label
string
default "Orbit"
Accessible name of the ring.
sound
boolean
default false
A whoosh when a throw or a long trip brings a moon round.
paused
boolean
default false
Hold the idle revolution.
disabled
boolean
default false
No drag, no presses; the moons leave the tab order.
className
string
default —
Classes for the root (a size container for the stage).