# Grid Scan

> A 3D grid room swept by a scanning light that follows your view.

A lit 3D room drawn with one raw WebGL2 shader: crisp grid lines, soft corner shading, a glossy floor that reflects the light and points that sparkle as the scan passes. A first scan reveals the room on mount, then scans repeat on a loop. Move the cursor and the view shifts like a window while the walls under it light up; click to send a ping across the walls. Pick a preset in the demo panel, or press refresh to replay the intro.

<demo-grid-scan>



</demo-grid-scan>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import GridScan from '~/components/ui/grid-scan/GridScan.vue';
</script>

<template>
  <div class="relative h-125 w-full overflow-hidden">
    <GridScan
      lines-color="#4d4757"
      scan-color="#7dd3fc"
      :cells="8"
      :depth="3"
      scan-direction="forward"
      click-effect="ping"
    />
  </div>
</template>
```

The demo presets ship with the component: `gridScanPreset('laser', isLight)` returns the look of the Scan, Laser, LiDAR, Blueprint, Deep, Wire or Pulse preset, with its light-mode colors when the second argument is `true`.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        lines-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#4d4757'
      </code>
    </td>
    
    <td>
      Color of the grid lines. Light mode defaults to <code>
        '#d4d4d8'
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scan-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#7dd3fc'
      </code>
    </td>
    
    <td>
      Color of the scan, trail, points and ping. Light mode defaults to <code>
        '#0284c7'
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cells
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        8
      </code>
    </td>
    
    <td>
      Number of grid cells from the floor to the ceiling (2–40).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-thickness
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Thickness of the grid lines in pixels (0.5–4).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        line-style
      </code>
    </td>
    
    <td>
      <code>
        'solid' | 'dashed' | 'dotted'
      </code>
    </td>
    
    <td>
      <code>
        'solid'
      </code>
    </td>
    
    <td>
      Style of the grid lines.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        depth
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        3
      </code>
    </td>
    
    <td>
      How deep the room goes, relative to its height. High values make a long corridor.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        depth-fade
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      How much the room fades into the distance, from 0 (even) to 1 (gone at the back).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parallax
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How far the view shifts as the cursor moves, like a head in front of a window.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shading
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.7
      </code>
    </td>
    
    <td>
      Soft light and corner shadows on the walls, from 0 (pure wireframe) to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reflection
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.35
      </code>
    </td>
    
    <td>
      How much the glossy floor reflects the scan and pings, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        points
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Scatters points over the walls that sparkle as the scan passes, like a LiDAR scan.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scan-direction
      </code>
    </td>
    
    <td>
      <code>
        'forward' | 'backward' | 'pingpong'
      </code>
    </td>
    
    <td>
      <code>
        'forward'
      </code>
    </td>
    
    <td>
      Whether the scan travels into the room, out of it, or alternates.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scan-duration
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2.4
      </code>
    </td>
    
    <td>
      Seconds each scan takes to cross the room.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scan-delay
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.6
      </code>
    </td>
    
    <td>
      Seconds between scans.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scan-width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Thickness of the scan line, from 0.2 to 5.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        trail
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How long the walls keep glowing behind the scan, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glow
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Bloom around the scan line and points, from 0 to 1.5.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        auto-scan
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Runs scans on a loop. Turn it off to scan only on click.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Moves the view with the cursor and lights up the walls under it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        click-effect
      </code>
    </td>
    
    <td>
      <code>
        'ping' | 'scan' | 'none'
      </code>
    </td>
    
    <td>
      <code>
        'ping'
      </code>
    </td>
    
    <td>
      What a click does: a ring of light across the walls, a new scan, or nothing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-webcam
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Moves the view with your head through the webcam. face-api.js loads from a CDN.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        show-preview
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Shows a small camera preview with the tracking status while the webcam is on.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        models-path
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      CDN URL
    </td>
    
    <td>
      Where the face tracking model loads from. Point it at your own copy to self-host.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        enable-gyro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Moves the view as a phone or tablet tilts. iOS asks for permission on the first tap.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Reveals the room with a first scan on mount.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        light-mode
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Renders a bright room with dark shading for light backgrounds.
    </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.
- Pointer and click listeners are passive and sit on `window`, so the room never steals focus or clicks from your UI.
- With `prefers-reduced-motion: reduce` there is no intro, no automatic scan, no drift and no click effect. The room is drawn once and holds still.
- The webcam only turns on when `enable-webcam` is set. The camera preview reports its state through a `role="status"` label.
- The render loop stops when the room is idle, offscreen or in a hidden tab.
- Ported from [React Bits](https://reactbits.dev/backgrounds/grid-scan) by David Haz.
