145 lines
3.7 KiB
JavaScript
145 lines
3.7 KiB
JavaScript
const container = document.getElementById('stars-container');
|
|
|
|
// Create Canvas
|
|
const canvas = document.createElement('canvas');
|
|
const ctx = canvas.getContext('2d');
|
|
container.appendChild(canvas);
|
|
|
|
let width, height;
|
|
let stars = [];
|
|
let comets = [];
|
|
|
|
function resize() {
|
|
width = window.innerWidth;
|
|
height = window.innerHeight;
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
initStars();
|
|
}
|
|
|
|
class Star {
|
|
constructor() {
|
|
this.reset();
|
|
this.y = Math.random() * height; // Initial random y
|
|
}
|
|
|
|
reset() {
|
|
this.x = Math.random() * width;
|
|
this.y = Math.random() * height;
|
|
this.z = Math.random() * 2 + 0.5; // Depth/Size/Speed
|
|
this.baseSize = Math.random() * 1.5;
|
|
this.alpha = Math.random() * 0.5 + 0.1;
|
|
this.twinkle = Math.random() * 0.05;
|
|
}
|
|
|
|
update() {
|
|
this.alpha += this.twinkle;
|
|
if (this.alpha > 0.8 || this.alpha < 0.1) this.twinkle = -this.twinkle;
|
|
}
|
|
|
|
draw() {
|
|
ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;
|
|
ctx.beginPath();
|
|
const size = this.baseSize * (this.z / 2);
|
|
ctx.arc(this.x, this.y, size, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
}
|
|
}
|
|
|
|
class Comet {
|
|
constructor() {
|
|
this.reset();
|
|
}
|
|
|
|
reset() {
|
|
this.x = Math.random() * width;
|
|
this.y = Math.random() * height * 0.5;
|
|
this.len = Math.random() * 80 + 20;
|
|
this.speed = Math.random() * 5 + 2;
|
|
this.angle = Math.PI / 4 + (Math.random() - 0.5) * 0.2; // 45 degrees
|
|
this.active = false;
|
|
this.wait = Math.random() * 200 + 50;
|
|
}
|
|
|
|
update() {
|
|
if (!this.active) {
|
|
this.wait--;
|
|
if (this.wait <= 0) {
|
|
this.active = true;
|
|
this.x = Math.random() * width - 200; // Start off screen slightly
|
|
this.y = Math.random() * height * 0.5;
|
|
}
|
|
return;
|
|
}
|
|
|
|
this.x += Math.cos(this.angle) * this.speed;
|
|
this.y += Math.sin(this.angle) * this.speed;
|
|
|
|
if (this.x > width + 100 || this.y > height + 100) {
|
|
this.active = false;
|
|
this.reset();
|
|
this.wait = Math.random() * 500 + 100; // Wait longer before next
|
|
}
|
|
}
|
|
|
|
draw() {
|
|
if (!this.active) return;
|
|
|
|
// Gradient tail
|
|
const grad = ctx.createLinearGradient(
|
|
this.x, this.y,
|
|
this.x - Math.cos(this.angle) * this.len,
|
|
this.y - Math.sin(this.angle) * this.len
|
|
);
|
|
grad.addColorStop(0, 'rgba(255, 255, 255, 0.8)');
|
|
grad.addColorStop(1, 'rgba(99, 102, 241, 0)'); // Fade to purple blue
|
|
|
|
ctx.strokeStyle = grad;
|
|
ctx.lineWidth = 2;
|
|
ctx.lineCap = 'round';
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(this.x, this.y);
|
|
ctx.lineTo(
|
|
this.x - Math.cos(this.angle) * this.len,
|
|
this.y - Math.sin(this.angle) * this.len
|
|
);
|
|
ctx.stroke();
|
|
|
|
// Head
|
|
ctx.fillStyle = 'white';
|
|
ctx.beginPath();
|
|
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
// Glow
|
|
ctx.shadowBlur = 10;
|
|
ctx.shadowColor = '#6366f1';
|
|
ctx.fill();
|
|
ctx.shadowBlur = 0;
|
|
}
|
|
}
|
|
|
|
function initStars() {
|
|
stars = [];
|
|
comets = [];
|
|
for (let i = 0; i < 150; i++) stars.push(new Star());
|
|
for (let i = 0; i < 3; i++) comets.push(new Comet());
|
|
}
|
|
|
|
function animate() {
|
|
ctx.clearRect(0, 0, width, height);
|
|
|
|
// Background gradient for depth
|
|
// ctx.fillStyle = 'rgba(5, 5, 16, 0.2)';
|
|
// ctx.fillRect(0,0,width,height);
|
|
|
|
stars.forEach(s => { s.update(); s.draw(); });
|
|
comets.forEach(c => { c.update(); c.draw(); });
|
|
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
window.addEventListener('resize', resize);
|
|
resize();
|
|
animate();
|