Fortura/apps/www/public/r/bubble-background.json
2025-08-20 04:12:49 -06:00

18 lines
6.3 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "bubble-background",
"type": "registry:ui",
"title": "Bubble Background",
"description": "An interactive background featuring smoothly animated gradient bubbles, creating a playful, dynamic, and visually engaging backdrop.",
"dependencies": [
"motion"
],
"files": [
{
"path": "registry/backgrounds/bubble/index.tsx",
"content": "'use client';\n\nimport * as React from 'react';\nimport {\n motion,\n type SpringOptions,\n useMotionValue,\n useSpring,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\ntype BubbleBackgroundProps = React.ComponentProps<'div'> & {\n interactive?: boolean;\n transition?: SpringOptions;\n colors?: {\n first: string;\n second: string;\n third: string;\n fourth: string;\n fifth: string;\n sixth: string;\n };\n};\n\nfunction BubbleBackground({\n ref,\n className,\n children,\n interactive = false,\n transition = { stiffness: 100, damping: 20 },\n colors = {\n first: '18,113,255',\n second: '221,74,255',\n third: '0,220,255',\n fourth: '200,50,50',\n fifth: '180,180,50',\n sixth: '140,100,255',\n },\n ...props\n}: BubbleBackgroundProps) {\n const containerRef = React.useRef<HTMLDivElement>(null);\n React.useImperativeHandle(ref, () => containerRef.current as HTMLDivElement);\n\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const springX = useSpring(mouseX, transition);\n const springY = useSpring(mouseY, transition);\n\n React.useEffect(() => {\n if (!interactive) return;\n\n const currentContainer = containerRef.current;\n if (!currentContainer) return;\n\n const handleMouseMove = (e: MouseEvent) => {\n const rect = currentContainer.getBoundingClientRect();\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n mouseX.set(e.clientX - centerX);\n mouseY.set(e.clientY - centerY);\n };\n\n currentContainer?.addEventListener('mousemove', handleMouseMove);\n return () =>\n currentContainer?.removeEventListener('mousemove', handleMouseMove);\n }, [interactive, mouseX, mouseY]);\n\n return (\n <div\n ref={containerRef}\n data-slot=\"bubble-background\"\n className={cn(\n 'relative size-full overflow-hidden bg-gradient-to-br from-violet-900 to-blue-900',\n className,\n )}\n {...props}\n >\n <style>\n {`\n :root {\n --first-color: ${colors.first};\n --second-color: ${colors.second};\n --third-color: ${colors.third};\n --fourth-color: ${colors.fourth};\n --fifth-color: ${colors.fifth};\n --sixth-color: ${colors.sixth};\n }\n `}\n </style>\n\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n className=\"absolute top-0 left-0 w-0 h-0\"\n >\n <defs>\n <filter id=\"goo\">\n <feGaussianBlur\n in=\"SourceGraphic\"\n stdDeviation=\"10\"\n result=\"blur\"\n />\n <feColorMatrix\n in=\"blur\"\n mode=\"matrix\"\n values=\"1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -8\"\n result=\"goo\"\n />\n <feBlend in=\"SourceGraphic\" in2=\"goo\" />\n </filter>\n </defs>\n </svg>\n\n <div\n className=\"absolute inset-0\"\n style={{ filter: 'url(#goo) blur(40px)' }}\n >\n <motion.div\n className=\"absolute rounded-full size-[80%] top-[10%] left-[10%] mix-blend-hard-light bg-[radial-gradient(circle_at_center,rgba(var(--first-color),0.8)_0%,rgba(var(--first-color),0)_50%)]\"\n animate={{ y: [-50, 50, -50] }}\n transition={{ duration: 30, ease: 'easeInOut', repeat: Infinity }}\n />\n\n <motion.div\n className=\"absolute inset-0 flex justify-center items-center origin-[calc(50%-400px)]\"\n animate={{ rotate: 360 }}\n transition={{\n duration: 20,\n ease: 'linear',\n repeat: Infinity,\n repeatType: 'loop',\n }}\n >\n <div className=\"rounded-full size-[80%] top-[10%] left-[10%] mix-blend-hard-light bg-[radial-gradient(circle_at_center,rgba(var(--second-color),0.8)_0%,rgba(var(--second-color),0)_50%)]\" />\n </motion.div>\n\n <motion.div\n className=\"absolute inset-0 flex justify-center items-center origin-[calc(50%+400px)]\"\n animate={{ rotate: 360 }}\n transition={{ duration: 40, ease: 'linear', repeat: Infinity }}\n >\n <div className=\"absolute rounded-full size-[80%] bg-[radial-gradient(circle_at_center,rgba(var(--third-color),0.8)_0%,rgba(var(--third-color),0)_50%)] mix-blend-hard-light top-[calc(50%+200px)] left-[calc(50%-500px)]\" />\n </motion.div>\n\n <motion.div\n className=\"absolute rounded-full size-[80%] top-[10%] left-[10%] mix-blend-hard-light bg-[radial-gradient(circle_at_center,rgba(var(--fourth-color),0.8)_0%,rgba(var(--fourth-color),0)_50%)] opacity-70\"\n animate={{ x: [-50, 50, -50] }}\n transition={{ duration: 40, ease: 'easeInOut', repeat: Infinity }}\n />\n\n <motion.div\n className=\"absolute inset-0 flex justify-center items-center origin-[calc(50%_-_800px)_calc(50%_+_200px)]\"\n animate={{ rotate: 360 }}\n transition={{ duration: 20, ease: 'linear', repeat: Infinity }}\n >\n <div className=\"absolute rounded-full size-[160%] mix-blend-hard-light bg-[radial-gradient(circle_at_center,rgba(var(--fifth-color),0.8)_0%,rgba(var(--fifth-color),0)_50%)] top-[calc(50%-80%)] left-[calc(50%-80%)]\" />\n </motion.div>\n\n {interactive && (\n <motion.div\n className=\"absolute rounded-full size-full mix-blend-hard-light bg-[radial-gradient(circle_at_center,rgba(var(--sixth-color),0.8)_0%,rgba(var(--sixth-color),0)_50%)] opacity-70\"\n style={{\n x: springX,\n y: springY,\n }}\n />\n )}\n </div>\n\n {children}\n </div>\n );\n}\n\nexport { BubbleBackground, type BubbleBackgroundProps };\n",
"type": "registry:ui",
"target": "components/animate-ui/backgrounds/bubble.tsx"
}
]
}