# Dot Field

> A gradient dot field seen through a lens that follows the cursor, magnifying, pinching or swirling the dots.

Dot Field lays out thousands of gradient dots and puts a smooth lens under the cursor that magnifies, pinches or swirls them, with a soft glow in the middle. Press and hold to zoom closer. The field pulls into focus on mount, and can drift in a slow wave or sparkle like stars.

<demo-dot-field>



</demo-dot-field>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import DotField from '~/components/ui/dot-field/DotField.vue';
</script>

<template>
  <div class="relative size-full min-h-80 overflow-hidden">
    <DotField
      class="absolute inset-0 size-full"
      pattern="grid"
      gradient-from="#5227FF"
      gradient-to="#FF9FFC"
      :cursor-radius="240"
      :bulge-strength="0.6"
      :twist="0"
    />
  </div>
</template>
```

The demo presets (Lens, Vortex, Gravity, Sunflower, Honeycomb, Drift, Starfield) ship with the component. `dotFieldPreset('vortex')` returns the full set of visual props; pass `true` as the second argument for the light-page variant.

```vue
<script setup lang="ts">
  import { DotField, dotFieldPreset } from '~/components/ui/dot-field';

  const vortex = dotFieldPreset('vortex');
</script>

<template>
  <DotField v-bind="vortex" />
</template>
```

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        dot-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.5
      </code>
    </td>
    
    <td>
      Radius of each dot in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dot-spacing
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        14
      </code>
    </td>
    
    <td>
      Gap between neighbouring dots in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pattern
      </code>
    </td>
    
    <td>
      <code>
        'grid' | 'hex' | 'spiral' | 'scatter'
      </code>
    </td>
    
    <td>
      <code>
        'grid'
      </code>
    </td>
    
    <td>
      How the dots are laid out: square rows, offset honeycomb rows, a sunflower spiral or a loose scatter.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gradient-from
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#5227FF'
      </code>
    </td>
    
    <td>
      Color the gradient starts from.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gradient-to
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#FF9FFC'
      </code>
    </td>
    
    <td>
      Color the gradient ends on.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gradient-angle
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        135
      </code>
    </td>
    
    <td>
      Direction of the gradient in degrees, the same as CSS <code>
        linear-gradient
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cursor-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        240
      </code>
    </td>
    
    <td>
      Radius of the lens that follows the cursor, in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        bulge-strength
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      How much the lens magnifies the dots under it, from -1 to 1. Negative values pinch them inward.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        twist
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Swirls the dots around the cursor by this many degrees. Negative values swirl the other way.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Color the dots inside the glow light up to.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        160
      </code>
    </td>
    
    <td>
      Radius of the glow around the cursor, in pixels. 0 turns it off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow-intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.8
      </code>
    </td>
    
    <td>
      How strongly the dots inside the glow light up and bloom.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        base-opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.55
      </code>
    </td>
    
    <td>
      Opacity of the dots outside the glow, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        wave-amplitude
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      How far the dots drift in a slow rolling wave, in pixels. 0 keeps the field still.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sparkle
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      A few dots at a time softly grow and brighten, like stars twinkling.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How fast the wave and the sparkles animate.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      The lens follows the cursor or finger. Turn off for a purely ambient background.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        hold-to-zoom
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Pressing and holding deepens the lens to look closer.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      The field pulls into focus on mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        light-mode
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Prints the dots as ink so they stay crisp on light backgrounds.
    </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>
        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 marked `aria-hidden="true"`; put real content on top of it.
- With `prefers-reduced-motion: reduce`, the intro is skipped and the wave and sparkles hold still. The lens still follows the pointer.
- The render loop only runs while something moves, and stops when the field is offscreen or the tab is hidden.
- Ported from [React Bits](https://reactbits.dev/backgrounds/dot-field) by David Haz.
