# Swarm Cursor

> A liquid swarm of particles that flows after the cursor, curls into eddies and pours around hovered buttons.

A WebGL2 particle swarm that rides a small fluid simulation. It flows after the cursor, curls into eddies when the cursor rests, pours around hovered links and buttons, and splashes when you click. Move the pointer over the demo, rest it, hover a button, then click.

<demo-swarm-cursor>



</demo-swarm-cursor>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import SwarmCursor from '~/components/ui/swarm-cursor/SwarmCursor.vue';
</script>

<template>
  <div class="relative h-130 w-full overflow-hidden bg-zinc-950">
    <SwarmCursor
      :count="800"
      :size="2.6"
      shape="dot"
      color="#ffffff"
      :spread="90"
      :swirl="0.6"
      :tail="0.5"
      idle="roam"
      click-effect="burst"
    >
      <div class="flex size-full flex-col items-center justify-center gap-6">
        <h1 class="text-4xl font-semibold text-white">
          Teams move faster in formation
        </h1>
        <button type="button">Start for free</button>
      </div>
    </SwarmCursor>
  </div>
</template>
```

The swarm fills its container and draws behind the default slot. Give the container a size, put your hero or buttons in the slot, and the particles pour around any element that matches `targets` while it is hovered. Add `data-swarm-target` to any other element you want the swarm to wrap.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        count
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        800
      </code>
    </td>
    
    <td>
      Number of particles in the swarm, up to 2000.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2.6
      </code>
    </td>
    
    <td>
      Size of each particle, in px.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shape
      </code>
    </td>
    
    <td>
      <code>
        'dot' | 'streak' | 'square'
      </code>
    </td>
    
    <td>
      <code>
        'dot'
      </code>
    </td>
    
    <td>
      Shape of each particle.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Color of the particles. Defaults to near black in light mode.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        accent-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        color
      </code>
    </td>
    
    <td>
      Color particles take on when they rush and when you click.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spread
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        90
      </code>
    </td>
    
    <td>
      Radius of the swarm around the cursor, in px.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How lively the swarm churns and turns while the cursor rests.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        swirl
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      How much the swarm curls into eddies and how long they keep turning, from 0 (calm) to 1 (stormy).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tail
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How far the swarm streams behind a fast cursor, from 0 (tight) to 1 (a long trailing tail).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trail
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Motion blur on fast particles.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wander
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How restlessly the swarm folds and drifts on its own.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        depth
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.7
      </code>
    </td>
    
    <td>
      How much near particles grow and blur and far ones shrink and fade, from 0 (flat) to 1 (deep).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        targets
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'a, button, [data-swarm-target]'
      </code>
    </td>
    
    <td>
      Elements inside the swarm that it pours around while hovered. Pass an empty string to turn this off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        idle
      </code>
    </td>
    
    <td>
      <code>
        'roam' | 'gather' | 'hide'
      </code>
    </td>
    
    <td>
      <code>
        'roam'
      </code>
    </td>
    
    <td>
      What the swarm does while the cursor is away: drift around the area, wait in the middle, or fade out.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-effect
      </code>
    </td>
    
    <td>
      <code>
        'burst' | 'pulse' | 'none'
      </code>
    </td>
    
    <td>
      <code>
        'burst'
      </code>
    </td>
    
    <td>
      What a click does. Burst splashes the swarm outward in a curl, pulse sends a wave of light through it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hide-cursor
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Hides the system cursor over the component and marks the pointer with a dot, so the swarm becomes the cursor.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Swirls the swarm in from across the area on mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Shows and animates the swarm.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        light-mode
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Uses near black particles by default and keeps them crisp, for light backgrounds.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dpr
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        auto
      </code>
    </td>
    
    <td>
      Maximum device pixel ratio, capped at 2.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra class names for the container.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        style
      </code>
    </td>
    
    <td>
      <code>
        CSSProperties
      </code>
    </td>
    
    <td>
      <code>
        -
      </code>
    </td>
    
    <td>
      Inline styles for the container.
    </td>
  </tr>
</tbody>
</table>

## Slots

<table>
<thead>
  <tr>
    <th>
      Slot
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      Content the swarm flows behind, such as a hero with buttons.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas carries `aria-hidden="true"`; the swarm is decorative and not keyboard focusable.
- When `hide-cursor` is enabled the system cursor is hidden over the component — use sparingly, as it removes the default pointer for mouse users.
- The swarm responds to pointer movement; touch and pen input also move it, and the swarm returns to its idle mode when a touch ends.
- With `prefers-reduced-motion: reduce` the swarm draws one still frame, gathered at the center, and click effects are off.
- The animation pauses while the component is offscreen or the tab is hidden.

---

- Ported from [React Bits](https://reactbits.dev/animations/swarm-cursor) by David Haz.
