# Zoom handover (goodtabs UI)

A framed image scales up to fill the window, then hands over to the content inside it.

## Install

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

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

## Usage

```tsx
import { ZoomHandover } from "@/components/ui/zoom-handover"

<ZoomHandover aria-label="Inside the product" src="/product.jpg" alt="" lead={<h2>A frame is a promise.</h2>}>
  <h3>Now the image is the room.</h3>
</ZoomHandover>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| src | `string` |  | The image in the frame, required. |
| alt | `string` |  | Describes the image, required. Empty when decorative. |
| lead | `ReactNode` |  | Sits above the frame at rest and leaves first. |
| frame | `number` | `0.66` | Frame size at rest, as a fraction of the viewport. |
| pace | `number` | `2.4` | Pin distance, as a multiple of the viewport height. |
| children | `ReactNode` |  | The content the frame hands over to. |

## When to use

- A hero that needs to walk people into the product
- Moving from a single image to the section that explains it
- Once on a landing page, as the opening move

## When not to use

- For reference content people need to reach fast: a plain image and heading is quicker
- Next to another pinned section, because two pins back to back feel like a trap
- Inside a scaled or transformed parent, which breaks ScrollTrigger's measuring

## Notes for agents

- GSAP installs from npm under GSAP's own licence. No GSAP code ships in this registry
- It pins against the window, so it must not sit inside an overflow container or a CSS transform
- Below 768px and under reduced motion there is no pin: a lead, a full width image, then the content
- Give it an aria-label, because it renders a section landmark

## The maths

- The frame is one number: rest scale 0.66 of the window, so 1280 by 800 rests at 845 by 528 and the aspect never changes.
- Layout radius is 12px / 0.66 = 18.2px, so the frame reads 12px at rest while it is laid out at full size.
- Corners clear the window once the frame overhangs by 0.293r, so the end scale is 1 + 2(0.293r + 1) / min(w, h), 1.016 at 800px tall.

Docs: https://ui.goodtabs.co/components/zoom-handover