# Splash Cursor

> A WebGL fluid simulation that trails the cursor in swirling ink and bursts into a splash on click.

A real-time fluid simulation follows your pointer as one unbroken stroke of ink whose color shifts as you move. Click or tap to burst a petal-shaped splash, and the effect rests when nothing moves. Use it full-screen over a page or `contained` inside one section, with a light theme where the ink absorbs instead of glowing.

<demo-splash-cursor>



</demo-splash-cursor>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import { SplashCursor } from '~/components/ui/splash-cursor';
</script>

<template>
  <!-- Covers the whole viewport and ignores pointer events -->
  <SplashCursor :colors="['#a855f7']" :rainbow="false" />

  <!-- Or only inside one section -->
  <section class="relative h-125">
    <SplashCursor contained :swirl="8" :trail="2.2" />
  </section>
</template>
```

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        colors
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        ['#4f8cff', '#2dd4bf', '#ffd166']
      </code>
    </td>
    
    <td>
      Palette the ink cycles through when <code>
        rainbow
      </code>
      
       is off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rainbow
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Cycles through the full spectrum instead of the palette.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color-speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How fast the colors shift while you move. <code>
        0
      </code>
      
       keeps one color per stroke.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How much ink each movement leaves behind.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Width of the stroke and the splash.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        force
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How hard the cursor pushes the fluid.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        swirl
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        3
      </code>
    </td>
    
    <td>
      Amount of curling eddies in the flow.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trail
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How long the ink lingers before it fades. <code>
        2
      </code>
      
       lasts twice as long.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        momentum
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How long the fluid keeps moving after the cursor stops.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shading
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Depth shading on the ripples, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Soft bloom around the brightest ink, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        quality
      </code>
    </td>
    
    <td>
      <code>
        'low' | 'medium' | 'high'
      </code>
    </td>
    
    <td>
      <code>
        'high'
      </code>
    </td>
    
    <td>
      Simulation detail. Lower settings are lighter on older devices.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-splash
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Bursts a splash where you click or tap.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Plays a short stroke across the screen on mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        contained
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Fills the parent element instead of the viewport and only reacts inside it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        theme
      </code>
    </td>
    
    <td>
      <code>
        'dark' | 'light'
      </code>
    </td>
    
    <td>
      <code>
        'dark'
      </code>
    </td>
    
    <td>
      Glowing ink for dark backgrounds or absorbing ink for light ones.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        z-index
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        50
      </code>
    </td>
    
    <td>
      Stacking order of the effect over your content.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes merged on the container.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The overlay is `aria-hidden` and `pointer-events: none`, so it never blocks clicks, focus or screen readers.
- The intro stroke is skipped when `prefers-reduced-motion: reduce` is set; ink only appears in response to the user's own pointer.
- The render loop stops and the canvas clears once the ink has faded, so an idle page costs nothing.
- Needs WebGL2 with half-float render targets; without them the component renders nothing.
- Ported from [React Bits](https://reactbits.dev/animations/splash-cursor) by David Haz.
