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

18 lines
4.5 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "stars-background",
"type": "registry:ui",
"title": "Stars Background",
"description": "A dark, interactive background featuring animated dots of varying sizes and speeds, simulating a dynamic and immersive starry space effect.",
"dependencies": [
"motion"
],
"files": [
{
"path": "registry/backgrounds/stars/index.tsx",
"content": "'use client';\n\nimport * as React from 'react';\nimport {\n type HTMLMotionProps,\n motion,\n type SpringOptions,\n type Transition,\n useMotionValue,\n useSpring,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\ntype StarLayerProps = HTMLMotionProps<'div'> & {\n count: number;\n size: number;\n transition: Transition;\n starColor: string;\n};\n\nfunction generateStars(count: number, starColor: string) {\n const shadows: string[] = [];\n for (let i = 0; i < count; i++) {\n const x = Math.floor(Math.random() * 4000) - 2000;\n const y = Math.floor(Math.random() * 4000) - 2000;\n shadows.push(`${x}px ${y}px ${starColor}`);\n }\n return shadows.join(', ');\n}\n\nfunction StarLayer({\n count = 1000,\n size = 1,\n transition = { repeat: Infinity, duration: 50, ease: 'linear' },\n starColor = '#fff',\n className,\n ...props\n}: StarLayerProps) {\n const [boxShadow, setBoxShadow] = React.useState<string>('');\n\n React.useEffect(() => {\n setBoxShadow(generateStars(count, starColor));\n }, [count, starColor]);\n\n return (\n <motion.div\n data-slot=\"star-layer\"\n animate={{ y: [0, -2000] }}\n transition={transition}\n className={cn('absolute top-0 left-0 w-full h-[2000px]', className)}\n {...props}\n >\n <div\n className=\"absolute bg-transparent rounded-full\"\n style={{\n width: `${size}px`,\n height: `${size}px`,\n boxShadow: boxShadow,\n }}\n />\n <div\n className=\"absolute bg-transparent rounded-full top-[2000px]\"\n style={{\n width: `${size}px`,\n height: `${size}px`,\n boxShadow: boxShadow,\n }}\n />\n </motion.div>\n );\n}\n\ntype StarsBackgroundProps = React.ComponentProps<'div'> & {\n factor?: number;\n speed?: number;\n transition?: SpringOptions;\n starColor?: string;\n pointerEvents?: boolean;\n};\n\nfunction StarsBackground({\n children,\n className,\n factor = 0.05,\n speed = 50,\n transition = { stiffness: 50, damping: 20 },\n starColor = '#fff',\n pointerEvents = true,\n ...props\n}: StarsBackgroundProps) {\n const offsetX = useMotionValue(1);\n const offsetY = useMotionValue(1);\n\n const springX = useSpring(offsetX, transition);\n const springY = useSpring(offsetY, transition);\n\n const handleMouseMove = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {\n const centerX = window.innerWidth / 2;\n const centerY = window.innerHeight / 2;\n const newOffsetX = -(e.clientX - centerX) * factor;\n const newOffsetY = -(e.clientY - centerY) * factor;\n offsetX.set(newOffsetX);\n offsetY.set(newOffsetY);\n },\n [offsetX, offsetY, factor],\n );\n\n return (\n <div\n data-slot=\"stars-background\"\n className={cn(\n 'relative size-full overflow-hidden bg-[radial-gradient(ellipse_at_bottom,_#262626_0%,_#000_100%)]',\n className,\n )}\n onMouseMove={handleMouseMove}\n {...props}\n >\n <motion.div\n style={{ x: springX, y: springY }}\n className={cn({ 'pointer-events-none': !pointerEvents })}\n >\n <StarLayer\n count={1000}\n size={1}\n transition={{ repeat: Infinity, duration: speed, ease: 'linear' }}\n starColor={starColor}\n />\n <StarLayer\n count={400}\n size={2}\n transition={{\n repeat: Infinity,\n duration: speed * 2,\n ease: 'linear',\n }}\n starColor={starColor}\n />\n <StarLayer\n count={200}\n size={3}\n transition={{\n repeat: Infinity,\n duration: speed * 3,\n ease: 'linear',\n }}\n starColor={starColor}\n />\n </motion.div>\n {children}\n </div>\n );\n}\n\nexport {\n StarLayer,\n StarsBackground,\n type StarLayerProps,\n type StarsBackgroundProps,\n};\n",
"type": "registry:ui",
"target": "components/animate-ui/backgrounds/stars.tsx"
}
]
}