{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-parallax",
  "title": "Hero Parallax",
  "description": "A scroll-driven grid of cards that drift in alternating directions on a tilted perspective plane.",
  "dependencies": ["framer-motion"],
  "registryDependencies": ["@godui/godui-theme"],
  "files": [
    {
      "path": "packages/components/src/hero-parallax/hero-parallax.tsx",
      "content": "\"use client\";\n\nimport {\n  type MotionValue,\n  motion,\n  useReducedMotion,\n  useScroll,\n  useSpring,\n  useTransform,\n} from \"framer-motion\";\nimport * as React from \"react\";\n\nexport type HeroParallaxItem = {\n  title: string;\n  thumbnail: string;\n  href?: string;\n};\n\nexport type HeroParallaxProps = React.HTMLAttributes<HTMLDivElement> & {\n  /** Cards to scatter across the parallax rows (best with ~15). */\n  products: HeroParallaxItem[];\n  /** Replaces the default headline block. */\n  header?: React.ReactNode;\n  /**\n   * Scrollport for measuring progress. Defaults to the viewport — pass a\n   * ref to an overflow container when embedding the hero in a framed demo.\n   */\n  scrollContainer?: React.RefObject<HTMLElement | null>;\n};\n\n// SPRING.smooth — surfaces / shared-layout feel.\nconst SPRING = { stiffness: 320, damping: 32, mass: 0.9 } as const;\n\nfunction ProductCard({\n  product,\n  translate,\n}: {\n  product: HeroParallaxItem;\n  translate: MotionValue<number>;\n}) {\n  const Wrapper = product.href ? motion.a : motion.div;\n  return (\n    <Wrapper\n      style={{ x: translate }}\n      whileHover={{ y: -20 }}\n      transition={SPRING}\n      href={product.href}\n      className=\"group/card relative h-64 w-[26rem] shrink-0\"\n    >\n      <img\n        src={product.thumbnail}\n        alt={product.title}\n        draggable={false}\n        className=\"absolute inset-0 size-full rounded-xl object-cover shadow-lg [outline:1px_solid_color-mix(in_oklch,var(--border)_60%,transparent)] [outline-offset:-1px]\"\n      />\n      <div className=\"pointer-events-none absolute inset-0 rounded-xl bg-black/50 opacity-0 transition-opacity duration-300 group-hover/card:opacity-100\" />\n      <h3 className=\"absolute bottom-4 left-4 text-white opacity-0 transition-opacity duration-300 group-hover/card:opacity-100\">\n        {product.title}\n      </h3>\n    </Wrapper>\n  );\n}\n\nconst HeroParallax = React.forwardRef<HTMLDivElement, HeroParallaxProps>(\n  ({ products, header, className, scrollContainer, ...props }, ref) => {\n    const reduce = useReducedMotion();\n    const containerRef = React.useRef<HTMLDivElement>(null);\n    React.useImperativeHandle(\n      ref,\n      () => containerRef.current as HTMLDivElement,\n    );\n\n    const firstRow = products.slice(0, 5);\n    const secondRow = products.slice(5, 10);\n    const thirdRow = products.slice(10, 15);\n\n    const { scrollYProgress } = useScroll({\n      target: containerRef,\n      container: scrollContainer,\n      offset: [\"start start\", \"end start\"],\n    });\n\n    const translateX = useSpring(\n      useTransform(scrollYProgress, [0, 1], [0, 1000]),\n      SPRING,\n    );\n    const translateXReverse = useSpring(\n      useTransform(scrollYProgress, [0, 1], [0, -1000]),\n      SPRING,\n    );\n    const rotateX = useSpring(\n      useTransform(scrollYProgress, [0, 0.2], [15, 0]),\n      SPRING,\n    );\n    const opacity = useSpring(\n      useTransform(scrollYProgress, [0, 0.2], [0.2, 1]),\n      SPRING,\n    );\n    const rotateZ = useSpring(\n      useTransform(scrollYProgress, [0, 0.2], [20, 0]),\n      SPRING,\n    );\n    const translateY = useSpring(\n      useTransform(scrollYProgress, [0, 0.2], [-700, 200]),\n      SPRING,\n    );\n\n    const defaultHeader = (\n      <div className=\"relative top-0 left-0 mx-auto w-full max-w-7xl px-4 py-20 md:py-40\">\n        <h2 className=\"text-2xl font-bold text-foreground md:text-7xl\">\n          The ultimate <br /> showcase reel\n        </h2>\n        <p className=\"mt-8 max-w-2xl text-base text-muted-foreground md:text-xl\">\n          Scroll to send the grid drifting on a perspective plane. Drop in your\n          own work and let the motion do the talking.\n        </p>\n      </div>\n    );\n\n    // Reduced motion: a calm static grid, no scroll-driven transforms.\n    if (reduce) {\n      return (\n        <div\n          ref={containerRef}\n          data-slot=\"hero-parallax\"\n          className={`py-10 ${className ?? \"\"}`}\n          {...props}\n        >\n          {header ?? defaultHeader}\n          <div className=\"mx-auto grid max-w-7xl grid-cols-2 gap-4 px-4 md:grid-cols-3\">\n            {products.slice(0, 9).map((product) => (\n              <div key={product.title} className=\"relative h-64 w-full\">\n                <img\n                  src={product.thumbnail}\n                  alt={product.title}\n                  className=\"size-full rounded-xl object-cover shadow-lg\"\n                />\n              </div>\n            ))}\n          </div>\n        </div>\n      );\n    }\n\n    return (\n      <div\n        ref={containerRef}\n        data-slot=\"hero-parallax\"\n        className={`relative flex h-[300vh] flex-col self-auto [perspective:1000px] [transform-style:preserve-3d] ${className ?? \"\"}`}\n        {...props}\n      >\n        {header ?? defaultHeader}\n        <motion.div\n          style={{ rotateX, rotateZ, translateY, opacity }}\n          className=\"[transform-style:preserve-3d]\"\n        >\n          <motion.div className=\"mb-20 flex flex-row-reverse space-x-20 space-x-reverse\">\n            {firstRow.map((product) => (\n              <ProductCard\n                key={product.title}\n                product={product}\n                translate={translateX}\n              />\n            ))}\n          </motion.div>\n          <motion.div className=\"mb-20 flex flex-row space-x-20\">\n            {secondRow.map((product) => (\n              <ProductCard\n                key={product.title}\n                product={product}\n                translate={translateXReverse}\n              />\n            ))}\n          </motion.div>\n          <motion.div className=\"flex flex-row-reverse space-x-20 space-x-reverse\">\n            {thirdRow.map((product) => (\n              <ProductCard\n                key={product.title}\n                product={product}\n                translate={translateX}\n              />\n            ))}\n          </motion.div>\n        </motion.div>\n      </div>\n    );\n  },\n);\nHeroParallax.displayName = \"HeroParallax\";\n\nexport { HeroParallax };\n",
      "type": "registry:ui",
      "target": "components/godui/hero-parallax.tsx"
    }
  ],
  "type": "registry:ui"
}
