Files
2025-05-27 21:36:06 +08:00

115 lines
3.8 KiB
HTML

<style>
#canvas-stardust-container {
width: 100%; height: 100%; background: #020208; /* 非常暗的蓝黑色 */
overflow: hidden; position: relative;
}
#stardust-canvas { display: block; position: absolute; top: 0; left: 0; }
</style>
<div id="canvas-stardust-container">
<canvas id="stardust-canvas"></canvas>
</div>
<script>
(function() {
const canvas = document.getElementById('stardust-canvas');
const layerElement = canvas.closest('.terminal-custom-html-layer') || canvas.parentElement;
if (!canvas || !layerElement) return;
const ctx = canvas.getContext('2d');
let width, height, particles = [];
const particleCount = 300; // 粒子数量,根据性能调整
const baseSpeed = 0.3;
const lifeSpan = 200; // 粒子生命周期(帧数)
const baseRadius = 0.5;
const radiusVariance = 1.5;
const colors = ["#FFFFFF", "#DDDDFF", "#BBBBFF", "#9999EE"]; // 星尘颜色
class Particle {
constructor() {
this.reset();
}
reset() {
this.x = Math.random() * width;
this.y = Math.random() * height; // 初始位置随机
// 或者让粒子从一个方向进入
// this.x = Math.random() * width;
// this.y = height + Math.random() * 100; // 从底部进入
this.vx = (Math.random() - 0.5) * baseSpeed * 0.5; // x方向轻微随机漂移
this.vy = -baseSpeed - Math.random() * baseSpeed; // 主要向上流动
this.life = Math.random() * lifeSpan * 0.5 + lifeSpan * 0.5;
this.initialLife = this.life;
this.radius = baseRadius + Math.random() * radiusVariance;
this.color = colors[Math.floor(Math.random() * colors.length)];
}
update() {
this.x += this.vx;
this.y += this.vy;
this.life--;
if (this.life <= 0 || this.y < -this.radius || this.x < -this.radius || this.x > width + this.radius) {
this.reset();
}
}
draw() {
ctx.beginPath();
// 透明度随生命周期变化,实现淡入淡出
const blinkFactor = Math.sin( (this.initialLife - this.life) * 0.1 + Math.random() * Math.PI ); // 模拟闪烁
const alpha = (this.life / this.initialLife) * 0.5 + 0.3 * blinkFactor;
ctx.globalAlpha = Math.max(0, Math.min(1, alpha));
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
}
}
function init() {
width = layerElement.offsetWidth;
height = layerElement.offsetHeight;
canvas.width = width;
canvas.height = height;
particles = [];
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle());
}
}
let animationFrameId;
function animate() {
ctx.clearRect(0, 0, width, height);
ctx.globalAlpha = 1; // Reset globalAlpha for clearing
particles.forEach(p => {
p.update();
p.draw();
});
ctx.globalAlpha = 1; // Reset globalAlpha after drawing all particles
animationFrameId = requestAnimationFrame(animate);
}
let resizeTimeout;
function onResize() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
init();
animate();
}, 250);
}
init();
animate();
window.addEventListener('resize', onResize);
canvas.cleanup = function() {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
window.removeEventListener('resize', onResize);
console.log("Stardust canvas cleaned up");
};
})();
</script>