Created
June 23, 2025 12:56
-
-
Save piotrkulpinski/99670628998ed3849db70b167dbf2d30 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { ComponentProps } from "react" | |
import { cva, cx } from "~/utils/cva" | |
const starsVariants = cva({ | |
base: [ | |
"overflow-hidden pointer-events-none select-none blur-[0.5px]", | |
"before:absolute before:inset-0 before:bg-radial-[at_top_center] before:from-fuchsia-950/50 before:to-transparent before:to-50%", | |
], | |
}) | |
const starsSvgVariants = cva({ | |
base: [ | |
"fill-current absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2", | |
"mask-radial-from-black mask-radial-to-transparent", | |
], | |
}) | |
export const Stars = ({ className, ...props }: ComponentProps<"div">) => { | |
const width = 872 | |
const height = 600 | |
const generateStars = (count: number) => { | |
const radii = [0.587, 0.881, 1.175] | |
const opacities = [0.11, 0.3, 1] | |
return Array.from({ length: count }, () => { | |
// Bias towards top center using a square root distribution | |
const verticalBias = Math.random() ** 2 | |
const cy = verticalBias * height | |
// Horizontal position gets more constrained as we go up | |
const horizontalSpread = 0.5 + (cy / height) * 0.5 // More spread at bottom, tighter at top | |
const cx = width / 2 + (Math.random() - 0.5) * width * horizontalSpread | |
return { | |
cx, | |
cy, | |
r: radii[Math.floor(Math.random() * radii.length)], | |
opacity: opacities[Math.floor(Math.random() * opacities.length)], | |
} | |
}) | |
} | |
return ( | |
<div className={cx(starsVariants({ className }))} {...props}> | |
<svg | |
xmlns="http://www.w3.org/2000/svg" | |
width={width} | |
height={height} | |
role="img" | |
aria-label="Stars" | |
className={cx(starsSvgVariants())} | |
> | |
{generateStars(150).map(({ cx, cy, r, opacity }, i) => ( | |
<circle key={i} cx={cx} cy={cy} r={r} opacity={opacity === 1 ? undefined : opacity} /> | |
))} | |
</svg> | |
</div> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment