Skip to content

Swarm

Add a flock that roams the page, then gathers and circles the pointer.

import { Swarm } from '@youj/motion/backgrounds'

Experimental: what this label means

Installation & usage

npm i @youj/motion

For 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.

Reference

Propscolors, intensity, speed… (7)

Props

Swarm props
PropType
colors[boids: string, highlight: string]

[boids, highlight] CSS colors. Default: --color-fg-muted, --color-accent.

–
intensitynumber

Opacity of the flock, 0–1.5.

default 1

1
speednumber

Flight speed multiplier.

default 1

1
densitynumber

Boids per area, relative. 1 ≈ one boid per 3 800 CSS px².

default 1

1
sizenumber

Size of each boid, 0.5–2.5.

default 1

1
interactiveboolean

Pointer reactivity: the flock gathers and circles the pointer.

default true

true
classNamestring–
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

Motion tokens
MomentTokens
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-hidden and 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.