Files
Randify.pro/src/components/Starfield.astro
T

98 lines
2.2 KiB
Plaintext

<canvas
id="starfield"
class="fixed inset-0 w-full h-full pointer-events-none"
style="z-index: 0;"
aria-hidden="true"
></canvas>
<script>
(function () {
const canvas = document.getElementById("starfield") as HTMLCanvasElement;
if (!canvas) return;
const ctx = canvas.getContext("2d");
if (!ctx) return;
let width = 0;
let height = 0;
let stars: { x: number; y: number; size: number; speed: number; opacity: number; phase: number }[] = [];
let animationId: number;
const STAR_COUNT = 180;
const TWINKLE_SPEED = 0.0008;
function resize() {
const dpr = Math.min(window.devicePixelRatio || 1, 2);
width = window.innerWidth;
height = window.innerHeight;
canvas.width = width * dpr;
canvas.height = height * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
function initStars() {
stars = [];
for (let i = 0; i < STAR_COUNT; i++) {
stars.push({
x: Math.random() * width,
y: Math.random() * height,
size: Math.random() < 0.95 ? 1 : Math.random() < 0.7 ? 1.5 : 2,
speed: 0.02 + Math.random() * 0.04,
opacity: 0.15 + Math.random() * 0.55,
phase: Math.random() * Math.PI * 2,
});
}
}
function draw(time: number) {
ctx.clearRect(0, 0, width, height);
for (const star of stars) {
const twinkle =
0.6 + 0.4 * Math.sin(time * TWINKLE_SPEED + star.phase);
const alpha = star.opacity * twinkle;
ctx.beginPath();
ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
ctx.fillStyle = `rgba(210, 210, 220, ${alpha})`;
ctx.fill();
star.y -= star.speed;
if (star.y < -2) {
star.y = height + 2;
star.x = Math.random() * width;
}
}
animationId = requestAnimationFrame(draw);
}
function start() {
resize();
initStars();
animationId = requestAnimationFrame(draw);
}
function stop() {
cancelAnimationFrame(animationId);
}
start();
window.addEventListener("resize", () => {
stop();
resize();
initStars();
start();
});
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
stop();
} else {
start();
}
});
})();
</script>