{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pin-scroll-gallery",
  "type": "registry:component",
  "title": "Pin scroll gallery",
  "description": "A pinned horizontal scroll gallery: the section sticks while vertical scrolling slides frames sideways. Falls back to a three column grid for reduced motion.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/premium/pin-scroll-gallery.tsx",
      "type": "registry:ui",
      "target": "components/ui/pin-scroll-gallery.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { motion, useScroll, useTransform, useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/lib/utils\"\n\nconst frames = [\n  { title: \"Compose\", body: \"Free primitives for product UI.\" },\n  { title: \"Elevate\", body: \"Motion that earns the first screen.\" },\n  { title: \"Ship\", body: \"Preview, approve and publish in one flow.\" },\n]\n\nfunction PinScrollGallery({ className }: { className?: string }) {\n  const reduce = useReducedMotion()\n  const ref = React.useRef<HTMLDivElement>(null)\n  const { scrollYProgress } = useScroll({ target: ref, offset: [\"start start\", \"end end\"] })\n  const x = useTransform(scrollYProgress, [0, 1], [\"0%\", `-${(frames.length - 1) * 100}%`])\n\n  if (reduce) {\n    return (\n      <div data-slot=\"pin-scroll-gallery\" data-tier=\"premium\" className={cn(\"grid gap-4 md:grid-cols-3\", className)}>\n        {frames.map((f) => (\n          <div key={f.title} className=\"rounded-2xl border border-border bg-surface p-6\">\n            <h3 className=\"text-xl font-medium text-fg\">{f.title}</h3>\n            <p className=\"mt-2 text-sm text-fg-muted\">{f.body}</p>\n          </div>\n        ))}\n      </div>\n    )\n  }\n\n  return (\n    <div ref={ref} data-slot=\"pin-scroll-gallery\" data-tier=\"premium\" className={cn(\"relative h-[220vh]\", className)}>\n      <div className=\"sticky top-20 overflow-hidden\">\n        <motion.div style={{ x }} className=\"flex w-full\">\n          {frames.map((f) => (\n            <div key={f.title} className=\"w-full shrink-0 px-2\">\n              <div className=\"rounded-2xl border border-border bg-surface p-10 shadow-highlight\">\n                <p className=\"text-xs font-medium tracking-[0.01em] text-fg-muted uppercase\">Pinned story</p>\n                <h3 className=\"mt-3 text-4xl font-medium tracking-[-0.026em] text-fg\">{f.title}</h3>\n                <p className=\"mt-3 max-w-md text-base leading-[1.55] text-fg-muted\">{f.body}</p>\n                <div className=\"mt-8 aspect-[16/9] rounded-xl border border-border bg-[radial-gradient(circle_at_30%_20%,color-mix(in_oklch,var(--accent)_20%,transparent),transparent_60%)] bg-sunken\" />\n              </div>\n            </div>\n          ))}\n        </motion.div>\n      </div>\n    </div>\n  )\n}\nexport { PinScrollGallery }\n"
    }
  ]
}
