MagicRings
magic-ringsDraws layered reactive rings that follow and frame the pointer.
Usage
Basic usage
Put relative + overflow-hidden into the dark container, MagicRings is covered with absolute inset-0.
<div className="relative h-64 overflow-hidden rounded-xl bg-neutral-950">
<MagicRings className="absolute inset-0" />
</div>Dense Ring · Slow
ringCount increases the number of layers, speed reduces the speed, and radiusStep tightens the ring spacing to obtain wallpaper-level dense rings.
<MagicRings
className="absolute inset-0"
ringCount={9}
speed={0.5}
radiusStep={0.07}
/>Two-color with petal split
color/colorTwo sets the inner and outer colors, and the ring color is interpolated according to the layer; ringGap enlarges the angular crack to form a petal shape.
<MagicRings
className="absolute inset-0"
color="var(--color-chart-3)"
colorTwo="oklch(0.72 0.22 30)"
ringGap={2.2}
attenuation={8}
/>Mouse Parallax · Click Burst
followMouse enables parallax following, clickBurst allows clicks to briefly zoom in and out, and hoverScale controls hover zoom.
<MagicRings
className="absolute inset-0"
followMouse
clickBurst
hoverScale={1.25}
/>When to Use
As a whole decorative background, it renders concentric halo ripples (two-color interpolation) that continuously expand and fade out, suitable for login page/hero/empty status shading. For a pouring volumetric laser, use LaserFlow, and for a border streamer surrounding a single element, use BorderBeam; this component is a "radial diffusion ripple" atmosphere layer. It is recommended that className="absolute inset-0" fill the parent container.
Import
import { MagicRings } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| color | string | var(--color-chart-1) | Inner circle starting color, light and dark theme; any CSS color string can be used |
| colorTwo | string | var(--color-chart-4) | The outer ring termination color, the halo color is linearly interpolated according to the number of layers between color→colorTwo |
| speed | number | 1 | Animation-speed multiplier; higher values expand the rings faster |
| ringCount | number | 6 | Number of simultaneous rings, clamped to 1–10 |
| attenuation | number | 10 | Ring attenuation; higher values produce sharper, shorter-lived rings, while lower values are more diffuse |
| lineThickness | number | 2 | Loop thickness magnification |
| baseRadius | number | 0.35 | Innermost circle starting radius (normalized to approximately 0–1) |
| radiusStep | number | 0.1 | Increasing step size of the starting radius of two adjacent circles |
| scaleRate | number | 0.1 | The expansion range of the inner ring radius in a single life cycle |
| opacity | number | 1 | Overall opacity, overlaid on luminance-derived alpha |
| blur | number | 0 | CSS blur radius (px), >0 add filter:blur to the canvas |
| noiseAmount | number | 0.1 | Grain noise intensity, 0=clean |
| rotation | number | 0 | Overall rotation angle (degrees) |
| ringGap | number | 1.5 | Width of angular gaps in each ring; higher values create deeper, more petal-like cuts |
| fadeIn | number | 0.7 | Single loop fade-in ratio (early stage of life cycle) |
| fadeOut | number | 0.5 | Single loop fade-out starting point ratio (late period of life cycle) |
| followMouse | boolean | false | The halo follows the mouse displacement to generate parallax |
| mouseInfluence | number | 0.2 | The influence coefficient of the mouse on the overall displacement when followMouse |
| hoverScale | number | 1.2 | Overall zoom target value on hover |
| parallax | number | 0.05 | Parallax dislocation coefficient of each layer with mouse |
| clickBurst | boolean | false | Click burst (shortly enlarge + brighten when clicked) |
| className | string | — | Additional class name for the root container or fallback div |
Usage Guidelines
- WebGL (ogl) component, cleanup and
loseContextunder React StrictMode dual mounting will poison the canvas reuse and cause it to go blank. A new canvas should be created internally every time it is mounted, see [[webgl-canvas-loseContext-poisons-strictmode-remount]]. - The parent container must be
relative+ dark background, and the halo should be filled withabsolute inset-0. - With reduced motion or without WebGL, the component falls back to static concentric rings; do not rely on the expansion animation.
Related
BorderBeam · ShineBorder · GlareHover · Lens · AnimatedBeam · OrbitingCircles
Playground
<div className="relative h-64 overflow-hidden rounded-xl"
style={{ background: "oklch(0.14 0.02 280)" }}>
<MagicRings
className="absolute inset-0"
ringCount={6}
speed={1}
attenuation={10}
ringGap={1.5}
blur={0}
followMouse={false}
clickBurst={false}
/>
</div>