KQ-1864 · LOTUS/BEADS

Lotus Beads

Beads of water on a waxy leaf, drawn per pixel in one WebGL2 pass as one smooth field, so two that come close join with a neck; each is shaded as water on a leaf that repels it, with the veined leaf beneath magnified and turned over, a dark rim, a sharp highlight, light gathered on the far side and the bright caustic it focuses into its own shadow. Dragged, a bead follows the finger 1:1 and rolls on with little friction when let go; nearing another it stretches a neck toward it, and past the merge distance the two snap into one larger bead, volume and momentum kept, that jiggles with the springs.recoil damping ratio and settles round, while a throw faster than splitSpeed splits it into droplets that fan out and roll apart. Every bead is a real button: Tab moves between them, arrow keys roll the focused one, Enter or Space flicks it so it splits, and focus stays with the bead you rolled through a merge.

KQ-1864 · LOTUS/BEADS

Gaugeworks Botanic · after rain

Arrow keys roll the bead; Enter or Space flicks it so it splits. Roll one into another and they merge.

7 beads · drag one into another

Install

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

$ pnpm dlx shadcn@latest add @kinetiq/lotus-beads

Props

beads
number
default 7
How many beads sit on the leaf at the start, 3 to 14.
tension
number
default 0.6
Surface tension, 0 (soft, flat beads that reach for each other from far off) to 1 (tight, round beads that hold apart until they touch).
tint
number
default 0.2
How much colour the water carries, 0 (clear) to 1 (deeply tinted).
sound
boolean
default false
Play the beads' sounds: a blup as two merge, a higher one as a bead splits.
friction
number
default 0.35
How soon a rolling bead stops, 0 (it glides on and on) to 1 (it stops short).
splitSpeed
number
default 1100
How fast a throw must be to split a bead into droplets, in px a second, 500 to 3000.
leafColor
string
default "oklch(from var(--success) 0.58 calc(c * 0.62) h)"
The leaf's colour: a pigment at a fixed lightness, so it reads the same in both themes.
waterColor
string
default "var(--accent-bright)"
The colour the water takes on as tint rises.
lightAngle
number
default 225
Where the light comes from, in degrees: 0 from the right, 90 from below, 225 from the upper left.
interactive
boolean
default true
Beads can be dragged, thrown and rolled with the keys.
disabled
boolean
default false
Shows the leaf but takes no input.
seed
number
default 7
Seeds where the beads sit and how big they are.
dpr
number
default 2
Cap on the canvas's device pixel ratio, at most 2.
onMerge
(beads: number) => void
default —
Fires when two beads merge, with how many beads are left.
onSplit
(pieces: number) => void
default —
Fires when a bead splits, with how many droplets it made.
onBeadsChange
(beads: number) => void
default —
Fires whenever the number of beads changes, with the new count.
label
string
default "Water beads"
Names the group of beads for assistive technology.
className
string
default "h-56 w-full"
Sizes the box.