KQ-1524 · FLUTED/TUMBLER
Fluted Tumbler
A heavy fluted tumbler of two to four coloured layers, drawn per pixel in one WebGL2 pass: every flute is a small lens that resamples the liquid about its own centre, so the layers' boundaries break into repeating slivers with a faint colour fringe at the ribs. Drag in circles and the hand's angular velocity spins the liquid; overturning currents fold the layers into streaks and buoyancy separates them again by weight, while a sideways move tips the glass on springs.glide (heavy, no bounce) and sets the surface sloshing on a pendulum damped by the viscosity. The glass is a button: Left and Right stir, Shift with them tips it, Enter or Space gives a brisk stir.
Drag in circles round the glass to stir it, or sideways to tip it. Left and Right stir, Shift with them tips the glass, Enter or Space gives a brisk stir.
settled · 3 layers, 20 flutes
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/fluted-tumbler
Props
- layers
- number
- default 3
- How many layers of liquid are stacked, 2 to 4; they take the first colours of `colors`.
- colors
- readonly string[]
- default cherry, amber, cream, sage pigments
- The layers' colours, bottom to top, as CSS colours; pigment, so they read the same in either theme.
- amounts
- readonly number[]
- default [1, 1.1, 0.8, 0.6]
- Each layer's share of the liquid, bottom to top; only the ratios matter.
- fill
- number
- default 0.78
- How full the glass is, 0.3 to 0.95 of the space above its heavy base.
- fluteCount
- number
- default 20
- Flutes round the whole glass, 8 to 40; about half face you.
- fluteDepth
- number
- default 0.6
- How hard each flute bends what is behind it, 0 (flat glass) to 1 (each flute shows a small inverted sliver).
- fringe
- number
- default 0.5
- The colour fringe where the image jumps at a rib, 0 to 1.
- viscosity
- number
- default 0.4
- How thick the liquid is, 0 to 1: runny liquid swirls long and sloshes, syrup turns slowly and comes to rest quickly.
- settle
- number
- default 5
- Roughly how long the layers take to separate again by weight, in seconds.
- tilt
- number
- default 5
- The furthest a sideways move tips the glass, in degrees.
- glassColor
- string
- default "var(--ink-3)"
- The glass's own tint, any CSS colour, resolved on the element so it follows the theme.
- interactive
- boolean
- default true
- Drag, tap and keys stir the glass.
- paused
- boolean
- default false
- Hold the liquid exactly where it is.
- label
- string
- default "A fluted tumbler of layered colour"
- Names the glass for assistive technology.
- sound
- boolean
- default false
- Play a pour while the liquid spins. Off unless asked for.
- seed
- number
- default 3
- Seeds where the overturning currents run, so two glasses never stir alike.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- onStir
- () => void
- default —
- Fires when the visitor starts stirring a settled glass: a drag, a tap or a key.
- onSettle
- () => void
- default —
- Fires once the stirred layers have separated again and the glass is still.
- disabled
- boolean
- default false
- Shows the glass but takes no stirring.
- className
- string
- default "h-56 w-full"
- Sizes the box; give it a height.
| Prop | Type | Default | Description |
|---|---|---|---|
| layers | number | 3 | How many layers of liquid are stacked, 2 to 4; they take the first colours of `colors`. |
| colors | readonly string[] | cherry, amber, cream, sage pigments | The layers' colours, bottom to top, as CSS colours; pigment, so they read the same in either theme. |
| amounts | readonly number[] | [1, 1.1, 0.8, 0.6] | Each layer's share of the liquid, bottom to top; only the ratios matter. |
| fill | number | 0.78 | How full the glass is, 0.3 to 0.95 of the space above its heavy base. |
| fluteCount | number | 20 | Flutes round the whole glass, 8 to 40; about half face you. |
| fluteDepth | number | 0.6 | How hard each flute bends what is behind it, 0 (flat glass) to 1 (each flute shows a small inverted sliver). |
| fringe | number | 0.5 | The colour fringe where the image jumps at a rib, 0 to 1. |
| viscosity | number | 0.4 | How thick the liquid is, 0 to 1: runny liquid swirls long and sloshes, syrup turns slowly and comes to rest quickly. |
| settle | number | 5 | Roughly how long the layers take to separate again by weight, in seconds. |
| tilt | number | 5 | The furthest a sideways move tips the glass, in degrees. |
| glassColor | string | "var(--ink-3)" | The glass's own tint, any CSS colour, resolved on the element so it follows the theme. |
| interactive | boolean | true | Drag, tap and keys stir the glass. |
| paused | boolean | false | Hold the liquid exactly where it is. |
| label | string | "A fluted tumbler of layered colour" | Names the glass for assistive technology. |
| sound | boolean | false | Play a pour while the liquid spins. Off unless asked for. |
| seed | number | 3 | Seeds where the overturning currents run, so two glasses never stir alike. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| onStir | () => void | — | Fires when the visitor starts stirring a settled glass: a drag, a tap or a key. |
| onSettle | () => void | — | Fires once the stirred layers have separated again and the glass is still. |
| disabled | boolean | false | Shows the glass but takes no stirring. |
| className | string | "h-56 w-full" | Sizes the box; give it a height. |