Particle Field
betaDrifting particle constellation that parts around the pointer and can converge into a ring or point to signal “generating”.
Drifting constellation
minimal
Converge, shapes and pause
Toggle converge, switch ring/point, tune link distance and speed.
full
Generating state
A Button starts a 4s generation: particles gather into a ring while ShimmerText reports progress.
composition
Describe a workspace and Kura sets it up.
Installation
npx shadcn@latest add https://kuro.abstergo.fyi/r/particle-field.jsonCopies the source into components/kura/particle-field with its dependencies (kura-theme, kura-merge-refs, use-reduced-motion, utils). Tokens come from the kura-theme item.
When to use it
Use it for
- An empty state or hero for a knowledge/graph/agent product where a quiet network motif fits.
- Signalling that something is being generated: flip `converge` while the model works, release when done.
- A subtle, interactive backdrop behind a short prompt or call to action.
Reach for something else when
- Soft colour backgrounds — use mesh-gradient or aurora.
- Inline progress feedback — use thinking-indicator or shimmer-text.
- A voice agent's presence — use agent-orb.
- Behind dense content: lines and motion compete with text.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| count | number | — | Number of particles. Default scales with the area (≈ one per 5,500 px², clamped 30–160). Links are O(n²); stay under ~180. |
| linkDistance | number | 110 | Max px distance at which two particles are joined by a hairline. |
| speed | number | 1 | Drift speed multiplier. |
| interactive | boolean | true | Particles part around the pointer and link to it in the accent colour. |
| converge | boolean | false | Gather the particles into `shape` in the accent colour (the generating signal). Set false to release them back into a drift. |
| shape | "ring" | "point" | "ring" | ring: a slowly turning halo. point: a tight orbiting cluster. |
| paused | boolean | false | Freeze the field on the current frame. |
| maxDpr | number | 2 | Device-pixel-ratio cap. |
| children | React.ReactNode | — | Content rendered on top, in normal flow. |
All native attributes of the root element, className and ref pass through.
Anatomy
- ParticleFieldRoot (`relative isolate overflow-hidden text-kura-fg-subtle`). `data-state` = drifting | converging | still | fallback; `data-converge` mirrors the prop.
data-slot="particle-field" - CanvasThe 2D canvas behind the children (aria-hidden).
data-slot="particle-field-canvas" - FallbackA static CSS dot grid shown when canvas 2D is unavailable.
data-slot="particle-field-fallback"
Accessibility
- Decorative: the canvas is aria-hidden and never takes pointer events from children.
- Converging is a visual signal only — pair it with text in a role=status region (e.g. “Generating…”).
- Reduced motion: No drift, travel or pointer reaction: one still frame. Toggling `converge` jumps straight to the gathered (or scattered) layout without animating.
Notes for agents
- Particle and link colour = the root's text colour; recolour with a class (`text-kura-fg-muted`). Converged particles and pointer links use `--kura-accent`.
- Give the root a height and a background; the canvas is transparent.
- Use `converge` for indeterminate generation (seconds, not milliseconds) and release it when output appears.
- It pauses automatically offscreen; keep one field per view.