{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flipflow",
  "type": "registry:ui",
  "title": "FlipFlow",
  "description": "A looping flow of flip cards with smooth motion and subtle interactive effects.",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "clsx", "tailwind-merge"],
  "css": {
    "@layer utilities": {
      ".animate-canopy-horizontal": {
        "animation": "canopy-x var(--duration) infinite linear"
      },
      ".animate-canopy-vertical": {
        "animation": "canopy-y var(--duration) linear infinite"
      },
      ".direction-reverse.animate-canopy-horizontal": {
        "animation-direction": "reverse"
      },
      ".direction-reverse.animate-canopy-vertical": {
        "animation-direction": "reverse"
      },
      ".group:hover .group-hover\\:paused": {
        "animation-play-state": "paused"
      }
    },
    "@keyframes canopy-x": {
      "from": {
        "transform": "translateX(0)"
      },
      "to": {
        "transform": "translateX(calc(-100% - var(--gap)))"
      }
    },
    "@keyframes canopy-y": {
      "from": {
        "transform": "translateY(0)"
      },
      "to": {
        "transform": "translateY(calc(-100% - var(--gap)))"
      }
    }
  },
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/flipflow.tsx",
      "content": "'use client';\nimport { cn } from '@/lib/utils';\nimport { motion } from 'motion/react';\nimport { useState } from 'react';\n\ninterface CardData {\n  name: string;\n}\n\ninterface FlowProps extends React.HTMLAttributes<HTMLDivElement> {\n  vertical?: boolean;\n  repeat?: number;\n  reverse?: boolean;\n  pauseOnHover?: boolean;\n  applyMask?: boolean;\n}\n\nconst Flow = ({\n  children,\n  vertical = false,\n  repeat = 4,\n  pauseOnHover = false,\n  reverse = false,\n  className,\n  applyMask = true,\n  ...props\n}: FlowProps) => (\n  <div\n    {...props}\n    className={cn(\n      'group relative flex h-full w-full overflow-hidden p-1 [--duration:10s] [--gap:12px] gap-(--gap)',\n      vertical ? 'flex-col' : 'flex-row',\n      className,\n    )}\n  >\n    {Array.from({ length: repeat }).map((_, index) => (\n      <div\n        key={`item-${index}`}\n        className={cn('flex shrink-0 gap-(--gap)', {\n          'group-hover:paused': pauseOnHover,\n          'direction-reverse': reverse,\n          'animate-canopy-horizontal flex-row': !vertical,\n          'animate-canopy-vertical flex-col': vertical,\n        })}\n      >\n        {children}\n      </div>\n    ))}\n    {applyMask && (\n      <div\n        className={cn(\n          'pointer-events-none absolute inset-0 z-10 h-full w-full',\n          vertical\n            ? 'bg-linear-to-b from-background via-transparent to-background'\n            : 'bg-linear-to-r from-background via-transparent to-background',\n        )}\n      />\n    )}\n  </div>\n);\n\nconst Card = ({\n  card,\n  className,\n  colorClass,\n  backColorClass,\n}: {\n  card: CardData;\n  className?: string;\n  colorClass: string;\n  backColorClass: string;\n}) => {\n  const [flip, setFlip] = useState(false);\n\n  return (\n    <div\n      className={cn('h-20 w-48 shrink-0 cursor-pointer', className)}\n      onMouseEnter={() => setFlip(true)}\n      onMouseLeave={() => setFlip(false)}\n      style={{ perspective: '1000px' }}\n    >\n      <motion.div\n        className='relative h-full w-full'\n        animate={{ rotateX: flip ? 180 : 0 }}\n        transition={{ duration: 0.6, type: 'spring', stiffness: 100 }}\n        style={{ transformStyle: 'preserve-3d' }}\n      >\n        <motion.div\n          className='absolute inset-0 rounded-2xl overflow-hidden'\n          style={{ backfaceVisibility: 'hidden' }}\n        >\n          <div\n            className={cn(\n              'h-full w-full border-4 border-black dark:border-white rounded-2xl flex items-center justify-center px-4',\n              colorClass,\n            )}\n          >\n            <span\n              className='text-black font-black text-3xl italic tracking-normal'\n              style={{ fontFamily: 'Impact, sans-serif' }}\n            >\n              {card.name}\n            </span>\n          </div>\n        </motion.div>\n\n        <motion.div\n          className='absolute inset-0 rounded-2xl overflow-hidden'\n          style={{\n            backfaceVisibility: 'hidden',\n            transform: 'rotateX(180deg)',\n          }}\n        >\n          <div\n            className={cn(\n              'h-full w-full border-4 border-black dark:border-white rounded-2xl flex items-center justify-center px-4',\n              backColorClass,\n            )}\n          >\n            <span\n              className='text-black font-black text-3xl not-italic tracking-normal'\n              style={{ fontFamily: 'Impact, sans-serif' }}\n            >\n              {card.name}\n            </span>\n          </div>\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n};\n\nconst FlipFlow = ({\n  data,\n  className,\n  cardClassName,\n  colors = [\n    'bg-linear-to-br from-orange-500 to-orange-600',\n    'bg-linear-to-br from-blue-400 to-blue-500',\n    'bg-linear-to-br from-green-400 to-green-500',\n    'bg-linear-to-br from-pink-300 to-pink-400',\n    'bg-linear-to-br from-yellow-300 to-yellow-400',\n    'bg-linear-to-br from-purple-400 to-purple-500',\n  ],\n  backColors = [\n    'bg-linear-to-br from-cyan-500 to-cyan-600',\n    'bg-linear-to-br from-rose-400 to-rose-500',\n    'bg-linear-to-br from-amber-400 to-amber-500',\n    'bg-linear-to-br from-teal-300 to-teal-400',\n    'bg-linear-to-br from-indigo-300 to-indigo-400',\n    'bg-linear-to-br from-lime-400 to-lime-500',\n  ],\n}: {\n  data: CardData[];\n  className?: string;\n  cardClassName?: string;\n  colors?: string[];\n  backColors?: string[];\n}) => (\n  <div className={cn('w-full overflow-hidden', className)}>\n    {[false, true, false].map((reverse, index) => (\n      <Flow\n        key={`flow-${index}`}\n        reverse={reverse}\n        className='[--duration:30s]'\n        pauseOnHover\n        applyMask\n        repeat={9}\n      >\n        {data.map((card, j) => (\n          <Card\n            key={`${card.name}-${j}`}\n            card={card}\n            className={cardClassName}\n            colorClass={colors[j % colors.length]}\n            backColorClass={backColors[j % backColors.length]}\n          />\n        ))}\n      </Flow>\n    ))}\n  </div>\n);\n\nexport { FlipFlow };\n"
    },
    {
      "type": "registry:lib",
      "path": "lib/utils.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}"
    }
  ]
}
