Getting Started
Scroll Animations
Text Animations
Hover & Cursor
Sliders & Carousels
Galleries & Grids
Menus & Navigation
Preloaders & Intros
Page Transitions
3D & WebGL
import { NameSwapScroll } from "@/registry/tween/name-swap-scroll"
export function NameSwapScrollDemo() {
return <NameSwapScroll />
}
import { NameSwapScroll } from "@/components/ui/name-swap-scroll"<NameSwapScroll
visuals={["/plates/0362.jpg", "/plates/0548.jpg"]}
names={[
{
label: "PLATES",
d: "M0 0H100V20H0Z",
viewBox: "0 0 100 20",
fill: "#F4D23C",
},
{ label: "0362", d: "...", viewBox: "...", fill: "#E0249A" },
{ label: "0548", d: "...", viewBox: "...", fill: "#FF6A13" },
]}
/>The frame pins for one viewport height per name after the first. Names are inline SVG paths drawn with preserveAspectRatio="none", so each one stretches to fill the frame (the first at full width, the rest at three quarters, aligned right).
Scroll progress is mapped to a position along the list. The current name collapses with scaleY from its top edge while the next one grows from its bottom edge, so they appear to push each other out. Each visual scales in from the bottom-left corner during its step, then shrinks and drifts up by driftAmount percent during the next one.
The trigger uses usePreviewScroller, and a ResizeObserver rebuilds it on resize. With prefers-reduced-motion: reduce the header and first visual are shown statically.
| Prop | Type | Default | Description |
|---|---|---|---|
names | NameSwapName[] | 7 names | { label, d, viewBox, fill }. The first is the header; the rest pair with visuals. |
visuals | string[] | 6 photos | Images that scale in, one per name after the header. Defaults load from Unsplash. |
driftAmount | number | 300 | How far (in % of its height) a visual drifts up as it exits. |
background | string | "#0f0f0f" | Frame background. |
scroller | HTMLElement | string | null | — | Optional ScrollTrigger scroller; defaults to the preview one. |
className | string | — | Extra classes on the outer container. |