PRISM2.0 / frontend /components /BackgroundAnimation.tsx
devranx's picture
Initial deploy with LFS images and audio
d790e98
raw
history blame
3.71 kB
import React, { useEffect, useRef } from 'react';
const BackgroundAnimation: React.FC = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
let width = window.innerWidth;
let height = window.innerHeight;
canvas.width = width;
canvas.height = height;
// Star parameters
const numStars = 400;
const speed = 2; // Speed of travel
const stars: { x: number; y: number; z: number; o: number }[] = [];
// Initialize stars
for (let i = 0; i < numStars; i++) {
stars.push({
x: Math.random() * width - width / 2,
y: Math.random() * height - height / 2,
z: Math.random() * width, // Depth
o: Math.random(), // Original z for resetting
});
}
const animate = () => {
// Clear screen with a slight fade trail for motion blur effect (optional, using clearRect for crispness now)
ctx.fillStyle = '#020617'; // Match slate-950
ctx.fillRect(0, 0, width, height);
const cx = width / 2;
const cy = height / 2;
stars.forEach((star) => {
// Move star closer
star.z -= speed;
// Reset if it passes the screen
if (star.z <= 0) {
star.z = width;
star.x = Math.random() * width - width / 2;
star.y = Math.random() * height - height / 2;
}
// Project 3D to 2D
// The factor 'width / star.z' makes things bigger as they get closer (z decreases)
const x = cx + (star.x / star.z) * width;
const y = cy + (star.y / star.z) * width;
// Calculate size based on proximity
const size = (1 - star.z / width) * 3;
// Calculate opacity based on proximity (fade in as they appear)
const opacity = (1 - star.z / width);
// Draw star
if (x >= 0 && x <= width && y >= 0 && y <= height) {
ctx.beginPath();
ctx.fillStyle = `rgba(255, 255, 255, ${opacity})`;
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
});
requestAnimationFrame(animate);
};
const animationId = requestAnimationFrame(animate);
const handleResize = () => {
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width;
canvas.height = height;
};
window.addEventListener('resize', handleResize);
return () => {
cancelAnimationFrame(animationId);
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<div className="fixed inset-0 overflow-hidden pointer-events-none z-0 bg-slate-950">
<canvas ref={canvasRef} className="absolute inset-0" />
{/* Subtle Nebula Overlay for atmosphere */}
<div className="absolute top-0 left-1/4 w-[600px] h-[600px] bg-blue-600/10 rounded-full mix-blend-screen filter blur-[120px] opacity-30 animate-blob" />
<div className="absolute bottom-0 right-1/4 w-[600px] h-[600px] bg-purple-600/10 rounded-full mix-blend-screen filter blur-[120px] opacity-30 animate-blob animation-delay-2000" />
</div>
);
};
export default BackgroundAnimation;