# Drift Wall

> An endless perspective wall of image tiles drifting past in alternating columns, lifting a tile toward you on hover.

An endless 3D wall of tiles. Columns drift up and down at slightly different speeds. Move the pointer to tilt the wall; hover or focus a tile to stop its column and lift the tile toward you.

<demo-drift-wall>



</demo-drift-wall>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import DriftWall from '~/components/ui/drift-wall/DriftWall.vue';
  import type { DriftWallItem } from '~/components/ui/drift-wall/types';

  const items: DriftWallItem[] = [1015, 1025, 1039, 1043, 1044, 1050].map(
    (id, i) => ({
      image: `https://picsum.photos/id/${id}/600/400`,
      title: `Tile ${i + 1}`,
      href: 'https://example.com',
    }),
  );
</script>

<template>
  <div class="relative h-150 w-full overflow-hidden">
    <DriftWall
      :items="items"
      :columns="5"
      :tilt="16"
      :turn="-14"
      :speed="42"
      direction="up"
      overlay-color="#060010"
    />
  </div>
</template>
```

The wall fills its parent, so give the parent a height.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        items
      </code>
    </td>
    
    <td>
      <code>
        DriftWallItem[]
      </code>
    </td>
    
    <td>
      15 demo tiles
    </td>
    
    <td>
      Tiles to display. Each item has <code>
        { image, title?, href? }
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        columns
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        5
      </code>
    </td>
    
    <td>
      Number of drifting columns.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tile-width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        200
      </code>
    </td>
    
    <td>
      Width of each tile in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tile-height
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        132
      </code>
    </td>
    
    <td>
      Height of each tile in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gap
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        18
      </code>
    </td>
    
    <td>
      Spacing between tiles and columns in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        14
      </code>
    </td>
    
    <td>
      Corner radius of each tile in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        16
      </code>
    </td>
    
    <td>
      Perspective pitch of the wall (rotateX, degrees).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        turn
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        -14
      </code>
    </td>
    
    <td>
      Perspective yaw of the wall (rotateY, degrees).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        roll
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      In-plane rotation of the wall (rotateZ, degrees).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        perspective
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1200
      </code>
    </td>
    
    <td>
      Perspective distance in pixels. Smaller is more dramatic.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        depth
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        120
      </code>
    </td>
    
    <td>
      How far the wall sits back from the viewer in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        speed
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        42
      </code>
    </td>
    
    <td>
      Base drift speed in pixels per second.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        direction
      </code>
    </td>
    
    <td>
      <code>
        'up' | 'down'
      </code>
    </td>
    
    <td>
      <code>
        'up'
      </code>
    </td>
    
    <td>
      Primary drift direction; columns alternate around it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        variance
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.45
      </code>
    </td>
    
    <td>
      How much column speeds differ from each other (0–1).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        parallax
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Pointer-follow tilt strength (0 disables it).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pause-on-hover
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Pause the whole wall while the pointer is over it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lift
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        64
      </code>
    </td>
    
    <td>
      How far a hovered tile lifts toward the viewer in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fade
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Strength of the edge and depth dissolve (0–1).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dim
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.55
      </code>
    </td>
    
    <td>
      Resting opacity of unhovered tiles (0–1).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        grayscale
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Desaturate resting tiles; hover restores colour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        overlay-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#060010'
      </code>
    </td>
    
    <td>
      Tint laid over resting tiles, cleared on hover.
    </td>
  </tr>
</tbody>
</table>

## Theming

Set these CSS custom properties on the component to fit a light page: `--dw-surface` (tile background, default `#0b0b12`), `--dw-overlay-opacity` (default `0.42`) and `--dw-ring` (focus ring colour). The demo uses `#f4f4f5`, `0.08` and a dark ring in light mode, together with a white overlay, `dim` 0.9 and `fade` 0.38.

## Accessibility

- Each tile is focusable. Tiles with an `href` are links that open in a new tab; others have `role="button"`.
- Focus lifts the tile, stops its column and shows a focus ring.
- With `prefers-reduced-motion: reduce` the columns stop drifting and the pointer tilt is off.
- Ported from [React Bits](https://reactbits.dev/components/drift-wall) by David Haz.
