<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dynamic Zodiac Animation</title>
  <style>
    body, html {
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #000;
    }
    canvas {
      display: block;
    }
  </style>
</head>
<body>
<canvas id="zodiacCanvas"></canvas>

<script>
  const canvas = document.getElementById("zodiacCanvas");
  const ctx = canvas.getContext("2d");

  let width, height;
  let points = [];
  let lastMouseMove = 0;
  let mouseX = 0;
  let mouseY = 0;
  let isAggregated = false;
  let meteors = [];

  // 初始化画布
  function initCanvas() {
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
    createPoints();
    draw();
  }

  // 创建粒子
  function createPoints() {
    points = [];
    for (let i = 0; i < 200; i++) {
      points.push(createParticle(Math.random() * width, Math.random() * height));
    }
  }

  function createParticle(x, y) {
    return {
      x, y,
      vx: Math.random() * 2 - 1,
      vy: Math.random() * 2 - 1,
      tx: x,
      ty: y,
      isMeteor: false
    };
  }

  // 生成陨石
  function createMeteor() {
    const angle = Math.random() * Math.PI * 2;
    const speed = 15;
    return {
      x: mouseX + Math.cos(angle) * 500,
      y: mouseY + Math.sin(angle) * 500,
      vx: -Math.cos(angle) * speed,
      vy: -Math.sin(angle) * speed,
      tx: mouseX,
      ty: mouseY,
      isMeteor: true
    };
  }

  // 更新粒子位置
  function updateParticles() {
    const now = Date.now();
    const isMouseStatic = (now - lastMouseMove) > 2000;

    if (isMouseStatic && !isAggregated) {
      // 进入聚合状态
      isAggregated = true;
      points.forEach((p, i) => {
        const angle = (i / points.length) * Math.PI * 2;
        const radius = 50;
        p.tx = mouseX + Math.cos(angle) * radius;
        p.ty = mouseY + Math.sin(angle) * radius;
      });
      
      // 生成陨石
      for (let i = 0; i < 5; i++) {
        meteors.push(createMeteor());
      }
    }

    if (!isMouseStatic && isAggregated) {
      // 退出聚合状态
      isAggregated = false;
      points.forEach(p => {
        p.tx = p.x;
        p.ty = p.y;
      });
    }

    // 更新普通粒子
    points.forEach(p => {
      if (!p.isMeteor) {
        p.x += (p.tx - p.x) * 0.05;
        p.y += (p.ty - p.y) * 0.05;
      }
    });

    // 更新陨石粒子
    meteors = meteors.filter(meteor => {
      meteor.x += meteor.vx;
      meteor.y += meteor.vy;
      
      // 检测碰撞
      const dx = meteor.x - mouseX;
      const dy = meteor.y - mouseY;
      if (Math.sqrt(dx*dx + dy*dy) < 60) {
        // 碰撞后打散粒子
        points.forEach(p => {
          if (!p.isMeteor) {
            const angle = Math.atan2(p.y - meteor.y, p.x - meteor.x);
            p.vx = Math.cos(angle) * 8;
            p.vy = Math.sin(angle) * 8;
            p.tx = p.x + p.vx * 50;
            p.ty = p.y + p.vy * 50;
          }
        });
        return false;
      }
      return true;
    });
  }

  // 绘制函数
  function draw() {
    ctx.clearRect(0, 0, width, height);
    updateParticles();

    // 绘制连线
    ctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
    points.forEach(p1 => {
      points.forEach(p2 => {
        const dx = p1.x - p2.x;
        const dy = p1.y - p2.y;
        const dist = Math.sqrt(dx*dx + dy*dy);
        if (dist < 80 && !p1.isMeteor && !p2.isMeteor) {
          ctx.beginPath();
          ctx.moveTo(p1.x, p1.y);
          ctx.lineTo(p2.x, p2.y);
          ctx.stroke();
        }
      });
    });

    // 绘制普通粒子
    ctx.fillStyle = "white";
    points.forEach(p => {
      if (!p.isMeteor) {
        ctx.beginPath();
        ctx.arc(p.x, p.y, 1, 0, Math.PI*2);
        ctx.fill();
      }
    });

    // 绘制陨石
    ctx.fillStyle = "rgba(255, 50, 50, 0.8)";
    meteors.forEach(meteor => {
      ctx.beginPath();
      ctx.arc(meteor.x, meteor.y, 2, 0, Math.PI*2);
      ctx.fill();
    });

    requestAnimationFrame(draw);
  }

  // 鼠标事件处理
  canvas.addEventListener("mousemove", (e) => {
    mouseX = e.clientX;
    mouseY = e.clientY;
    lastMouseMove = Date.now();
    
    if (isAggregated) {
      points.forEach(p => {
        if (!p.isMeteor) {
          p.tx = p.x;
          p.ty = p.y;
        }
      });
      isAggregated = false;
    }
  });

  // 初始化
  initCanvas();
</script>
</body>
</html>