nye fireworks

This commit is contained in:
2024-12-31 17:28:09 -05:00
parent 5b9edbe95f
commit ef93087215
2 changed files with 95 additions and 2 deletions
+93
View File
@@ -0,0 +1,93 @@
import { useState, useEffect, useCallback } from 'react';
interface Particle {
id: number;
angle: number;
color: string;
distance: number;
opacity: number;
x: number;
y: number;
}
export default function Firework() {
const [particles, setParticles] = useState<Particle[]>([]);
const getRandomPosition = (): { x: number; y: number } => {
// Get container dimensions (in percentage to be responsive)
return {
x: Math.random() * 100, // Random position from 0% to 100% of container width
y: Math.random() * 70 + 15, // Random position from 15% to 85% of container height
};
};
const createParticles = useCallback((): Particle[] => {
const particleCount = 30;
const colors = ['red', 'gold', 'blue', 'green', 'purple', 'pink'];
const position = getRandomPosition();
return Array.from({ length: particleCount }, (_, i) => ({
id: Date.now() + i,
angle: (i * 360) / particleCount,
color: colors[Math.floor(Math.random() * colors.length)],
distance: 0,
opacity: 1,
x: position.x,
y: position.y,
}));
}, []);
const explode = useCallback(() => {
const newParticles = createParticles();
setParticles(prev => [...prev, ...newParticles]);
setTimeout(() => {
setParticles(prev => prev.filter(p => p.id !== newParticles[0].id));
}, 500);
}, [createParticles]);
// Automatic firework launcher
useEffect(() => {
const launchInterval = setInterval(() => {
explode();
}, 2000); // Launch a new firework every 2 seconds
return () => clearInterval(launchInterval);
}, [explode]);
// Particle animation
useEffect(() => {
if (particles.length > 0) {
const animationInterval = setInterval(() => {
setParticles(prev =>
prev.map(particle => ({
...particle,
distance: particle.distance + 2,
opacity: particle.opacity - 0.02
}))
);
}, 20);
return () => clearInterval(animationInterval);
}
}, [particles.length]);
return (
<div className="fixed h-screen w-full overflow-hidden">
{particles.map(particle => (
<div
key={particle.id}
className="absolute h-2 w-2 rounded-full"
style={{
backgroundColor: particle.color,
transform: `rotate(${particle.angle}deg) translateX(${particle.distance}px)`,
opacity: particle.opacity,
transition: 'transform 20ms linear, opacity 20ms linear',
left: `${particle.x}%`,
top: `${particle.y}%`,
}}
/>
))}
</div>
);
}
+2 -2
View File
@@ -1,6 +1,6 @@
import Header from "./Header" import Header from "./Header"
import Footer from "./Footer" import Footer from "./Footer"
import Snow from "./Snow" import Firework from "./Firework";
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback } from 'react';
export default function Layout({ export default function Layout({
@@ -49,7 +49,7 @@ export default function Layout({
return ( return (
<main className="bg-black select-none text-white min-h-screen"> <main className="bg-black select-none text-white min-h-screen">
<Header isAudioActive={shouldShowAudio} /> <Header isAudioActive={shouldShowAudio} />
<Snow /> <Firework />
{children} {children}
<Footer /> <Footer />
{shouldShowAudio && <audio onEnded={() => setShouldShowAudio(false)} autoPlay={true} src={"https://storage.alexav.gg/content/0f4ce103-62d0-4ff1-8b8b-e38becced35d.mp3"} />} {shouldShowAudio && <audio onEnded={() => setShouldShowAudio(false)} autoPlay={true} src={"https://storage.alexav.gg/content/0f4ce103-62d0-4ff1-8b8b-e38becced35d.mp3"} />}