# Decal — Animated Card for React

> A matte label stuck to a dark surface that physically peels — hover lifts and curls a corner back to reveal a lit paper-grey underside with a cyan specular rim and a growing drop shadow, while grabbing deepens the peel, leans the sticker, and drags it with weight before it settles home. Faint adhesive glue-string filaments stretch and snap as it lifts; the peel origin is a 360° knob. Coarse pointers and reduced motion get a static half-peeled frame with drag disabled.

- Page: https://crucibleui.com/components/cards/decal
- Category: [cards](https://crucibleui.com/components/cards)
- Tier: pro (one-time purchase, see https://crucibleui.com/pricing)
- Engine: gsap
- npm dependencies: gsap

## Install

```bash
npx shadcn@latest add @crucible/decal
```

Pro install requires adding the token-bearing `@crucible` registry to components.json (issued at https://crucibleui.com/account after purchase).

Import from `@/components/crucible/decal`.

## Props (`DecalProps`)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `children?` | `React.ReactNode` | — | Content printed on the sticker face (kept upright as the sticker rotates). |
| `peelDirection?` | `number` | `45` | Direction the corner peels from, in degrees (0 = top edge, 90 = right edge). |
| `peelBackHoverPct?` | `number` | `30` | How far the corner lifts on hover, as a percent of the sticker's side length. |
| `peelBackActivePct?` | `number` | `44` | How far the corner lifts while grabbed/dragged, as a percent of the side length. |
| `dragRotate?` | `number` | `12` | Max degrees the sticker leans as you drag it sideways. |
| `width?` | `number` | `220` | Sticker side length in px (it is square). |
| `shadowIntensity?` | `number` | `0.55` | Depth/opacity of the drop shadow the lifting sticker casts, 0–1. |
| `lightingIntensity?` | `number` | `0.6` | Strength of the revealed underside lighting + specular rim, 0–1. |
| `accent?` | `string` | `"#67e8f8"` | Accent color of the thin specular line riding the rolled edge. |
| `faceColor?` | `string` | `"#f2f0ea"` | Matte sticker face color. |
| `undersideColor?` | `string` | `"#c3cbd2"` | Cool paper-grey color revealed on the peeled-back underside. |
| `draggable?` | `boolean` | `true` | Enable grab-and-drag. Ignored on coarse pointers / reduced motion. |
| `speed?` | `number` | `1` | Settle-speed multiplier (higher = snappier). |
| `paused?` | `boolean` | `false` | Freeze to a static, invitingly half-peeled frame with no interaction. |
| `label?` | `string` | `"Sticker"` | Accessible label for the sticker region. |

Also accepts: `Omit<React.ComponentPropsWithoutRef<"div">, "children">`.

## Usage example

```tsx
"use client";

import { Decal } from "@/components/crucible/decal";

export default function DecalDemo() {
  return (
    <div className="relative isolate flex h-full min-h-[360px] w-full items-center justify-center overflow-hidden rounded-xl bg-neutral-950">
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_50%_40%,rgba(255,255,255,0.045),transparent_65%)]"
      />
      {/* Faint surface texture so the peeled reveal reads against a real material. */}
      <div
        aria-hidden
        className="pointer-events-none absolute inset-0 opacity-[0.04] [background:repeating-linear-gradient(45deg,#fff_0,#fff_1px,transparent_1px,transparent_10px)]"
      />
      <div className="relative z-10 flex flex-col items-center gap-6">
        <Decal width={220} />
        <p className="pointer-events-none text-sm text-neutral-500">
          Peel the corner — or grab it and drag.
        </p>
      </div>
    </div>
  );
}
```

## Accessibility & performance

Honors `prefers-reduced-motion` with a designed static frame or fade (never a blank box) and passes `className` through.
