# Lanyard

> Swinging 3D badge on a stretchy woven band that you can drag, throw or click to flip.

A three.js ID badge hanging from a woven strap. The band stretches and snaps back, a light breeze keeps it moving, and the card has real momentum. Drag it to stretch and throw it, or click it to flip it over. Pass any image for the front, back and band; no models or setup are needed.

<demo-lanyard>



</demo-lanyard>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import Lanyard from '~/components/ui/lanyard/Lanyard.vue';
</script>

<template>
  <div class="relative h-125 w-full">
    <Lanyard
      front-image="/badge-front.webp"
      back-image="/badge-back.webp"
      strap-image="/band.png"
      finish="holographic"
      metal="gold"
      :strap-length="0.5"
    />
  </div>
</template>
```

The component fills its parent, so give the parent a height. Images load with `crossOrigin="anonymous"`; remote images must send CORS headers.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        front-image
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Image URL printed on the front of the card. Any size or aspect works.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        back-image
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Image URL printed on the back. Falls back to <code>
        front-image
      </code>
      
      , then to a blank card.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        image-fit
      </code>
    </td>
    
    <td>
      <code>
        'cover' | 'contain'
      </code>
    </td>
    
    <td>
      <code>
        'cover'
      </code>
    </td>
    
    <td>
      Cover fills and crops; contain fits inside on the card colour.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        card-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#ffffff'
      </code>
    </td>
    
    <td>
      Colour of the card, shown when there is no image and around contained images.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        orientation
      </code>
    </td>
    
    <td>
      <code>
        'portrait' | 'landscape'
      </code>
    </td>
    
    <td>
      <code>
        'portrait'
      </code>
    </td>
    
    <td>
      Whether the card hangs tall or wide.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        finish
      </code>
    </td>
    
    <td>
      <code>
        'glossy' | 'matte' | 'holographic' | 'metallic'
      </code>
    </td>
    
    <td>
      <code>
        'glossy'
      </code>
    </td>
    
    <td>
      Card surface. Holographic adds a sparkling foil that shifts as the card turns; metallic a brushed sheen.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        corner-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.3
      </code>
    </td>
    
    <td>
      Corner roundness, from 0 (square) to 1 (very round).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        size
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Card height as a fraction of the container height.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        anchor
      </code>
    </td>
    
    <td>
      <code>
        'left' | 'center' | 'right'
      </code>
    </td>
    
    <td>
      <code>
        'center'
      </code>
    </td>
    
    <td>
      Where the band hangs from along the top edge.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strap-length
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How far below the top edge the card hangs, from 0 (short) to 1 (long).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strap-image
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Image URL printed along the band. A wide image repeats along its length; its height spans the band width.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strap-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#111111'
      </code>
    </td>
    
    <td>
      Band colour when there is no strap image.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        strap-width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.65
      </code>
    </td>
    
    <td>
      Band width relative to its default, from 0.4 to 2.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        metal
      </code>
    </td>
    
    <td>
      <code>
        'graphite' | 'silver' | 'gold'
      </code>
    </td>
    
    <td>
      <code>
        'silver'
      </code>
    </td>
    
    <td>
      Finish of the clamp and the ring that holds the card.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gravity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How strongly the card falls. Lower values float and swing slowly; 0 turns gravity off.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        damping
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How quickly the swing dies down, from 0 (long sway) to 1 (quick settle).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        elasticity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How hard the band snaps the card back after it is stretched.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        breeze
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      A gentle, changing wind that keeps the card moving when nobody touches it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Lets visitors drag, stretch and throw the card, and click it to flip it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      On mount the card drops in from the side and swings into place.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the root element.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas is decorative (`aria-hidden`); put any information printed on the badge in the page text as well.
- With `prefers-reduced-motion: reduce` the intro drop and the breeze are off, so the card only moves when dragged.
- On touch screens the page still scrolls vertically unless the drag starts on the card.
- Rendering pauses while the component is off screen and once the card comes to rest with no breeze.

## Credits

- Ported from [React Bits](https://reactbits.dev/components/lanyard) by David Haz.
