# Letter Glitch

> A calm field of letters that flicker, scramble and glitch in color, stirred by the cursor and torn by clicks.

A crisp grid of letters drawn by one raw WebGL2 shader from a glyph atlas. Letters scramble quietly at rest, soft waves of light drift across them and random runs glitch into color. Move the cursor to light up and scramble the letters around it; move fast to leave a trail of glitches. Click to tear a glitch through the rows, or switch the click effect to a burst. Pick a preset in the demo panel, or press refresh to replay the boot-in flicker.

<demo-letter-glitch>



</demo-letter-glitch>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import LetterGlitch from '~/components/ui/letter-glitch/LetterGlitch.vue';
</script>

<template>
  <div class="relative h-125 w-full overflow-hidden">
    <LetterGlitch
      :glitch-colors="['#ffffff', '#61dca3']"
      :glitch-amount="0.5"
      :flow="0.5"
      click-effect="tear"
    />
  </div>
</template>
```

The demo presets ship with the component: `letterGlitchPreset('terminal', isLight)` returns the look of the Signature, Classic, Terminal, Binary, Hex, Sparse, Storm or Pixel preset, with its light-mode colors when the second argument is `true`. Its `font` and `charset` keys map to `LETTER_GLITCH_FONTS` and `LETTER_GLITCH_CHARSETS`.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        glitch-colors
      </code>
    </td>
    
    <td>
      <code>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        ['#ffffff', '#61dca3']
      </code>
    </td>
    
    <td>
      Up to 8 colors that glitching letters light up in. Light mode defaults to dark ink tones.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        base-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Color of the letters at rest. Light mode defaults to near black.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        characters
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'ABC…XYZ!@#$&*()…0-9'
      </code>
    </td>
    
    <td>
      Characters to draw. Repeat a character to make it appear more often.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-family
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'ui-monospace, …'
      </code>
    </td>
    
    <td>
      CSS font family for the letters. Web fonts are drawn once they have loaded.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        font-size
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        14
      </code>
    </td>
    
    <td>
      Size of the letters in pixels (6–96).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        spacing
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Room around each letter relative to the font size. 0 packs them like lines of text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        density
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.9
      </code>
    </td>
    
    <td>
      Share of the grid that shows a letter at rest, from 0 to 1. Empty cells still flicker.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        base-opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.16
      </code>
    </td>
    
    <td>
      Opacity of the letters at rest, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glitch-amount
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How often letters glitch, from 0 (never) to 1 (constantly).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Tempo of the scrambling and glitches. 0 freezes the letters.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        flow
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      Strength of the soft waves of light that drift across the letters, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smooth
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Fades glitching letters in and out. When off, they flicker on and off instantly.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Lights up and scrambles the letters near the cursor, leaving a trail of glitches as it moves.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cursor-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        140
      </code>
    </td>
    
    <td>
      Radius of the area around the cursor that reacts, in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-effect
      </code>
    </td>
    
    <td>
      <code>
        'tear' | 'burst' | 'none'
      </code>
    </td>
    
    <td>
      <code>
        'tear'
      </code>
    </td>
    
    <td>
      What a click does. Tear rips a glitch through the rows, burst sends glitches outward.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        edge-fade
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Fades the letters out toward the edges, from 0 to 0.5.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        center-fade
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Clears the letters behind the middle of the container to keep content readable, 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Boots the letters in with a flicker on mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        light-mode
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Switches the default colors to dark ink for light backgrounds.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        background-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Paints an opaque background behind the letters. Leave it unset for a transparent canvas.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dpr
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      auto
    </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 classes merged on the container.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas is decorative and marked `aria-hidden="true"`. Put real content above it; `center-fade` keeps the middle clear for it.
- Pointer listeners are passive and sit on `window`, so the field never steals focus or clicks from your UI.
- With `prefers-reduced-motion: reduce` there is no intro, no scrambling, no cursor effect and no click effect. The letters are drawn once and hold still.
- The render loop stops when the field is idle, offscreen or in a hidden tab.
- Ported from [React Bits](https://reactbits.dev/backgrounds/letter-glitch) by David Haz.
