87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
import { useMemo } from 'react';
|
|
|
|
const HEX_COUNT = 50;
|
|
|
|
interface HexConfig {
|
|
size: number;
|
|
opacity: number;
|
|
top: number;
|
|
left: number;
|
|
driftDuration: number;
|
|
bobDuration: number;
|
|
bobAmount: number;
|
|
delay: number;
|
|
reverse: boolean;
|
|
}
|
|
|
|
function generateHexes(): HexConfig[] {
|
|
const hexes: HexConfig[] = [];
|
|
for (let i = 0; i < HEX_COUNT; i++) {
|
|
const driftDuration = 40 + Math.random() * 60;
|
|
hexes.push({
|
|
size: 10 + Math.random() * 32,
|
|
opacity: 0.06 + Math.random() * 0.18,
|
|
top: Math.random() * 100,
|
|
left: Math.random() * 100,
|
|
driftDuration,
|
|
bobDuration: 6 + Math.random() * 8,
|
|
bobAmount: 8 + Math.random() * 30,
|
|
delay: -Math.random() * driftDuration,
|
|
reverse: Math.random() < 0.3,
|
|
});
|
|
}
|
|
return hexes;
|
|
}
|
|
|
|
export default function HexCanvas({
|
|
isDark = false,
|
|
animated = true,
|
|
className = '',
|
|
}: {
|
|
isDark?: boolean;
|
|
animated?: boolean;
|
|
className?: string;
|
|
}) {
|
|
const hexes = useMemo(generateHexes, []);
|
|
|
|
return (
|
|
<div
|
|
className={`absolute inset-0 overflow-hidden pointer-events-none ${className}`.trim()}
|
|
style={{ zIndex: 0 }}
|
|
>
|
|
{hexes.map((hex, i) => (
|
|
<div
|
|
key={i}
|
|
className="absolute"
|
|
style={{
|
|
top: `${hex.top}%`,
|
|
...(animated
|
|
? {
|
|
animation: `hex-drift ${hex.driftDuration}s linear ${hex.delay}s infinite${hex.reverse ? ' reverse' : ''}`,
|
|
}
|
|
: {
|
|
left: `${hex.left}%`,
|
|
transform: `translate(-50%, -50%) rotate(${hex.delay * 12}deg)`,
|
|
}),
|
|
}}
|
|
>
|
|
<div
|
|
className="bg-teal-500"
|
|
style={
|
|
{
|
|
width: hex.size,
|
|
height: (hex.size * 2) / Math.sqrt(3),
|
|
opacity: hex.opacity * (isDark ? 0.45 : 0.6),
|
|
clipPath: 'polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)',
|
|
animation: animated
|
|
? `hex-bob ${hex.bobDuration}s ease-in-out infinite`
|
|
: undefined,
|
|
'--bob': `${hex.bobAmount}px`,
|
|
} as React.CSSProperties
|
|
}
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|