Particle Halo
A ring of colored particles that breathes in and out with elastic + back easings. The cursor angle around the center sweeps the breathe progress, so the wave follows your pointer.
particle-halo
Particle halo
Build lazily.
Move your cursor around the ring to sweep the wave.
0px
Customize
Edit props; preview updates instantly.
Customize
Color 1
Color 2
Shape
Mode
Particles
1800
Radius
0.70
Intensity
1.00x
Cycle
16.0s
Trail
0.00
Max size
8px
Props
Props accepted by ParticleHalo.
| Prop | Type | Default | Description |
|---|---|---|---|
| particleCount | number | 1800 | How many particles ride the ring. Auto-halves to 1000 on viewports under 600 px on either axis. Larger counts give a denser ring at the cost of per-frame fill time. |
| colors | string[] | ["#a3a3a3","#f8f8f8"] | Palette each particle samples from. Repeating an entry biases probability. Any number of CSS color strings — the customize panel exposes two free-pick slots; downstream you can pass more. |
| shape | "circle" | "square" | "line" | "spark" | "circle" | Particle render shape. `circle` and `square` read as dots; `line` draws a radial streak that lengthens with wave intensity (best paired with `trail` > 0 for a liquid look); `spark` is a perpendicular cross. |
| mode | "wave" | "pulse" | "spiral" | "chaos" | "wave" | How each particle samples the global progress. `wave` rolls a single wave around the ring; `pulse` breathes the entire ring in unison (no spatial offset); `spiral` runs three overlapping waves; `chaos` gives each particle a random phase so the ring shimmers without structure. |
| trail | number | 0 | Trail fade per frame (0–0.95). `0` clears the canvas fully each frame; higher values leave the previous frame visible underneath, smearing particles into dye-like streaks. Values around 0.85 with `shape="line"` produce a liquid-reveal feel. |
| radius | number | 0.7 | Ring radius as a fraction of the canvas's smaller dimension. `0.5` is a tight inner ring; `1` packs particles against the canvas edge. |
| intensity | number | 1 | Multiplier on the radial breathing amplitude. `0` freezes the ring as a perfect circle; `2` doubles the peak drift so the wave swells well beyond the base radius. |
| duration | number | 16 | Seconds per full breathe cycle (shrink + grow). The wave's apparent rotation around the ring scales with this. Mouse-hover overrides the auto-cycle until the cursor is idle for 1 second. |
| particleSize | [number, number] | [2, 8] | Min / max particle diameter in pixels. Each particle picks one size in this range at build time. |
| glow | boolean | true | Applies a CSS `drop-shadow` filter to the canvas so each particle has a soft halo. Cheap — single GPU compositor pass. Toggle off for flat, crisp dots. |
| glowColor | string | brightest entry in `colors` | CSS color used by the glow drop-shadow. Defaults to the last entry in `colors`, which is usually the brightest. |
| background | string | "#050505" | Solid fill drawn beneath the particles each frame. The screen-blend particle pass paints over it, so use a dark color for a luminous effect. |
| className | string | — | Extra class names merged onto the outer wrapper. Width and height are governed here — the canvas fills the container. |
Installation
Choose CLI for the one-line shadcn install, or copy the file manually.
npx shadcn@latest add https://2lazyui.com/r/particle-halo.json
Usage
Import the component and drop it into a render.
demo.tsx21 lines
import { ParticleHalo } from "@/components/lazy-ui/particle-halo"; export function Demo() { return ( <div className="relative h-[640px] w-full overflow-hidden rounded-2xl"> <ParticleHalo colors={["#7c3aed", "#f5f3ff"]} shape="line" mode="wave" trail={0.85} radius={0.7} intensity={1} duration={16} className="absolute inset-0" /> <span className="pointer-events-none absolute inset-0 flex items-center justify-center text-7xl font-semibold tracking-tighter text-white"> Build lazily. </span> </div> ); }