constellation_particles 1.0.0
constellation_particles: ^1.0.0 copied to clipboard
A pointer-reactive constellation particle background for Flutter. Particles drift, repel from the cursor, and link with fading lines. Near-O(n) spatial grid, zero runtime deps.
constellation_particles #
A pointer-reactive constellation particle field for Flutter. Particles drift, wrap at the edges, repel from the pointer, and link up with fading lines when they get close. No plugins, no shaders, no runtime dependencies beyond Flutter.

Why this exists #
Connecting-line particle fields are everywhere, and most of them are quietly O(n²): every frame each particle is distance-checked against every other particle to decide whether to draw a line. At 100 particles that's ~5,000 checks a frame; the effect looks great in a demo and then drops frames the moment you scale it up or put it behind real content.
This one buckets particles into a spatial hash grid whose cell size equals the connection distance. A particle can only link to something in its own cell or the eight around it, so each frame walks ~9 cells per particle instead of the whole population. The line pass stays close to O(n), and the field stays smooth with a few hundred particles on a mid web target.
A couple of other things it does so you don't have to:
- Pauses its ticker when the app is hidden or backgrounded.
- Holds still when the platform asks for reduced motion: the constellation is painted, but nothing drifts. Drifting particles in the background are the kind of motion that setting exists to stop, and honouring it should not mean the design disappears.
- Halves the particle count when the platform requests high contrast.
- Caches paints and the glow gradient, and only repaints when the simulation
actually advanced (
shouldRepaintgates on a generation counter). - Excludes itself from the semantics tree; it's decoration, not content.
Install #
flutter pub add constellation_particles
Usage #
Drop it into a Stack behind your content and give it a bounded size:
Stack(
children: [
const Positioned.fill(
child: ConstellationParticles(),
),
yourContent,
],
)
Tune it:
ConstellationParticles(
particleCount: 160,
color: const Color(0xFF64FFDA),
speed: 1.2,
connectionDistance: 140,
repulsionRadius: 220,
)
Parameters #
| Parameter | Default | Description |
|---|---|---|
particleCount |
100 |
Particles at full density; halved under high contrast. |
color |
0xFF64FFDA |
Base colour; per-particle/line opacity derived from it. |
speed |
1.0 |
Drift-speed multiplier. |
connectionDistance |
120.0 |
Max link distance, also the grid cell size. |
repulsionRadius |
200.0 |
Pointer influence radius. |
repulsionForce |
50.0 |
Pointer push strength. |
seed |
42 |
Layout seed; fixed by default for reproducible fields. |
touchReactive |
false |
Let touches drive repulsion too, not just the mouse. |
Notes #
- The mouse cursor drives repulsion on desktop and web out of the box. On
touch the field just drifts by default, which is the right call for a
background: turning it on would let the widget swallow drags meant for your
content. Set
touchReactive: truewhen the particles are a foreground surface and you want touches to push them around too. - It renders into a
RepaintBoundary, so it won't drag your content into its repaints.
License #
MIT © Yusuf İhsan Görgel
