KQ-1477 · BEAD/PIT
Bead Pit
A background whose floor is a pit of glossy glass beads under simple 2D physics: a position-based solve at 120 Hz with gravity, collisions through a spatial hash, bouncing floor and walls and static friction, drawn as shaded spheres with soft contact shadows, sized so the beads fill the same depth at any width. The pointer is a round paddle that pushes beads aside and lends them its speed, and a click pops the beads on top of the pile into the air with a soft blup chord when sound is on; the loop sleeps once every bead is still. Keyboard focus on a control inside pops the beads behind it.
Fieldline Beads
Every colour, by the handful
Sorted by hand, sent in cotton bags
160 beads · settled
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/bead-pit
Props
- children
- React.ReactNode
- default —
- The content on top of the pit: a hero line, a heading, a call to action.
- count
- number
- default 160
- How many beads lie in the pit, 20 to 400; more beads are smaller, so the pit fills the same depth.
- gravity
- number
- default 1
- How hard the beads fall, 0 (they drift) to 2 (heavy).
- palette
- "candy" | "accent" | "pearl" | "ember" | readonly string[]
- default "candy"
- The beads' glass: a named set of pigments, or CSS colours of your own.
- fill
- number
- default 0.42
- How deep the pit is filled, as a share of the height, 0.1 to 0.8.
- bounce
- number
- default 0.3
- How lively a bead bounces off the floor, the walls and the others, 0 (dead) to 0.8.
- gloss
- number
- default 0.7
- How glossy the glass is: the size and strength of each highlight, 0 (matte) to 1.
- stir
- number
- default 0.6
- How much of the hand's speed a stirred bead takes, 0 (it is only pushed aside) to 1.
- radius
- number
- default 40
- The hand's reach in the pit, px.
- pop
- number
- default 8
- How many beads a click pops into the air, 1 to 24.
- popHeight
- number
- default 0.6
- How high a popped bead flies, as a share of the height, 0 to 1.
- interactive
- boolean
- default true
- The pointer stirs the pit and a click pops beads; keyboard focus inside pops them too.
- paused
- boolean
- default false
- Freeze the beads where they are.
- seed
- number
- default 1
- Seeds the beads' colours, sizes and places.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- sound
- boolean
- default false
- Pops answer with a soft blup and each popped bead lands with a quieter one. Off unless asked for.
- onActiveChange
- (active: boolean) => void
- default —
- Fires when the pointer starts (true) or stops (false) stirring the pit.
- onPop
- (count: number) => void
- default —
- Fires on every pop, with how many beads went up.
- onSettle
- () => void
- default —
- Fires when every bead has come to rest.
- className
- string
- default "h-full w-full"
- Sizes and shapes the box.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | — | The content on top of the pit: a hero line, a heading, a call to action. |
| count | number | 160 | How many beads lie in the pit, 20 to 400; more beads are smaller, so the pit fills the same depth. |
| gravity | number | 1 | How hard the beads fall, 0 (they drift) to 2 (heavy). |
| palette | "candy" | "accent" | "pearl" | "ember" | readonly string[] | "candy" | The beads' glass: a named set of pigments, or CSS colours of your own. |
| fill | number | 0.42 | How deep the pit is filled, as a share of the height, 0.1 to 0.8. |
| bounce | number | 0.3 | How lively a bead bounces off the floor, the walls and the others, 0 (dead) to 0.8. |
| gloss | number | 0.7 | How glossy the glass is: the size and strength of each highlight, 0 (matte) to 1. |
| stir | number | 0.6 | How much of the hand's speed a stirred bead takes, 0 (it is only pushed aside) to 1. |
| radius | number | 40 | The hand's reach in the pit, px. |
| pop | number | 8 | How many beads a click pops into the air, 1 to 24. |
| popHeight | number | 0.6 | How high a popped bead flies, as a share of the height, 0 to 1. |
| interactive | boolean | true | The pointer stirs the pit and a click pops beads; keyboard focus inside pops them too. |
| paused | boolean | false | Freeze the beads where they are. |
| seed | number | 1 | Seeds the beads' colours, sizes and places. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| sound | boolean | false | Pops answer with a soft blup and each popped bead lands with a quieter one. Off unless asked for. |
| onActiveChange | (active: boolean) => void | — | Fires when the pointer starts (true) or stops (false) stirring the pit. |
| onPop | (count: number) => void | — | Fires on every pop, with how many beads went up. |
| onSettle | () => void | — | Fires when every bead has come to rest. |
| className | string | "h-full w-full" | Sizes and shapes the box. |