# Spectral Ribbon

> A soft spectral light ribbon on pure black — slow liquid motion and a rainbow fringe, drawn by a single WebGL fragment shader.

A glowing C-shaped light trail arcs across a black canvas. Its core runs hot cream, its edges split into a prismatic warm → green → cyan → blue → magenta fringe, and a soft noise warp keeps it drifting like liquid. It is a pure background: put hero content in the default slot.

<demo-spectral-ribbon>



</demo-spectral-ribbon>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import SpectralRibbon from '~/components/ui/spectral-ribbon/SpectralRibbon.vue';
</script>

<template>
  <SpectralRibbon class="h-140 rounded-2xl" :speed="1" :intensity="1">
    <div class="flex size-full items-end p-10">
      <h1 class="text-5xl font-semibold text-white">Ship in light.</h1>
    </div>
  </SpectralRibbon>
</template>
```

Give the root an explicit height — the canvas fills its container and the ribbon reframes itself on square and portrait aspect ratios so the full arc stays visible.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Animation speed, 0 to 2. Zero freezes the frame.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Ribbon brightness, 0.25 to 2.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        thickness
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Ribbon thickness, 0.5 to 2.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        grain
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.45
      </code>
    </td>
    
    <td>
      Film grain amount, 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Additional classes for the root 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 composed over the ribbon (<code>
        z-10
      </code>
      
      , filled).
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas is decorative (`aria-hidden="true"`, `pointer-events-none`); slot content stays fully interactive.
- With `prefers-reduced-motion: reduce` the ribbon renders one still frame and stops.
- The render loop pauses when the canvas is offscreen or the tab is hidden, and the WebGL context is released on unmount.
- Ported from [componentry.fun](https://componentry.dev/docs/components/spectral-ribbon) by Harsh Jadhav.
