# Parallax layers (goodtabs UI)

Stacked layers drift at different rates inside a frame, transform only and capped.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/parallax-layers.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/parallax-layers`

## Usage

```tsx
import { ParallaxLayers, ParallaxLayer } from "@/components/ui/parallax-layers"

<ParallaxLayers className="h-96 rounded-lg border">
  <ParallaxLayer depth={-0.4}>
    <img src="/sky.jpg" alt="" className="size-full object-cover" />
  </ParallaxLayer>
  <ParallaxLayer depth={0.6}>
    <img src="/hills.png" alt="" className="size-full object-cover" />
  </ParallaxLayer>
</ParallaxLayers>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| range | `number` | `0.12` | Furthest any layer travels from rest, as a fraction of the frame height. |
| depth | `number` | `0` | On ParallaxLayer: 0 rides with the frame, 1 moves the full range with the scroll, -1 against it. |
| children | `ReactNode` |  | What sits on the layer, positioned inside it. |

## When to use

- A hero or feature visual that needs a little depth
- Layered illustrations and cut out images
- A quiet way to reward scrolling without pinning anything

## When not to use

- On text people need to read while it moves
- Across a whole page, because many moving planes read as noise
- When any layer needs to line up exactly with another

## Notes for agents

- GSAP installs from npm under GSAP's own licence. No GSAP code ships in this registry
- The frame needs a height from its className. Layers are absolute and give it none
- Layers paint in DOM order: far planes first, near planes last. Mark decorative layers aria-hidden
- Under reduced motion every layer stays at its rest position, the same frame you get with the frame centred

## The maths

- A layer travels ±depth × range × H, so depth 0.5 in a 672px frame at 0.12 moves ±40px.
- It overhangs top and bottom by the same amount, so travel can never reveal an edge, and |depth| is capped at 1.
- The sweep runs from frame top at window bottom to frame bottom at window top, so y is 0 exactly when the frame is centred.

Docs: https://ui.goodtabs.co/components/parallax-layers