KQ-1406 · COMPASS/FIELD
Compass Field
A staggered grid of compass needles on one canvas, each a damped rotational spring that turns to point at the pointer with a wobble set by its damping ratio, stiffening, lengthening and brightening as the pointer comes near. Every needle reads the pointer where it was distance / wave seconds ago, so a turn spreads outward from the hand like a ripple and the field swings home to north as a wave from wherever the pointer left; a seeded gust swings through it the first time it comes into view. Keyboard focus inside turns the needles toward the focused element, and a tap turns them for a moment.
Fieldline · orienteering kit
Find your bearing.
needles at north · move across the field, or tab to it
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/compass-field
Props
- children
- ReactNode
- default —
- Content laid over the field, such as a headline; it stays fully interactive.
- density
- number
- default 4
- How many needles stand in every 100 px, along each axis.
- length
- number
- default 0.7
- A needle's resting length, as a share of the space between needles.
- damping
- number
- default 0.45
- Each needle's damping ratio: low values ring and wobble, 1 settles dead-beat.
- grow
- number
- default 0.4
- How much longer needles grow as the pointer comes near, as a share of their length.
- reach
- number
- default 200
- The distance, in px, within which needles answer faster, lengthen and brighten.
- speed
- number
- default 1
- How quickly the needles answer overall, as a multiple of the house stiffness.
- wave
- number
- default 900
- How fast a turn spreads outward from the pointer, in px per second; 0 turns every needle at once.
- north
- number
- default 0
- The bearing every needle rests at when the pointer is away, in degrees clockwise from up.
- scatter
- number
- default 6
- The seeded deviation from that bearing at rest, in degrees.
- polarity
- "attract" | "repel"
- default "attract"
- Whether the north ends turn toward the pointer or away from it.
- northColor
- string
- default "var(--accent-bright)"
- The north half of every needle, any CSS colour, resolved on the element.
- southColor
- string
- default "var(--ink-3)"
- The south half and the pivot, any CSS colour, resolved on the element.
- intro
- boolean
- default true
- One gust through the field the first time it comes into view.
- followFocus
- boolean
- default true
- Keyboard focus inside turns the needles toward the focused element.
- interactive
- boolean
- default true
- The pointer (mouse and pen) turns the needles, and a tap turns them for a moment.
- paused
- boolean
- default false
- Holds every needle where it is and stops the loop.
- seed
- number
- default 7
- Seed for the resting scatter, each needle's own frequency and the gust.
- dpr
- number
- default 2
- The highest device pixel ratio the canvas draws at (never above 2).
- className
- string
- default —
- Classes for the box; give it a height.
- ref
- Ref<CompassFieldHandle>
- default —
- Exposes swing(), which sends a silent, seeded gust through the field.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | Content laid over the field, such as a headline; it stays fully interactive. |
| density | number | 4 | How many needles stand in every 100 px, along each axis. |
| length | number | 0.7 | A needle's resting length, as a share of the space between needles. |
| damping | number | 0.45 | Each needle's damping ratio: low values ring and wobble, 1 settles dead-beat. |
| grow | number | 0.4 | How much longer needles grow as the pointer comes near, as a share of their length. |
| reach | number | 200 | The distance, in px, within which needles answer faster, lengthen and brighten. |
| speed | number | 1 | How quickly the needles answer overall, as a multiple of the house stiffness. |
| wave | number | 900 | How fast a turn spreads outward from the pointer, in px per second; 0 turns every needle at once. |
| north | number | 0 | The bearing every needle rests at when the pointer is away, in degrees clockwise from up. |
| scatter | number | 6 | The seeded deviation from that bearing at rest, in degrees. |
| polarity | "attract" | "repel" | "attract" | Whether the north ends turn toward the pointer or away from it. |
| northColor | string | "var(--accent-bright)" | The north half of every needle, any CSS colour, resolved on the element. |
| southColor | string | "var(--ink-3)" | The south half and the pivot, any CSS colour, resolved on the element. |
| intro | boolean | true | One gust through the field the first time it comes into view. |
| followFocus | boolean | true | Keyboard focus inside turns the needles toward the focused element. |
| interactive | boolean | true | The pointer (mouse and pen) turns the needles, and a tap turns them for a moment. |
| paused | boolean | false | Holds every needle where it is and stops the loop. |
| seed | number | 7 | Seed for the resting scatter, each needle's own frequency and the gust. |
| dpr | number | 2 | The highest device pixel ratio the canvas draws at (never above 2). |
| className | string | — | Classes for the box; give it a height. |
| ref | Ref<CompassFieldHandle> | — | Exposes swing(), which sends a silent, seeded gust through the field. |