分享图
动画工坊
引擎就绪

看起来之前的动画没有成功生成,我来为你创建一个视觉冲击力强的自动播放动画演示:

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>星际潮汐 · Cosmic Tide</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Noto+Sans+SC:wght@100;300;400&display=swap" rel="stylesheet">
<style>
  :root {
    --bg: #04060f;
    --fg: #e8ecf5;
    --accent: #00e5c3;
    --accent2: #ff6b35;
    --muted: rgba(255,255,255,0.12);
    --glow: rgba(0,229,195,0.35);
  }

  *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    background: var(--bg);
    color: var(--fg);
    font-family: 'Noto Sans SC', sans-serif;
    overflow: hidden;
    width: 100vw;
    height: 100vh;
    cursor: none;
  }

  canvas#cosmic {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    z-index: 1;
  }

  /* 自定义光标 */
  .cursor-dot {
    position: fixed;
    width: 8px; height: 8px;
    background: var(--accent);
    border-radius: 50%;
    pointer-events: none;
    z-index: 1000;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 20px var(--glow), 0 0 60px var(--glow);
    transition: width 0.2s, height 0.2s;
  }

  .cursor-ring {
    position: fixed;
    width: 40px; height: 40px;
    border: 1.5px solid rgba(0,229,195,0.4);
    border-radius: 50%;
    pointer-events: none;
    z-index: 1000;
    transform: translate(-50%, -50%);
    transition: transform 0.15s ease-out, width 0.3s, height 0.3s, border-color 0.3s;
  }

  /* 覆盖层文字 */
  .overlay {
    position: fixed;
    top: 0; left: 0;
    width: 100%; height: 100%;
    z-index: 10;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    pointer-events: none;
  }

  .title {
    font-family: 'Orbitron', sans-serif;
    font-weight: 900;
    font-size: clamp(3rem, 8vw, 7rem);
    letter-spacing: 0.15em;
    color: transparent;
    background: linear-gradient(135deg, var(--accent) 0%, #ffffff 50%, var(--accent2) 100%);
    background-clip: text;
    -webkit-background-clip: text;
    opacity: 0;
    animation: titleReveal 2s ease-out 0.5s forwards;
    text-shadow: none;
    position: relative;
  }

  .subtitle {
    font-weight: 100;
    font-size: clamp(0.85rem, 2vw, 1.3rem);
    letter-spacing: 0.6em;
    color: rgba(255,255,255,0.5);
    margin-top: 1.5rem;
    opacity: 0;
    animation: subtitleReveal 1.8s ease-out 1.5s forwards;
  }

  .line-accent {
    width: 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    margin-top: 2rem;
    animation: lineExpand 2s ease-out 2s forwards;
  }

  .corner-mark {
    position: fixed;
    font-family: 'Orbitron', sans-serif;
    font-size: 0.65rem;
    letter-spacing: 0.3em;
    color: rgba(255,255,255,0.15);
    z-index: 10;
  }
  .corner-mark.tl { top: 2rem; left: 2rem; }
  .corner-mark.br { bottom: 2rem; right: 2rem; }

  /* 底部粒子计数 */
  .stats {
    position: fixed;
    bottom: 2rem;
    left: 2rem;
    font-family: 'Orbitron', sans-serif;
    font-size: 0.6rem;
    letter-spacing: 0.2em;
    color: rgba(0,229,195,0.3);
    z-index: 10;
  }

  /* 右侧装饰线 */
  .deco-line {
    position: fixed;
    right: 3rem;
    top: 50%;
    transform: translateY(-50%);
    width: 1px;
    height: 0;
    background: linear-gradient(180deg, transparent, var(--accent), transparent);
    z-index: 10;
    opacity: 0.3;
    animation: decoLineGrow 2.5s ease-out 2.5s forwards;
  }

  @keyframes titleReveal {
    0% { opacity: 0; transform: translateY(30px) scale(0.95); filter: blur(10px); }
    100% { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
  }

  @keyframes subtitleReveal {
    0% { opacity: 0; transform: translateY(15px); }
    100% { opacity: 1; transform: translateY(0); }
  }

  @keyframes lineExpand {
    0% { width: 0; }
    100% { width: min(400px, 60vw); }
  }

  @keyframes decoLineGrow {
    0% { height: 0; }
    100% { height: 30vh; }
  }

  /* 减弱动画偏好 */
  @media (prefers-reduced-motion: reduce) {
    .title, .subtitle, .line-accent, .deco-line {
      animation-duration: 0.01s !important;
    }
  }
</style>
</head>
<body>

<canvas id="cosmic"></canvas>

<div class="cursor-dot" id="cursorDot"></div>
<div class="cursor-ring" id="cursorRing"></div>

<div class="overlay">
  <div class="title">COSMIC TIDE</div>
  <div class="subtitle">星 际 潮 汐</div>
  <div class="line-accent"></div>
</div>

<div class="corner-mark tl">SECTOR 7G — DEEP FIELD</div>
<div class="corner-mark br">ANOMALY DETECTED</div>

<div class="deco-line"></div>
<div class="stats" id="stats">PARTICLES: 0</div>

<script>
/**
 * 星际潮汐 - 粒子流体动画
 * 多层粒子系统 + 几何晶体 + 鼠标交互
 */

const canvas = document.getElementById('cosmic');
const ctx = canvas.getContext('2d');
const cursorDot = document.getElementById('cursorDot');
const cursorRing = document.getElementById('cursorRing');
const statsEl = document.getElementById('stats');

let W, H, cx, cy;
let mouse = { x: -1000, y: -1000, vx: 0, vy: 0 };
let prevMouse = { x: -1000, y: -1000 };
let time = 0;

// 画布尺寸
function resize() {
  W = canvas.width = window.innerWidth;
  H = canvas.height = window.innerHeight;
  cx = W / 2;
  cy = H / 2;
}
resize();
window.addEventListener('resize', resize);

// 鼠标追踪
document.addEventListener('mousemove', (e) => {
  mouse.vx = e.clientX - mouse.x;
  mouse.vy = e.clientY - mouse.y;
  mouse.x = e.clientX;
  mouse.y = e.clientY;
  cursorDot.style.left = e.clientX + 'px';
  cursorDot.style.top = e.clientY + 'px';
  cursorRing.style.left = e.clientX + 'px';
  cursorRing.style.top = e.clientY + 'px';
});

// ====== 噪声函数 ======
function simplexLike(x, y) {
  const sin1 = Math.sin(x * 0.8 + y * 1.3) * 0.5;
  const sin2 = Math.sin(x * 1.7 - y * 0.9) * 0.3;
  const sin3 = Math.sin(x * 0.3 + y * 2.1) * 0.2;
  return sin1 + sin2 + sin3;
}

// ====== 粒子系统 ======
class Particle {
  constructor(layer) {
    this.layer = layer; // 0=远景, 1=中景, 2=近景
    this.reset();
  }

  reset() {
    this.x = Math.random() * W;
    this.y = Math.random() * H;
    const layerConfig = [
      { sizeMin: 0.5, sizeMax: 1.5, speedMax: 0.3, alpha: 0.3 },
      { sizeMin: 1, sizeMax: 3, speedMax: 0.6, alpha: 0.5 },
      { sizeMin: 2, sizeMax: 5, speedMax: 1.0, alpha: 0.8 }
    ][this.layer];
    this.size = layerConfig.sizeMin + Math.random() * (layerConfig.sizeMax - layerConfig.sizeMin);
    this.baseAlpha = layerConfig.alpha * (0.5 + Math.random() * 0.5);
    this.alpha = this.baseAlpha;
    this.vx = (Math.random() - 0.5) * layerConfig.speedMax;
    this.vy = (Math.random() - 0.5) * layerConfig.speedMax;
    this.life = 0.5 + Math.random() * 0.5;
    this.phase = Math.random() * Math.PI * 2;
    // 颜色:青色系为主,少量橙色点缀
    if (Math.random() < 0.85) {
      const hue = 160 + Math.random() * 30; // 青绿色
      this.color = `hsla(${hue}, 90%, 70%, `;
    } else {
      const hue = 15 + Math.random() * 20; // 暖橙色
      this.color = `hsla(${hue}, 95%, 60%, `;
    }
  }

  update(dt) {
    // 噪声场驱动
    const noiseScale = 0.002;
    const n = simplexLike(
      this.x * noiseScale + time * 0.2,
      this.y * noiseScale + time * 0.15
    );
    const angle = n * Math.PI * 4;
    const fieldStrength = [0.15, 0.3, 0.5][this.layer];
    this.vx += Math.cos(angle) * fieldStrength * dt;
    this.vy += Math.sin(angle) * fieldStrength * dt;

    // 鼠标吸引
    const dx = mouse.x - this.x;
    const dy = mouse.y - this.y;
    const dist = Math.sqrt(dx * dx + dy * dy);
    const influence = [80, 150, 250][this.layer];
    if (dist < influence && dist > 1) {
      const force = (1 - dist / influence) * 0.8;
      this.vx += (dx / dist) * force * dt * 60;
      this.vy += (dy / dist) * force * dt * 60;
    }

    // 阻尼
    const damping = 0.97;
    this.vx *= damping;
    this.vy *= damping;

    this.x += this.vx;
    this.y += this.vy;

    // 脉动
    this.alpha = this.baseAlpha * (0.6 + 0.4 * Math.sin(time * 2 + this.phase));

    // 边界循环
    if (this.x < -20) this.x = W + 20;
    if (this.x > W + 20) this.x = -20;
    if (this.y < -20) this.y = H + 20;
    if (this.y > H + 20) this.y = -20;
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, Math.max(0.5, this.size), 0, Math.PI * 2);
    ctx.fillStyle = this.color + this.alpha + ')';
    ctx.fill();

    // 近景粒子发光
    if (this.layer === 2 && this.size > 3) {
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.size * 3, 0, Math.PI * 2);
      ctx.fillStyle = this.color + (this.alpha * 0.15) + ')';
      ctx.fill();
    }
  }
}

// ====== 几何晶体 ======
class Crystal {
  constructor() {
    this.x = W * (0.2 + Math.random() * 0.6);
    this.y = H * (0.2 + Math.random() * 0.6);
    this.sides = 3 + Math.floor(Math.random() * 4); // 3-6边
    this.radius = 30 + Math.random() * 80;
    this.rotation = Math.random() * Math.PI * 2;
    this.rotSpeed = (Math.random() - 0.5) * 0.3;
    this.alpha = 0;
    this.targetAlpha = 0.08 + Math.random() * 0.12;
    this.delay = Math.random() * 3;
    this.born = false;
  }

  update(dt) {
    if (time < this.delay) return;
    this.born = true;
    this.alpha += (this.targetAlpha - this.alpha) * 0.02;
    this.rotation += this.rotSpeed * dt;

    // 鼠标靠近时增亮
    const dx = mouse.x - this.x;
    const dy = mouse.y - this.y;
    const dist = Math.sqrt(dx * dx + dy * dy);
    if (dist < 200) {
      this.targetAlpha = 0.08 + (1 - dist / 200) * 0.25;
    } else {
      this.targetAlpha = 0.08 + Math.random() * 0.04;
    }
  }

  draw() {
    if (!this.born) return;
    ctx.save();
    ctx.translate(this.x, this.y);
    ctx.rotate(this.rotation);

    // 外框
    ctx.beginPath();
    for (let i = 0; i < this.sides; i++) {
      const a = (Math.PI * 2 / this.sides) * i - Math.PI / 2;
      const px = Math.cos(a) * this.radius;
      const py = Math.sin(a) * this.radius;
      if (i === 0) ctx.moveTo(px, py);
      else ctx.lineTo(px, py);
    }
    ctx.closePath();
    ctx.strokeStyle = `rgba(0, 229, 195, ${this.alpha})`;
    ctx.lineWidth = 1;
    ctx.stroke();

    // 内框
    ctx.beginPath();
    for (let i = 0; i < this.sides; i++) {
      const a = (Math.PI * 2 / this.sides) * i - Math.PI / 2 + Math.PI / this.sides;
      const px = Math.cos(a) * this.radius * 0.5;
      const py = Math.sin(a) * this.radius * 0.5;
      if (i === 0) ctx.moveTo(px, py);
      else ctx.lineTo(px, py);
    }
    ctx.closePath();
    ctx.strokeStyle = `rgba(255, 107, 53, ${this.alpha * 0.6})`;
    ctx.lineWidth = 0.5;
    ctx.stroke();

    // 连接线
    for (let i = 0; i < this.sides; i++) {
      const a1 = (Math.PI * 2 / this.sides) * i - Math.PI / 2;
      const a2 = (Math.PI * 2 / this.sides) * i - Math.PI / 2 + Math.PI / this.sides;
      ctx.beginPath();
      ctx.moveTo(Math.cos(a1) * this.radius, Math.sin(a1) * this.radius);
      ctx.lineTo(Math.cos(a2) * this.radius * 0.5, Math.sin(a2) * this.radius * 0.5);
      ctx.strokeStyle = `rgba(0, 229, 195, ${this.alpha * 0.3})`;
      ctx.stroke();
    }

    ctx.restore();
  }
}

// ====== 流星 ======
class Meteor {
  constructor() {
    this.reset();
  }

  reset() {
    this.active = false;
    this.x = Math.random() * W;
    this.y = -20;
    this.length = 60 + Math.random() * 120;
    this.speed = 8 + Math.random() * 12;
    this.angle = Math.PI / 4 + (Math.random() - 0.5) * 0.3;
    this.alpha = 0;
    this.life = 0;
    this.maxLife = 40 + Math.random() * 30;
  }

  update() {
    if (!this.active) {
      // 随机触发
      if (Math.random() < 0.003) {
        this.active = true;
        this.x = Math.random() * W * 1.2 - W * 0.1;
        this.y = -20;
        this.life = 0;
        this.alpha = 0;
      }
      return;
    }

    this.life++;
    this.x += Math.cos(this.angle) * this.speed;
    this.y += Math.sin(this.angle) * this.speed;

    // 淡入淡出
    const progress = this.life / this.maxLife;
    if (progress < 0.2) this.alpha = progress / 0.2;
    else if (progress > 0.7) this.alpha = (1 - progress) / 0.3;
    else this.alpha = 1;

    if (this.life > this.maxLife || this.y > H + 50) {
      this.reset();
    }
  }

  draw() {
    if (!this.active) return;
    const tailX = this.x - Math.cos(this.angle) * this.length;
    const tailY = this.y - Math.sin(this.angle) * this.length;

    const grad = ctx.createLinearGradient(tailX, tailY, this.x, this.y);
    grad.addColorStop(0, `rgba(255, 107, 53, 0)`);
    grad.addColorStop(0.6, `rgba(255, 107, 53, ${this.alpha * 0.4})`);
    grad.addColorStop(1, `rgba(255, 255, 255, ${this.alpha * 0.9})`);

    ctx.beginPath();
    ctx.moveTo(tailX, tailY);
    ctx.lineTo(this.x, this.y);
    ctx.strokeStyle = grad;
    ctx.lineWidth = 1.5;
    ctx.stroke();

    // 头部光点
    ctx.beginPath();
    ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
    ctx.fillStyle = `rgba(255, 255, 255, ${this.alpha})`;
    ctx.fill();
  }
}

// ====== 粒子间连线 ======
function drawConnections(particles) {
  const maxDist = 100;
  // 只连接近景粒子
  const nearParticles = particles.filter(p => p.layer === 2);
  for (let i = 0; i < nearParticles.length; i++) {
    for (let j = i + 1; j < nearParticles.length; j++) {
      const dx = nearParticles[i].x - nearParticles[j].x;
      const dy = nearParticles[i].y - nearParticles[j].y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist < maxDist) {
        const alpha = (1 - dist / maxDist) * 0.15;
        ctx.beginPath();
        ctx.moveTo(nearParticles[i].x, nearParticles[i].y);
        ctx.lineTo(nearParticles[j].x, nearParticles[j].y);
        ctx.strokeStyle = `rgba(0, 229, 195, ${alpha})`;
        ctx.lineWidth = 0.5;
        ctx.stroke();
      }
    }
  }
}

// ====== 背景雾气 ======
function drawNebula() {
  // 径向光晕 - 跟随鼠标轻微偏移
  const mx = cx + (mouse.x - cx) * 0.1;
  const my = cy + (mouse.y - cy) * 0.1;

  const grad1 = ctx.createRadialGradient(mx, my, 0, mx, my, Math.max(W, H) * 0.6);
  grad1.addColorStop(0, 'rgba(0, 229, 195, 0.03)');
  grad1.addColorStop(0.4, 'rgba(0, 100, 120, 0.02)');
  grad1.addColorStop(1, 'rgba(0, 0, 0, 0)');
  ctx.fillStyle = grad1;
  ctx.fillRect(0, 0, W, H);

  // 第二个光晕 - 暖色
  const ox = W * 0.75 + Math.sin(time * 0.5) * 50;
  const oy = H * 0.3 + Math.cos(time * 0.3) * 30;
  const grad2 = ctx.createRadialGradient(ox, oy, 0, ox, oy, 300);
  grad2.addColorStop(0, 'rgba(255, 107, 53, 0.025)');
  grad2.addColorStop(1, 'rgba(0, 0, 0, 0)');
  ctx.fillStyle = grad2;
  ctx.fillRect(0, 0, W, H);
}

// ====== 鼠标光圈 ======
function drawMouseGlow() {
  if (mouse.x < 0) return;
  const grad = ctx.createRadialGradient(mouse.x, mouse.y, 0, mouse.x, mouse.y, 150);
  grad.addColorStop(0, 'rgba(0, 229, 195, 0.06)');
  grad.addColorStop(0.5, 'rgba(0, 229, 195, 0.02)');
  grad.addColorStop(1, 'rgba(0, 0, 0, 0)');
  ctx.fillStyle = grad;
  ctx.fillRect(mouse.x - 150, mouse.y - 150, 300, 300);
}

// ====== 初始化 ======
const particles = [];
const particleCounts = [200, 120, 50]; // 远、中、近
for (let layer = 0; layer < 3; layer++) {
  for (let i = 0; i < particleCounts[layer]; i++) {
    particles.push(new Particle(layer));
  }
}

const crystals = [];
for (let i = 0; i < 5; i++) {
  crystals.push(new Crystal());
}

const meteors = [];
for (let i = 0; i < 3; i++) {
  meteors.push(new Meteor());
}

// ====== 扫描线效果 ======
let scanY = -10;
function drawScanLine() {
  scanY += 1.5;
  if (scanY > H + 10) scanY = -10;

  const grad = ctx.createLinearGradient(0, scanY - 5, 0, scanY + 5);
  grad.addColorStop(0, 'rgba(0, 229, 195, 0)');
  grad.addColorStop(0.5, 'rgba(0, 229, 195, 0.04)');
  grad.addColorStop(1, 'rgba(0, 229, 195, 0)');
  ctx.fillStyle = grad;
  ctx.fillRect(0, scanY - 5, W, 10);
}

// ====== 主循环 ======
let lastTime = performance.now();

function animate(now) {
  const dt = Math.min((now - lastTime) / 1000, 0.05);
  lastTime = now;
  time += dt;

  // 清屏 - 半透明实现拖尾
  ctx.fillStyle = 'rgba(4, 6, 15, 0.15)';
  ctx.fillRect(0, 0, W, H);

  // 每隔一段完全清屏避免残影堆积
  if (Math.floor(time * 10) % 50 === 0) {
    ctx.fillStyle = 'rgba(4, 6, 15, 0.5)';
    ctx.fillRect(0, 0, W, H);
  }

  // 背景雾气
  drawNebula();

  // 扫描线
  drawScanLine();

  // 更新和绘制晶体
  crystals.forEach(c => { c.update(dt); c.draw(); });

  // 更新和绘制粒子
  particles.forEach(p => { p.update(dt); p.draw(); });

  // 粒子连线
  drawConnections(particles);

  // 流星
  meteors.forEach(m => { m.update(); m.draw(); });

  // 鼠标光圈
  drawMouseGlow();

  // 更新统计
  statsEl.textContent = `PARTICLES: ${particles.length} | T: ${time.toFixed(1)}s`;

  requestAnimationFrame(animate);
}

// 启动
requestAnimationFrame(animate);
</script>
</body>
</html>

实现说明:

这是一个名为"星际潮汐"的全屏粒子流体动画,页面加载后立即自动播放,包含以下视觉层次:

  1. 三层粒子系统 — 远景(200个微小星尘)、中景(120个中等粒子)、近景(50个大号发光粒子),由噪声场驱动形成流体运动
  2. 几何晶体 — 5个缓慢旋转的多边形线框结构,鼠标靠近时会增亮
  3. 流星划过 — 随机触发的流星带有渐变尾迹
  4. 鼠标交互 — 自定义光标、粒子被鼠标吸引、光晕跟随、晶体响应
  5. 扫描线 + 星云雾气 — 缓慢扫过屏幕的半透明光线,加上随鼠标微动的径向光晕
  6. 近景粒子连线 — 距离较近的粒子之间绘制半透明连接线

配色采用深空黑底 + 电光青(#00e5c3)主调 + 暖橙(#ff6b35)点缀,字体使用 Orbitron 营造科技感。

你说得对,我之前没有了解你的实际需求就生成了一个通用的粒子动画,这确实不合适。

请告诉我:

  1. 你的项目是什么? — 比如是数据可视化、产品展示、品牌官网、仪表盘、某个具体应用的界面,还是其他?
  2. 你需要的动画具体表现什么? — 比如数据流动、物理模拟、图表动效、页面转场、某个概念的视觉隐喻?
  3. 有没有参考风格或氛围? — 比如极简、工业风、赛博朋克、自然有机、日式、杂志排版等?

有了这些信息,我才能做出真正贴合你项目的动画,而不是一个脱离上下文的演示。

积分规则:第一轮对话扣减8分,后续每轮扣6分