# Warp Text

The text is drawn into a texture and rendered through a WebGL glass shader. Slow noise keeps the letters gently undulating. Move the cursor over the text to bend it with a lens that bulges, pinches or swirls, with optional color fringing. Click to send a shockwave ring through the letters. When the cursor leaves, the lens keeps wandering over the words. On mount, the text fades in from a strong warp and settles.

<demo-warp-text>



</demo-warp-text>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import WarpText from '~/components/ui/warp-text/WarpText.vue';
</script>

<template>
  <div class="relative h-112 w-full overflow-hidden rounded-3xl">
    <WarpText
      text="Bend the moment"
      lens="swirl"
      :pointer-strength="0.5"
      :chromatic="0.35"
      class="absolute inset-0 size-full"
    />
  </div>
</template>
```

The component fills its container, so give the parent a real height. The text color follows `currentColor` by default and re-rasterises when the inherited color changes, so it follows light and dark mode.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        text
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Bend the moment'
      </code>
    </td>
    
    <td>
      The headline drawn into the WebGL texture. Use <code>
        \n
      </code>
      
       for line breaks.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'currentColor'
      </code>
    </td>
    
    <td>
      Text fill before the glass pass. Follows the surrounding text color by default.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        warp-strength
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.08
      </code>
    </td>
    
    <td>
      Amount of ambient glass distortion at rest.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        warp-scale
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.7
      </code>
    </td>
    
    <td>
      Size of the moving distortion cells.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.55
      </code>
    </td>
    
    <td>
      Speed of the ambient undulation.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lens
      </code>
    </td>
    
    <td>
      <code>
        'bulge' | 'pinch' | 'swirl'
      </code>
    </td>
    
    <td>
      <code>
        'bulge'
      </code>
    </td>
    
    <td>
      How the cursor bends the text: magnify it, pull it inward or twist it around the pointer.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pointer-influence
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.42
      </code>
    </td>
    
    <td>
      Radius of the cursor lens.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pointer-strength
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.38
      </code>
    </td>
    
    <td>
      Strength of cursor-driven bending and magnification.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        idle-drift
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.2
      </code>
    </td>
    
    <td>
      How strongly the lens keeps wandering while the cursor is away, from <code>
        0
      </code>
      
       (fades) to <code>
        1
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        chromatic
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Color fringing inside the lens and click ripples. <code>
        0
      </code>
      
       is off, <code>
        1
      </code>
      
       is strong.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        refraction
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.018
      </code>
    </td>
    
    <td>
      Subtle RGB channel split for the glass edge.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ripple
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Adds a soft ripple to the pointer lens.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-ripple
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Clicking sends a shockwave ring through the text that bends the letters as it passes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Fades the text in from a strong warp that settles.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-size
      </code>
    </td>
    
    <td>
      <code>
        string | number
      </code>
    </td>
    
    <td>
      <code>
        'clamp(3rem, 10vw, 9rem)'
      </code>
    </td>
    
    <td>
      Raster font size. Numbers are pixels. The text shrinks to fit the container.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-weight
      </code>
    </td>
    
    <td>
      <code>
        string | number
      </code>
    </td>
    
    <td>
      <code>
        800
      </code>
    </td>
    
    <td>
      Font weight used when rasterising the text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-family
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'inherit'
      </code>
    </td>
    
    <td>
      Font family used when rasterising the text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        letter-spacing
      </code>
    </td>
    
    <td>
      <code>
        string | number
      </code>
    </td>
    
    <td>
      <code>
        '-0.06em'
      </code>
    </td>
    
    <td>
      Tracking applied while drawing the text. Numbers are pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-height
      </code>
    </td>
    
    <td>
      <code>
        string | number
      </code>
    </td>
    
    <td>
      <code>
        0.9
      </code>
    </td>
    
    <td>
      Line height for multi-line text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The root has `role="img"` and an `aria-label` with the text. The canvas is `aria-hidden`.
- With `prefers-reduced-motion`, the intro and ambient undulation are off, the lens runs at 35% strength and click ripples are softer.
- If WebGL is unavailable or the context is lost, the text renders as plain styled HTML.
- The render loop pauses when the component is offscreen or the tab is hidden.
- Ported from [React Bits](https://reactbits.dev/text-animations/warp-text) by David Haz.
