Power-User Systems

Swarm

Up to a quarter of a million particles integrated entirely on the GPU, morphing between words and solids, with a drag-orbit camera. Position and velocity live in floating-point textures and never come back to the CPU; text targets are sampled once out of an offscreen canvas, so the shape can be any string with no font atlas.

Install

bun add ogl

Then copy 2 files into your project:

  • components/registry/swarm/swarm.tsx
  • hooks/use-animation-loop.ts

Props

PropTypeDefaultDescription
density"16k" | "65k" | "131k" | "262k""65k"Particle count, as discrete steps rather than a slider. Each value reallocates four floating-point targets and rebuilds the geometry, and a slider would do that on every pixel of a drag. Sixty-five thousand is where letterforms close up. The simulation is nearly free above that — the cost is all fill rate — so the top step is for a machine you already know the answer about.
shape"auto" | "text" | "sphere" | "torus" | "grid" | "disperse""auto"What the cloud is heading for. Auto walks every form in turn — text, sphere, torus, grid — before repeating, and advances the word list one entry each time it comes back around to text; the rest hold. Disperse is the exception auto never lands on: its targets are uniformly random, so it is a state to send the cloud into rather than a form to morph between. Targets are sampled out of an offscreen 2D canvas, so the text form is whatever string you pass — the GPU never sees a glyph, only a texture of positions.
swapDurationnumber3.2How long a shape holds before auto moves to the next one. This is the hold, not the travel — the morph itself is paced by morphSpeed, so a short duration with a slow morph gives a cloud that never quite arrives anywhere, which is a look rather than a mistake.
morphSpeednumber1.1How hard each particle is pulled toward its target. This is an acceleration, not a duration — the cloud arrives when the pull and the damping agree, which is why it never snaps. It also has to win against the turbulence: too low against a high curl and the letterforms never resolve, they just hover.
staggernumber0.45How much of the morph is spread across the cloud instead of happening at once. At zero every particle leaves and arrives together and it reads as a slide; near one the shape assembles over time and you can watch it build. The phase comes from each particle's own texel, so it does not reshuffle between shapes.
curlnumber0.3Curl-noise turbulence applied on the way. Curl of a vector field is divergence-free by construction, so it stirs the cloud without ever thinning it or piling it up — which is the entire reason to use curl noise rather than plain noise on a velocity field, where the cloud slowly develops holes.
dampingnumber0.9How much velocity survives each step, applied per second rather than per frame. Below about 0.8 particles arrive dead and the shape has no life in it; above 0.97 they orbit their targets forever and never settle.
repelnumber1How hard the pointer pushes particles away on hover. Dragging orbits the camera instead — sharing one gesture between the two would mean every attempt to look around also blew a hole in what you were looking at. The falloff is exponential in squared distance, so the hole has a soft edge and the cloud closes behind your cursor rather than leaving a permanent scar.
pointSizenumber1.6Point sprite width, and the real performance control. Doubling it costs four times the shading at any density — at a quarter of a million particles the simulation is trivial and the fill rate is what falls over, which is the opposite of where most people expect the cost to be.
zoomnumber1How close the camera sits to the cloud. Sprite size scales with it: leaving the points fixed makes a zoomed-in cloud read as sparser rather than nearer, which is the tell that a zoom is really a viewport crop.
autoSpinbooleantrueIdle rotation while nothing is being dragged. Off holds the cloud still and hands the camera entirely to the pointer — a flung orbit still coasts to rest, since that motion was asked for. The drift exists to show the form is solid rather than a flat sprite, so turning it off is a choice about a still image, not a performance one.
particleColorstring (hex)"#a855f7"The colour of a settled particle.
accentColorstring (hex)"#67e8f9"The colour of a moving one. Particles are blended between the two by their own speed, so the palette is a readout of the simulation rather than decoration laid over it.
backgroundColorstring (hex)"#04040a"The void behind the cloud. Points blend additively, so this wants to stay genuinely dark — anything lighter and the dense core clips to white before the count is visible.

What It Demonstrates

Loop
An animation that repeats, a set number of times or infinitely.
Morph
One shape smoothly turns into another shape, e.g. Dynamic Island.
Stagger
Animate several items one after another with a small delay between each, creating a cascade.
Interpolation / Tween
Generating all the in-between frames between a start and end value, so motion is continuous.
Idle animation
Subtle motion that plays while an element is just sitting there, waiting to be interacted with.
Hover effect
Visual change when the cursor moves over an element.

Related Components

Appears In