body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
<canvas id="canvas"></canvas>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
this.y = canvas.height/2;
this.angle = Math.random() * Math.PI * 2;
this.speed = Math.random() * 1.2 + 0.3; // 更慢的速度范围
this.size = Math.random() * 2 + 1;
this.trailLength = Math.floor(Math.random() * 25 + 15); // 更长尾迹
this.maxDistance = Math.max(canvas.width, canvas.height) / 2; // 动态最大距离
this.trail.push({ x: this.x, y: this.y })
if(this.trail.length > this.trailLength) this.trail.shift()
this.x += Math.cos(this.angle) * this.speed;
this.y += Math.sin(this.angle) * this.speed;
const dx = this.x - canvas.width/2;
const dy = this.y - canvas.height/2;
const distance = Math.sqrt(dx*dx + dy*dy);
this.alpha = Math.min(distance / this.maxDistance, 1); // 距离渐显
if(this.x < 0 || this.x > canvas.width ||
this.y < 0 || this.y > canvas.height) {
this.trail.forEach((pos, index) => {
const ratio = index/this.trailLength;
ctx.arc(pos.x, pos.y, this.size * ratio, 0, Math.PI*2);
ctx.fillStyle = `rgba(255, 255, 255, ${ratio * 0.6 * this.alpha})`; // 复合透明度
ctx.arc(this.x, this.y, this.size, 0, Math.PI*2);
ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;
const meteors = Array(150).fill().map(() => new Meteor());
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; // 更淡的尾迹残留
ctx.fillRect(0, 0, canvas.width, canvas.height);
meteors.forEach(meteor => {
requestAnimationFrame(animate);
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
meteors.forEach(meteor => meteor.reset());