KQ-1533 · DUST/DEVIL
Dust Devil
A tall funnel of fine light threads spiralling up from a floor in Canvas 2D, tight at the foot and loose at the crown, with dust circling its skirt: each thread winds round a spine of twenty nodes, spinning faster low down, drawn dim behind and bright in front, dense at the skirt and wispy at the crown. The foot walks after the pointer on springs.glide while every node above chases the one below on its own underdamped spring, softer toward the top, so the column bends as it walks and the crown whips past and settles when it stops; a click flings a spray of dust off the skirt along the spin. It is a slider for where it stands: arrow keys walk the foot and Enter flings dust.
Arrow keys walk the whirlwind across; Enter flings dust off its skirt.
Fieldline · trail report
Dry wind on the east mesa
standing at 50% · 24 threads
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/dust-devil
Props
- turns
- number
- default 3.5
- How many times each thread winds round the column from foot to crown, 1 to 8.
- lean
- number
- default 0.6
- How far the crown trails the foot and whips past when it stops, 0 (a stiff column) to 1 (a whippy one).
- threadCount
- number
- default 24
- How many threads of light make the funnel, 6 to 64.
- color
- string
- default "oklch(from var(--warn) 0.8 0.09 h)"
- The light's colour: sand from the warn token's hue. Drawn additively on a dark page and as ink on a light one.
- flare
- number
- default 0.55
- The crown's width, as a share of the box's width, 0.2 to 0.9.
- height
- number
- default 0.82
- The funnel's height, as a share of the box's height, 0.4 to 0.95.
- speed
- number
- default 1
- How fast it spins, 0 (held) to 2.
- dust
- number
- default 0.6
- How much dust circles the skirt and how big a spray a click flings, 0 to 1.
- wander
- number
- default 0.5
- How far the foot wanders round its spot when no hand leads it, 0 to 1.
- step
- number
- default 8
- Percent of the width per arrow key.
- value / defaultValue
- number
- default 50
- Where it stands, 0 (left) to 100 (right), across the room the crown allows. Controlled or initial.
- onValueChange
- (value: number) => void
- default —
- Fires when the pointer (on leaving) or the keys set a new place, in whole percent.
- interactive
- boolean
- default true
- The pointer and keys walk it, and a click flings dust.
- disabled
- boolean
- default false
- No walking or flinging by hand or key.
- paused
- boolean
- default false
- Hold the spin and the wander; the walk and a fling still move.
- seed
- number
- default 1
- Seeds the threads and the dust, so two whirlwinds never match.
- dpr
- number
- default 2
- Cap on the canvas's device pixel ratio, at most 2.
- label
- string
- default "Move the whirlwind"
- The accessible name of the whirlwind's control.
- onFling
- () => void
- default —
- Fires when a click or Enter flings dust off the skirt.
- className
- string
- default —
- Sizes the box; it fills its parent by default (h-full w-full).
| Prop | Type | Default | Description |
|---|---|---|---|
| turns | number | 3.5 | How many times each thread winds round the column from foot to crown, 1 to 8. |
| lean | number | 0.6 | How far the crown trails the foot and whips past when it stops, 0 (a stiff column) to 1 (a whippy one). |
| threadCount | number | 24 | How many threads of light make the funnel, 6 to 64. |
| color | string | "oklch(from var(--warn) 0.8 0.09 h)" | The light's colour: sand from the warn token's hue. Drawn additively on a dark page and as ink on a light one. |
| flare | number | 0.55 | The crown's width, as a share of the box's width, 0.2 to 0.9. |
| height | number | 0.82 | The funnel's height, as a share of the box's height, 0.4 to 0.95. |
| speed | number | 1 | How fast it spins, 0 (held) to 2. |
| dust | number | 0.6 | How much dust circles the skirt and how big a spray a click flings, 0 to 1. |
| wander | number | 0.5 | How far the foot wanders round its spot when no hand leads it, 0 to 1. |
| step | number | 8 | Percent of the width per arrow key. |
| value / defaultValue | number | 50 | Where it stands, 0 (left) to 100 (right), across the room the crown allows. Controlled or initial. |
| onValueChange | (value: number) => void | — | Fires when the pointer (on leaving) or the keys set a new place, in whole percent. |
| interactive | boolean | true | The pointer and keys walk it, and a click flings dust. |
| disabled | boolean | false | No walking or flinging by hand or key. |
| paused | boolean | false | Hold the spin and the wander; the walk and a fling still move. |
| seed | number | 1 | Seeds the threads and the dust, so two whirlwinds never match. |
| dpr | number | 2 | Cap on the canvas's device pixel ratio, at most 2. |
| label | string | "Move the whirlwind" | The accessible name of the whirlwind's control. |
| onFling | () => void | — | Fires when a click or Enter flings dust off the skirt. |
| className | string | — | Sizes the box; it fills its parent by default (h-full w-full). |