# Sticker Peel

> A die-cut sticker you can peel at any edge, drag, throw and swing, in gloss, matte or holographic finishes.

A die-cut sticker rendered in WebGL 2. Hover it to peel back the edge nearest your cursor, then drag and throw it: it swings around the point you hold, slides and bounces off the edges of its parent. Pick a gloss, matte or holographic finish.

<demo-sticker-peel>



</demo-sticker-peel>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import StickerPeel from '~/components/ui/sticker-peel/StickerPeel.vue';

  const onDrop = () => console.log('sticker dropped');
</script>

<template>
  <div class="relative h-100 w-full overflow-hidden">
    <StickerPeel
      image-src="/stickers/nxui.png"
      finish="gloss"
      :width="200"
      :curl-radius="12"
      @drag-end="onDrop"
    />
  </div>
</template>
```

Use an image with a transparent background: the alpha channel sets the die-cut outline, the hit area and the shadow. The sticker positions itself inside its nearest parent, so give that parent a real size and `position: relative`.

## Props

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

<tbody>
  <tr>
    <td>
      <code>
        image-src
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Sticker image. Use a PNG with a transparent background so the die-cut outline shows.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        200
      </code>
    </td>
    
    <td>
      Width of the sticker in pixels. Minimum 16.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rotate
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Resting rotation of the sticker in degrees.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        finish
      </code>
    </td>
    
    <td>
      <code>
        'gloss' | 'matte' | 'holo'
      </code>
    </td>
    
    <td>
      <code>
        'gloss'
      </code>
    </td>
    
    <td>
      Surface of the sticker. Holo turns light areas into foil with rainbow bands and glitter.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        back-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#d4d4d8'
      </code>
    </td>
    
    <td>
      Color of the back of the sticker, seen on the peeled part.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        peel-direction
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Edge that peels, in degrees clockwise from the top.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        peel-back-hover-pct
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        25
      </code>
    </td>
    
    <td>
      How far the sticker peels back on hover, as a percentage of its size.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        peel-back-active-pct
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        40
      </code>
    </td>
    
    <td>
      How far the sticker peels back while pressed or dragged.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        curl-radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        12
      </code>
    </td>
    
    <td>
      Radius of the curl where the sticker bends, in pixels. Larger values feel like thicker vinyl.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lighting-intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      Strength of the highlights that follow the cursor, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        shadow-intensity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      Strength of the shadows under the sticker and the peeled part, from 0 to 1.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        follow-pointer
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Peels the edge or corner nearest the cursor, and the edge you grab while dragging.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        draggable
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Lets the sticker be picked up, dragged and thrown around its parent.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        swing
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How much the sticker swings around the point you hold while dragging, from 0 to 3.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        friction
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.5
      </code>
    </td>
    
    <td>
      How quickly a thrown sticker slides to a stop, from 0 (ice) to 1 (felt).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        bounce
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.35
      </code>
    </td>
    
    <td>
      How much of its speed a thrown sticker keeps when it hits the edge of its parent.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        intro
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Drops the sticker onto the surface on mount and smooths its corner down.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        initial-position
      </code>
    </td>
    
    <td>
      <code>
        'center' | { x: number; y: number }
      </code>
    </td>
    
    <td>
      <code>
        'center'
      </code>
    </td>
    
    <td>
      Starting position. An object offsets the sticker from the center of its parent, in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dpr
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        auto
      </code>
    </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 for the root element.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        style
      </code>
    </td>
    
    <td>
      <code>
        CSSProperties
      </code>
    </td>
    
    <td>
      <code>
        -
      </code>
    </td>
    
    <td>
      Inline styles for the root element.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        drag-start
      </code>
    </td>
    
    <td>
      none
    </td>
    
    <td>
      Fired when the sticker starts being dragged.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        drag-end
      </code>
    </td>
    
    <td>
      none
    </td>
    
    <td>
      Fired when a dragged sticker is released.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The canvas is decorative and marked `aria-hidden`. Add a visible caption or an `aria-label` on a parent if the sticker carries meaning.
- With `prefers-reduced-motion: reduce` the intro is skipped and the sticker rests flat.
- The render loop stops while the sticker is offscreen or idle, and the WebGL context is released on unmount.
- Needs WebGL 2. Without it the component renders nothing.
- Ported from [React Bits](https://reactbits.dev/animations/sticker-peel) by David Haz.
