KQ-1811 · ROOT/EXCHANGE
Root Exchange
A hub feeding a ring of nodes through fine, root-like paths: neighbours share a trunk that forks half way, each trunk as thick as the flow it carries, and pulses of light leave the hub along every route at that node's share of the total, so the busy ones visibly draw more. Hovering or tabbing to a node lights its route and shows its label, value and share in a tag that rises on springs.snap; a press reverses its flow, the route's direction springing through zero on springs.snap so pulses already in flight slow, stop and run home while the node kicks on springs.recoil and its chevron turns. Arrow keys walk the ring and Enter or Space reverses the focused node.
Arrow keys move between nodes; Enter or Space reverses a node's flow.
reservoir · 6,310 l/s to 7 districts
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/root-exchange
Props
- nodes
- { id: string; label: string; value: number }[]
- default defaultRootNodes
- The nodes the hub feeds; each value's share of the total sets its pulse rate and its route's thickness.
- hubLabel
- string
- default "Hub"
- What the hub is, for its accessible name and announcements.
- format
- (value: number) => string
- default en-US grouping
- Prints a node's value in its tag and accessible name.
- reversed / defaultReversed
- string[]
- default []
- Ids of the nodes whose flow runs back to the hub, controlled or initial.
- onReversedChange
- (ids: string[]) => void
- default —
- Fires from the press that reversed or restored a node, with the new ids.
- onActiveChange
- (id: string | null) => void
- default —
- Fires when hover or keyboard focus brings a node forward, or lets it go.
- pulseRate
- number
- default 4
- Pulses a second leaving the hub in all, shared out by value.
- travel
- number
- default 1800
- Time for a pulse to cross an average route, ms; every pulse moves at the same speed in pixels.
- curve
- number
- default 0.55
- How far the roots wander off a straight line, 0 (schematic) to 1 (gnarled).
- rootlets
- number
- default 0.5
- How many hair-fine side rootlets the routes shed, 0 to 1.
- palette
- "cobalt" | "signal" | "amber" | "ink"
- default "cobalt"
- The colourway, from the theme's tokens.
- colors
- { route?: string; pulse?: string; hub?: string }
- default —
- CSS colours that replace parts of palette.
- seed
- number
- default 7
- Seeds where the nodes sit and how the roots wander.
- paused
- boolean
- default false
- Freezes the pulses where they are.
- dpr
- number
- default 2
- Cap on the pulse canvas's device pixel ratio, at most 2.
- label
- string
- default "Flow from the hub"
- The node group's accessible name.
- disabled
- boolean
- default false
- Nodes cannot be focused or reversed; the flow still runs.
- className
- string
- default "h-56 w-full"
- Sizes the box.
| Prop | Type | Default | Description |
|---|---|---|---|
| nodes | { id: string; label: string; value: number }[] | defaultRootNodes | The nodes the hub feeds; each value's share of the total sets its pulse rate and its route's thickness. |
| hubLabel | string | "Hub" | What the hub is, for its accessible name and announcements. |
| format | (value: number) => string | en-US grouping | Prints a node's value in its tag and accessible name. |
| reversed / defaultReversed | string[] | [] | Ids of the nodes whose flow runs back to the hub, controlled or initial. |
| onReversedChange | (ids: string[]) => void | — | Fires from the press that reversed or restored a node, with the new ids. |
| onActiveChange | (id: string | null) => void | — | Fires when hover or keyboard focus brings a node forward, or lets it go. |
| pulseRate | number | 4 | Pulses a second leaving the hub in all, shared out by value. |
| travel | number | 1800 | Time for a pulse to cross an average route, ms; every pulse moves at the same speed in pixels. |
| curve | number | 0.55 | How far the roots wander off a straight line, 0 (schematic) to 1 (gnarled). |
| rootlets | number | 0.5 | How many hair-fine side rootlets the routes shed, 0 to 1. |
| palette | "cobalt" | "signal" | "amber" | "ink" | "cobalt" | The colourway, from the theme's tokens. |
| colors | { route?: string; pulse?: string; hub?: string } | — | CSS colours that replace parts of palette. |
| seed | number | 7 | Seeds where the nodes sit and how the roots wander. |
| paused | boolean | false | Freezes the pulses where they are. |
| dpr | number | 2 | Cap on the pulse canvas's device pixel ratio, at most 2. |
| label | string | "Flow from the hub" | The node group's accessible name. |
| disabled | boolean | false | Nodes cannot be focused or reversed; the flow still runs. |
| className | string | "h-56 w-full" | Sizes the box. |