# Magic Rings

> Glowing rings that pulse outward in a wave, swell toward the cursor and flare on click.

Concentric rings of light drawn with raw WebGL2. They pulse outward in a wave, ripple from the center or breathe together. Hover to make them swell and lean toward the cursor, click to send a bright ring racing outward, and use `tilt`, `spin` and `dispersion` for 3D portals, gyroscopes and prism fringes. No extra dependencies.

<demo-magic-rings>



</demo-magic-rings>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/magic-rings.json"
```

## Usage

```vue
<script setup lang="ts">
  import MagicRings from '~/components/ui/magic-rings/MagicRings.vue';
</script>

<template>
  <div class="relative h-125 w-full overflow-hidden">
    <MagicRings
      color="#A855F7"
      color-two="#6366F1"
      :ring-count="6"
      motion="pulse"
      :line-thickness="2"
      :glow="1"
      click-burst
    />
  </div>
</template>
```

The canvas is transparent, so the page background shows through. On light pages pass `theme="light"`: the rings are drawn as crisp ink with a soft halo instead of additive light, so pick darker colors.

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#A855F7'
      </code>
    </td>
    
    <td>
      Color of the innermost ring.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color-two
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#6366F1'
      </code>
    </td>
    
    <td>
      Color of the outermost ring. The rings in between blend from one to the other.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ring-count
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        6
      </code>
    </td>
    
    <td>
      Number of rings, from 1 to 12.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        motion
      </code>
    </td>
    
    <td>
      <code>
        'pulse' | 'ripple' | 'breathe'
      </code>
    </td>
    
    <td>
      <code>
        'pulse'
      </code>
    </td>
    
    <td>
      A wave that lights the rings one by one, rings flowing outward, or all rings breathing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Animation speed. <code>
        0
      </code>
      
       freezes the rings.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-thickness
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      Thickness of the rings in px. Rings are thickest at the sides and taper at the ends.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Size and strength of the glow around the rings.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        base-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.35
      </code>
    </td>
    
    <td>
      Radius of the innermost ring, as a share of the smaller side of the container.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius-step
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.1
      </code>
    </td>
    
    <td>
      Space between neighboring rings.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        expansion
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.1
      </code>
    </td>
    
    <td>
      How far each ring drifts outward while it glows.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        taper
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.5
      </code>
    </td>
    
    <td>
      How quickly outer rings shorten into side arcs. <code>
        1
      </code>
      
       keeps every ring the same length.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rotation
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Rotates the whole pattern, in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spin
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Spins the arcs, neighbors turning in opposite directions. Negative values reverse it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Leans the rings back in 3D, in degrees, like a portal seen at an angle.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dispersion
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Splits each ring into rainbow fringes like light through a prism, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        grain
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Film grain over the glow, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Overall opacity, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        follow-mouse
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      The rings drift toward the cursor.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mouse-influence
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.2
      </code>
    </td>
    
    <td>
      How far the rings drift when <code>
        follow-mouse
      </code>
      
       is on.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hover-scale
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.2
      </code>
    </td>
    
    <td>
      How much the rings swell on hover.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hover-intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How much the rings brighten and thicken near the cursor.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parallax
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.05
      </code>
    </td>
    
    <td>
      How much the rings shift and lean with the cursor, outer rings the most.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-burst
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Clicking sends a bright ring racing outward that lights up the rings as it passes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      The rings open from the sides one by one when they mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        theme
      </code>
    </td>
    
    <td>
      <code>
        'dark' | 'light'
      </code>
    </td>
    
    <td>
      <code>
        'dark'
      </code>
    </td>
    
    <td>
      Glowing light for dark pages, or crisp ink with a soft halo for light ones.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max-device-pixel-ratio
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      Highest pixel ratio the canvas renders at.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the container.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas is decorative and has `aria-hidden="true"`. Put real content on top of it; the canvas ignores pointer events, so links and buttons above it stay clickable.
- With `prefers-reduced-motion: reduce` the rings stand still, the intro and click bursts are skipped, and hover no longer moves them.
- Rendering stops while the component is off screen, the tab is hidden, or nothing is moving (`speed` 0 with no hover).
- Ported from [React Bits](https://reactbits.dev/backgrounds/magic-rings) by David Haz.
