# Image Trail

> A trail of photos that appears behind the cursor, with tunable size, timing, zoom, flash, drift, 3D tilt, rotation and a stacking pile.

Move the cursor (or drag a finger) across the area and photos drop in behind it, then fade away. One tunable trail replaces the old fixed variants: change how big and how long the photos stay, let them pop in with a zoom and flash, drift after the cursor, tilt in 3D, turn to face the motion, or pile up in a stack. Try the four presets in the panel.

<demo-image-trail>



</demo-image-trail>

## Installation

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

## Usage

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

```vue
<script setup lang="ts">
  import ImageTrail from '~/components/ui/image-trail/ImageTrail.vue';

  const items = [
    'https://picsum.photos/id/287/300/300',
    'https://picsum.photos/id/1001/300/300',
    'https://picsum.photos/id/1025/300/300',
    'https://picsum.photos/id/1026/300/300',
  ];
</script>

<template>
  <div class="relative h-100 overflow-hidden">
    <!-- "Pop" preset -->
    <ImageTrail :items="items" :appear-scale="0" :zoom="2.4" :flash="0.6" />
  </div>
</template>
```

## 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>
        string[]
      </code>
    </td>
    
    <td>
      <code>
        []
      </code>
    </td>
    
    <td>
      Image URLs shown in the trail, in order.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        number | string
      </code>
    </td>
    
    <td>
      <code>
        190
      </code>
    </td>
    
    <td>
      Width of each image in px, or any CSS length.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aspect-ratio
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1.1
      </code>
    </td>
    
    <td>
      Width divided by height for each image.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number | string
      </code>
    </td>
    
    <td>
      <code>
        15
      </code>
    </td>
    
    <td>
      Corner radius of the images.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        threshold
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        80
      </code>
    </td>
    
    <td>
      How far the cursor travels, in px, before the next image appears.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lifetime
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.4
      </code>
    </td>
    
    <td>
      Seconds an image stays before it fades out.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        appear-scale
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Size an image starts at as it appears. 0 grows it from nothing, 1 shows it at full size.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        zoom
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How far each photo starts zoomed in before settling inside its frame. 1 turns it off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        flash
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Brightness flash as an image appears, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        exit-scale
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.2
      </code>
    </td>
    
    <td>
      Size an image shrinks or grows to while it fades out. 1 keeps its size.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        drift
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      How far images keep flying in the direction of the cursor as they fade, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rotation
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Random tilt of each image, in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size-variance
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Random size variation between images, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        align-to-motion
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Turns each image to face the direction the cursor is moving.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        stack
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Keeps this many of the newest images on screen in a pile instead of fading each. 0 turns off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Tilts images in 3D toward the edge where they appear, in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the container.
    </td>
  </tr>
</tbody>
</table>

### Presets

<table>
<thead>
  <tr>
    <th>
      Preset
    </th>
    
    <th>
      Props
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Classic
    </td>
    
    <td>
      defaults
    </td>
  </tr>
  
  <tr>
    <td>
      Pop
    </td>
    
    <td>
      <code>
        appear-scale: 0
      </code>
      
      , <code>
        zoom: 2.4
      </code>
      
      , <code>
        flash: 0.6
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Drift
    </td>
    
    <td>
      <code>
        appear-scale: 0.1
      </code>
      
      , <code>
        align-to-motion
      </code>
      
      , <code>
        drift: 0.8
      </code>
      
      , <code>
        exit-scale: 1
      </code>
      
      , <code>
        lifetime: 0.6
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Stack
    </td>
    
    <td>
      <code>
        stack: 7
      </code>
      
      , <code>
        rotation: 4
      </code>
      
      , <code>
        size-variance: 0.6
      </code>
      
      , <code>
        appear-scale: 0.7
      </code>
      
      , <code>
        exit-scale: 1.3
      </code>
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The images are decorative and use `pointer-events: none`, so they never block clicks on content underneath.
- With `prefers-reduced-motion: reduce` no images are spawned.
- The animation loop only runs while the pointer moves or images are still animating.
- Ported from [React Bits](https://reactbits.dev/animations/image-trail) by David Haz.
