Particle field
stable 3.1 kB<hk-particle-field>Drifting points that draw a line when they come close. The link pass is the expensive half — naively O(n squared) per frame, which is why most versions of this crawl past a few hundred particles. This one bins into a spatial grid sized to the link distance, so each particle only tests its nine neighbouring cells.
#background#canvas#decorative
Live demo
Running in this page — interact with it.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
| color | string | '#dc2626' | Base colour. Any hex the background derives its palette from. |
| speed | number | 1 | Animation multiplier. 0 freezes on the first frame. |
| opacity | number | 1 | Canvas opacity — these sit behind real content. |
| paused | boolean | false | Stops the loop without unmounting. |
| density | number | 0.9 | Particles per 10,000 css px². Scaled by area, so it reads the same at any size. |
| linkDistance | number | 110 | Max px between two particles for a link. 0 disables linking. |
| repelRadius | number | 120 | Radius in px within which the pointer pushes particles away. |
| particleSize | number | 1.8 | Base dot radius in px. |
Theming
Component tokens, each falling back to a global one:
| Property | Default | Controls |
|---|---|---|
| --hk-bg-color | #dc2626 | Base hue. Every background derives its palette from it. |
Accessibility
- The canvas is aria-hidden — a decorative layer must never be announced.
- Under prefers-reduced-motion it paints one frame and never starts the loop.
- The loop stops when the element scrolls out of view and when the tab is hidden, so an offscreen background costs nothing.
- Frames run outside the Angular zone, so animating never triggers change detection in the rest of the app.
- Pointer tracking is bound outside the zone and never allocates, so moving across a dense field stays at frame rate.