Swarm
Add a flock that roams the page, then gathers and circles the pointer.
import { Swarm } from '@youj/motion/backgrounds'
Installation & usage
npm i @youj/motionFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use it where the idea is a group moving as one: teams, communities, collaboration, anything with many small parts and one direction. It's playful without being busy, and the pointer gives it a hook that people reach for. Don't use it behind reading-length text, and keep it to one animated background per page.
The flock fills its nearest positioned ancestor and paints behind your content, so make the container relative and isolate.
import { Swarm } from '@youj/motion/backgrounds'
export function TeamHero() {
return (
<section className="relative isolate min-h-[560px]">
<Swarm />
<p className="relative text-5xl font-semibold">Everyone moving the same way</p>
</section>
)
}Each boid steers by three rules: back away from a neighbor that is too close, match the heading of the neighbors in sight, and drift toward their center. A slow personal wander keeps the flock roaming instead of settling, and the edges turn boids back before they leave. The number of boids follows the area, so a phone and a wide display look equally full.
Description
A hero section over the flock; move the pointer across it and the boids gather around it and circle.
colors takes two CSS colors: the boids, then the highlight for the ones circling the pointer. The defaults are --color-fg-muted and --color-accent. Token references follow the theme, and the flock rereads them when the theme changes.
Controls for the size of the flock, the size of each boid and the pointer.
densitysets how many boids there are per area. It defaults to 1, which is one per 3,800 square pixels, capped at 480.size, from 0.5 to 2.5, scales each boid. It defaults to 1.intensity(0 to 1.5) sets how strongly the flock shows, andspeedhow fast it flies.
The pointer calls the flock. Boids within reach turn toward it, settle on a circle around it and keep turning, and the ones in the circle take the highlight color. When the pointer leaves, the flock goes back to roaming. Set interactive={false} where the flock sits behind something people work in.
A small, slow flock behind an empty state, with no pointer response.
At a low density, intensity and speed, and without pointer response, the flock is company for an empty room rather than a show.
Code
swarm-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propscolors, intensity, speed… (7)
Props
| Prop | Type | |
|---|---|---|
colors | [boids: string, highlight: string][boids, highlight] CSS colors. Default: | – |
intensity | numberOpacity of the flock, 0–1.5. default 1 | 1 |
speed | numberFlight speed multiplier. default 1 | 1 |
density | numberBoids per area, relative. 1 ≈ one boid per 3 800 CSS px². default 1 | 1 |
size | numberSize of each boid, 0.5–2.5. default 1 | 1 |
interactive | booleanPointer reactivity: the flock gathers and circles the pointer. default true | true |
className | string | – |
PerformanceIt's drawn with Canvas 2D, not WebGL
Performance
It's drawn with Canvas 2D, not WebGL. Boids only look at their neighbors, which come from a spatial grid sized to their sight, so the cost grows with the size of the flock and not with its square. The boids are darts batched into a few fills by opacity. The canvas renders at a device-pixel ratio capped at 2, and the low motion budget keeps 60% of the flock. The loop pauses when the flock is offscreen or the tab is hidden, and it stops and cleans up on unmount. If the browser can't create a 2D context, it falls back to a static CSS wash of the highlight color.
MotionFlocking, wander, pointer orbit · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Flockingseparation, alignment and cohesion with neighbors in sight | no token speed ÷ time scale | speed ÷ time scale | |
| Wandera slow sideways drift that is different for every boid | no token per-boid phase | per-boid phase | |
| Pointer orbitboids in reach turn toward the pointer and circle it | no token per-frame physics | per-frame physics | |
| Pointer strengtheases in and out with the pointer | no token smoothed per frame | smoothed per frame |
Reduced motion
Draws one fixed, seeded flock: the same composition every time. There's no flight and no pointer response, and it redraws only when the size, the props or the theme change.
Reduced motion
The flock shows a fixed composition from a seeded layout that has already settled into streams, so it's the same on every visit and in every screenshot. Only the flight and the pointer response are gone. Switch on Reduced motion in any preview above to compare.
AccessibilityARIA
Accessibility
- It's decorative: the element is
aria-hiddenand ignores pointer events. - Boids pass over whatever sits above them. Keep a quiet pool of canvas behind the copy, as the hero preview does, or lower
intensity, and check your text's contrast there. - The flight is slow and stops offscreen. Under reduced motion the flock doesn't move at all.