分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>超临界 CO₂ 热射流无触点破岩原理演示</title>
  <style>
    :root {
      --bg-color: #050811;
      --panel-bg: rgba(10, 16, 30, 0.75);
      --panel-border: rgba(0, 240, 255, 0.25);
      --accent-cyan: #00f0ff;
      --accent-orange: #ff5500;
      --accent-yellow: #ffb800;
      --accent-red: #ff2a4b;
      --text-muted: #64748b;
      --text-main: #e2e8f0;
    }

    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
      user-select: none;
    }

    body {
      background-color: var(--bg-color);
      color: var(--text-main);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      width: 100vw;
      height: 100vh;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      position: relative;
    }

    /* 顶部精简微标头 - 绝不侵占中央空间 */
    .header-bar {
      position: absolute;
      top: 16px;
      left: 20px;
      z-index: 20;
      display: flex;
      align-items: center;
      gap: 12px;
      pointer-events: none;
    }

    .status-badge {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 3px 8px;
      background: rgba(0, 240, 255, 0.1);
      border: 1px solid var(--accent-cyan);
      border-radius: 4px;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.5px;
      color: var(--accent-cyan);
    }

    .status-dot {
      width: 6px;
      height: 6px;
      background: var(--accent-cyan);
      border-radius: 50%;
      box-shadow: 0 0 8px var(--accent-cyan);
      animation: pulse-dot 1.5s infinite alternate;
    }

    .title-group h1 {
      font-size: 14px;
      font-weight: 600;
      letter-spacing: 0.8px;
      color: #ffffff;
    }

    .title-group p {
      font-size: 11px;
      color: var(--text-muted);
    }

    /* 中央超大核心动画主视口 */
    .viewport-container {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      z-index: 1;
    }

    #stage-svg {
      width: 100%;
      height: 100%;
      max-width: 100%;
      max-height: 100%;
      object-fit: contain;
    }

    /* 粒子/特效独立 Canvas 覆盖层 */
    #fx-canvas {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      pointer-events: none;
      z-index: 2;
    }

    /* 右上角精简参数指示面板 (HUD) */
    .hud-metrics {
      position: absolute;
      top: 16px;
      right: 20px;
      z-index: 20;
      background: var(--panel-bg);
      backdrop-filter: blur(8px);
      border: 1px solid var(--panel-border);
      border-radius: 6px;
      padding: 10px 14px;
      display: grid;
      grid-template-columns: repeat(2, auto);
      gap: 8px 16px;
      font-size: 11px;
      box-shadow: 0 8px 24px rgba(0,0,0,0.5);
    }

    .metric-item {
      display: flex;
      flex-direction: column;
    }

    .metric-label {
      color: var(--text-muted);
      font-size: 10px;
      margin-bottom: 1px;
    }

    .metric-value {
      font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
      font-weight: 700;
      font-size: 13px;
      color: #fff;
    }

    .val-temp { color: #ff6e26; }
    .val-press { color: #00f0ff; }
    .val-speed { color: #ffca28; }
    .val-stress { color: #ff2a4b; }

    /* 底部极简悬浮控制器 */
    .controls-dock {
      position: absolute;
      bottom: 16px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 20;
      background: var(--panel-bg);
      backdrop-filter: blur(10px);
      border: 1px solid rgba(255, 255, 255, 0.12);
      border-radius: 30px;
      padding: 6px 16px;
      display: flex;
      align-items: center;
      gap: 16px;
      box-shadow: 0 10px 30px rgba(0,0,0,0.6);
    }

    .ctrl-group {
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 11px;
      color: var(--text-muted);
    }

    .ctrl-label {
      font-size: 11px;
      white-space: nowrap;
      color: var(--text-main);
    }

    input[type="range"] {
      -webkit-appearance: none;
      width: 90px;
      height: 4px;
      background: rgba(255,255,255,0.2);
      border-radius: 2px;
      outline: none;
    }

    input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 12px;
      height: 12px;
      border-radius: 50%;
      background: var(--accent-orange);
      cursor: pointer;
      box-shadow: 0 0 6px var(--accent-orange);
    }

    .btn-action {
      background: rgba(0, 240, 255, 0.15);
      border: 1px solid var(--accent-cyan);
      color: #fff;
      font-size: 11px;
      padding: 4px 10px;
      border-radius: 12px;
      cursor: pointer;
      transition: all 0.2s ease;
    }

    .btn-action:hover {
      background: rgba(0, 240, 255, 0.35);
      box-shadow: 0 0 8px rgba(0, 240, 255, 0.4);
    }

    /* 左下角紧凑微型图例 */
    .legend-dock {
      position: absolute;
      bottom: 16px;
      left: 20px;
      z-index: 20;
      background: var(--panel-bg);
      backdrop-filter: blur(6px);
      border: 1px solid rgba(255, 255, 255, 0.08);
      border-radius: 6px;
      padding: 6px 10px;
      font-size: 10px;
      display: flex;
      flex-direction: column;
      gap: 4px;
      color: var(--text-muted);
      pointer-events: none;
    }

    .legend-row {
      display: flex;
      align-items: center;
      gap: 6px;
    }

    .legend-color {
      width: 8px;
      height: 8px;
      border-radius: 2px;
    }

    @keyframes pulse-dot {
      from { opacity: 0.4; transform: scale(0.9); }
      to { opacity: 1; transform: scale(1.15); }
    }

    @keyframes heat-glow {
      0% { opacity: 0.7; }
      50% { opacity: 1; filter: drop-shadow(0 0 12px #ff4500); }
      100% { opacity: 0.7; }
    }

    .glow-anim {
      animation: heat-glow 2s infinite ease-in-out;
    }
  </style>
</head>
<body>

  <!-- 顶部精简状态与标题 -->
  <div class="header-bar">
    <div class="status-badge">
      <span class="status-dot"></span>
      <span>超临界状态</span>
    </div>
    <div class="title-group">
      <h1>高温超临界 CO₂ 热射流无触点破岩系统</h1>
      <p>超临界循环 · 剧烈热应力 · 片状剥落</p>
    </div>
  </div>

  <!-- 右上角精简参数仪表盘 -->
  <div class="hud-metrics">
    <div class="metric-item">
      <span class="metric-label">射流出口温度</span>
      <span class="metric-value val-temp" id="disp-temp">680 °C</span>
    </div>
    <div class="metric-item">
      <span class="metric-label">射流喷出速度</span>
      <span class="metric-value val-speed" id="disp-speed">265 m/s</span>
    </div>
    <div class="metric-item">
      <span class="metric-label">井底环境压力</span>
      <span class="metric-value val-press">48.5 MPa</span>
    </div>
    <div class="metric-item">
      <span class="metric-label">表层热应力 / 临界</span>
      <span class="metric-value val-stress" id="disp-stress">142 / 8.5 MPa</span>
    </div>
  </div>

  <!-- 左下角微型图例 -->
  <div class="legend-dock">
    <div class="legend-row">
      <span class="legend-color" style="background: linear-gradient(90deg, #ffeedd, #ff3700);"></span>
      <span>650°C 超临界 CO₂ 高速射流</span>
    </div>
    <div class="legend-row">
      <span class="legend-color" style="background: #00f0ff;"></span>
      <span>井筒环空携屑上返流 (高密度)</span>
    </div>
    <div class="legend-row">
      <span class="legend-color" style="background: #ff2a4b;"></span>
      <span>热张应力集中裂纹扩展区</span>
    </div>
  </div>

  <!-- 底部精简控制器 -->
  <div class="controls-dock">
    <div class="ctrl-group">
      <span class="ctrl-label">射流功率</span>
      <input type="range" id="power-slider" min="500" max="750" value="680" step="5">
      <span id="power-val" style="font-size:10px; color:var(--accent-orange); font-family:monospace;">680°C</span>
    </div>
    <div style="width: 1px; height: 16px; background: rgba(255,255,255,0.15);"></div>
    <button class="btn-action" id="btn-toggle-stress">热应力云图: 开</button>
    <button class="btn-action" id="btn-burst">强化脉冲热冲击</button>
  </div>

  <!-- 视口与核心 SVG 结构 -->
  <div class="viewport-container">
    <svg id="stage-svg" viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid meet">
      <defs>
        <!-- 渐变定义 -->
        <linearGradient id="casingGrad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#1e293b"/>
          <stop offset="40%" stop-color="#475569"/>
          <stop offset="70%" stop-color="#334155"/>
          <stop offset="100%" stop-color="#0f172a"/>
        </linearGradient>

        <linearGradient id="insulationGrad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#b45309"/>
          <stop offset="50%" stop-color="#f59e0b"/>
          <stop offset="100%" stop-color="#78350f"/>
        </linearGradient>

        <linearGradient id="innerPipeGrad" x1="0" y1="0" x2="1" y2="0">
          <stop offset="0%" stop-color="#dc2626"/>
          <stop offset="30%" stop-color="#ff7849"/>
          <stop offset="70%" stop-color="#ffedd5"/>
          <stop offset="100%" stop-color="#c2410c"/>
        </linearGradient>

        <radialGradient id="hotSpotGrad" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stop-color="#ffffff" stop-opacity="1"/>
          <stop offset="25%" stop-color="#ffea79" stop-opacity="0.95"/>
          <stop offset="55%" stop-color="#ff4800" stop-opacity="0.8"/>
          <stop offset="85%" stop-color="#d90429" stop-opacity="0.4"/>
          <stop offset="100%" stop-color="#1a0005" stop-opacity="0"/>
        </radialGradient>

        <radialGradient id="stressHalo" cx="50%" cy="30%" r="70%">
          <stop offset="0%" stop-color="#ff0055" stop-opacity="0.7"/>
          <stop offset="30%" stop-color="#ff5500" stop-opacity="0.4"/>
          <stop offset="70%" stop-color="#00f0ff" stop-opacity="0.15"/>
          <stop offset="100%" stop-color="#000000" stop-opacity="0"/>
        </radialGradient>

        <pattern id="rockTexture" width="60" height="60" patternUnits="userSpaceOnUse">
          <rect width="60" height="60" fill="#121624"/>
          <path d="M0 20 L20 0 M30 60 L60 30 M10 50 L50 10 M-5 35 L35 -5" stroke="#1c2338" stroke-width="1.5"/>
          <circle cx="15" cy="15" r="1" fill="#2d3748"/>
          <circle cx="45" cy="35" r="1.5" fill="#334155"/>
          <circle cx="28" cy="52" r="1" fill="#1e293b"/>
        </pattern>

        <filter id="superGlow" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="6" result="blur1" />
          <feGaussianBlur stdDeviation="16" result="blur2" />
          <feMerge>
            <feMergeNode in="blur2" />
            <feMergeNode in="blur1" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>

        <!-- 喷嘴剪切路径 -->
        <clipPath id="nozzleClip">
          <path d="M 680 50 L 920 50 L 920 380 L 870 470 L 830 500 L 770 500 L 730 470 L 680 380 Z"/>
        </clipPath>
      </defs>

      <!-- 1. 背景地层 (花岗岩超深层 300°C 环境) -->
      <rect x="0" y="0" width="1600" height="900" fill="url(#rockTexture)"/>

      <!-- 井眼外壁轮廓与环空边界 -->
      <!-- 井筒左壁 -->
      <path d="M 0 0 L 520 0 L 520 620 Q 520 740 640 760 L 640 900 L 0 900 Z" fill="#0b0e1a" stroke="#222f49" stroke-width="2"/>
      <!-- 井筒右壁 -->
      <path d="M 1600 0 L 1080 0 L 1080 620 Q 1080 740 960 760 L 960 900 L 1600 900 Z" fill="#0b0e1a" stroke="#222f49" stroke-width="2"/>

      <!-- 井底岩面基底 (被热射流冲击剥落形成的凹坑) -->
      <g id="rock-bed">
        <!-- 基础岩石截面 -->
        <path id="rock-bottom-path" d="M 520 620 Q 640 730 800 740 Q 960 730 1080 620 L 1080 900 L 520 900 Z" fill="#181d2f" stroke="#ff4500" stroke-width="1.5"/>

        <!-- 热应力波穿透与温度梯度伪彩场 (FEM 风格应力云图) -->
        <path id="stress-field" d="M 540 630 Q 640 730 800 740 Q 960 730 1060 630 L 1060 880 Q 800 910 540 880 Z" fill="url(#stressHalo)" opacity="0.85"/>

        <!-- 陡峭热边界层(0.5mm微观急热层,白热化) -->
        <path id="thermal-skin" d="M 680 690 Q 800 745 920 690 Q 800 735 680 690 Z" fill="url(#hotSpotGrad)" filter="url(#superGlow)"/>

        <!-- 动态裂纹网络 (热应力张拉导致微裂纹脆性扩展) -->
        <g id="crack-network" stroke="#ff1133" stroke-width="1.8" stroke-linecap="round" fill="none" opacity="0.9">
          <!-- 裂纹1 -->
          <path d="M 760 730 L 745 745 L 725 740 L 710 755" />
          <path d="M 745 745 L 750 760" />
          <!-- 裂纹2 (中央主剥落区) -->
          <path d="M 790 738 L 795 758 L 780 770 L 765 775" />
          <path d="M 795 758 L 815 765 L 830 780" />
          <!-- 裂纹3 -->
          <path d="M 835 732 L 850 746 L 875 742 L 890 758" />
          <path d="M 850 746 L 855 768" />
          <!-- 微小分叉 -->
          <path d="M 815 765 L 810 785" stroke-dasharray="2 3"/>
          <path d="M 725 740 L 720 758" stroke-dasharray="2 3"/>
        </g>
      </g>

      <!-- 2. 井下无触点热射流喷嘴总成 (耐高温合金,无旋转密封与电子元器件) -->
      <g id="nozzle-assembly">
        <!-- 隔热连续油管 (真空绝热夹层结构) -->
        <!-- 外层承压壁 -->
        <rect x="680" y="-20" width="240" height="400" fill="url(#casingGrad)" stroke="#64748b" stroke-width="1.5"/>
        <!-- 真空绝热层 -->
        <rect x="710" y="-20" width="25" height="400" fill="url(#insulationGrad)"/>
        <rect x="865" y="-20" width="25" height="400" fill="url(#insulationGrad)"/>
        <line x1="722.5" y1="-20" x2="722.5" y2="380" stroke="#fef08a" stroke-width="1" stroke-dasharray="6 4" opacity="0.8"/>
        <line x1="877.5" y1="-20" x2="877.5" y2="380" stroke="#fef08a" stroke-width="1" stroke-dasharray="6 4" opacity="0.8"/>

        <!-- 内部高温通道 (650°C 超临界 CO₂ 注入管) -->
        <rect x="735" y="-20" width="130" height="400" fill="url(#innerPipeGrad)" opacity="0.95"/>

        <!-- 下部拉瓦尔/收缩型机械热喷嘴锥体 -->
        <path d="M 680 380 L 920 380 L 860 480 L 835 495 L 765 495 L 740 480 Z" fill="url(#casingGrad)" stroke="#64748b" stroke-width="2"/>
        <!-- 喷嘴内收缩流道 -->
        <path d="M 735 380 L 865 380 L 825 480 L 818 495 L 782 495 L 775 480 Z" fill="url(#innerPipeGrad)"/>

        <!-- 喷嘴合金耐磨耐冲刷唇口 -->
        <ellipse cx="800" cy="495" rx="18" ry="5" fill="#ffffff" filter="url(#superGlow)"/>

        <!-- 喷嘴结构注解精简小标牌 (SVG内部固定位置,不遮挡核心) -->
        <g opacity="0.75" transform="translate(930, 240)">
          <line x1="0" y1="0" x2="40" y2="0" stroke="#94a3b8" stroke-width="1"/>
          <circle cx="0" cy="0" r="2.5" fill="#00f0ff"/>
          <text x="48" y="4" fill="#cbd5e1" font-size="11" font-family="sans-serif">真空隔热连续油管 (外壁&lt;150°C)</text>
        </g>
        <g opacity="0.75" transform="translate(900, 440)">
          <line x1="0" y1="0" x2="70" y2="0" stroke="#94a3b8" stroke-width="1"/>
          <circle cx="0" cy="0" r="2.5" fill="#ff5500"/>
          <text x="78" y="4" fill="#cbd5e1" font-size="11" font-family="sans-serif">耐高温合金超音速喷嘴 (无转动件/无电子)</text>
        </g>
      </g>

      <!-- 3. 超临界射流核心束 (高亮光柱与马赫环) -->
      <g id="jet-stream">
        <!-- 主发光能量射流 -->
        <polygon points="782,495 818,495 890,720 710,720" fill="url(#innerPipeGrad)" opacity="0.85" filter="url(#superGlow)" class="glow-anim"/>
        <!-- 射流中心极高温超音速核 -->
        <polygon points="792,495 808,495 840,710 760,710" fill="#ffffff" opacity="0.95" filter="url(#superGlow)"/>

        <!-- 驻点冲击波与马赫盘结构 (Shock Diamonds) -->
        <g opacity="0.85" stroke="#ffffff" stroke-width="2" fill="none">
          <ellipse cx="800" cy="540" rx="16" ry="4" stroke="#ffea79"/>
          <ellipse cx="800" cy="590" rx="28" ry="6" stroke="#ffaa40"/>
          <ellipse cx="800" cy="650" rx="46" ry="9" stroke="#ff7020"/>
          <!-- 冲击底面翻卷激波 -->
          <ellipse cx="800" cy="722" rx="90" ry="16" fill="url(#hotSpotGrad)"/>
        </g>
      </g>

      <!-- 4. 环空携屑流动导引线 (动画虚线示意) -->
      <g id="annulus-flow-lines" stroke="#00f0ff" stroke-width="1.5" stroke-dasharray="8 12" fill="none" opacity="0.45">
        <!-- 左侧上返路径 -->
        <path d="M 720 710 Q 560 690 560 550 L 560 0">
          <animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.2s" repeatCount="indefinite"/>
        </path>
        <path d="M 690 718 Q 600 690 600 550 L 600 0">
          <animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.5s" repeatCount="indefinite"/>
        </path>
        <!-- 右侧上返路径 -->
        <path d="M 880 710 Q 1040 690 1040 550 L 1040 0">
          <animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.2s" repeatCount="indefinite"/>
        </path>
        <path d="M 910 718 Q 1000 690 1000 550 L 1000 0">
          <animate attributeName="stroke-dashoffset" from="100" to="0" dur="1.5s" repeatCount="indefinite"/>
        </path>
      </g>

      <!-- 5. 核心破岩热应力机理原理解析标示 (居中右侧,极简箭头,不挡主体) -->
      <g transform="translate(1090, 680)" opacity="0.9">
        <rect x="0" y="0" width="230" height="95" rx="6" fill="rgba(15, 23, 42, 0.85)" stroke="rgba(0, 240, 255, 0.3)" stroke-width="1"/>
        <text x="14" y="22" fill="#00f0ff" font-size="12" font-weight="bold">热应力片状剥落机理 (Spallation)</text>
        <text x="14" y="42" fill="#94a3b8" font-size="10">① 岩石低导热率 → 极窄层急剧膨胀</text>
        <text x="14" y="58" fill="#94a3b8" font-size="10">② 内部冷态约束 → 形成巨大热剪/拉应力</text>
        <text x="14" y="74" fill="#ff7020" font-size="10">③ 超越岩石抗拉强度(8MPa) → 薄片崩裂</text>
        <text x="14" y="88" fill="#38bdf8" font-size="10">④ 高密超临界流瞬间携屑上返</text>
        <path d="M 0 45 L -25 45 L -45 55" stroke="#00f0ff" stroke-width="1" fill="none" stroke-dasharray="3 2"/>
        <circle cx="-45" cy="55" r="3" fill="#ff2a4b"/>
      </g>

    </svg>

    <!-- 用于高性能粒子、剥落薄片飞溅、高温流体微团渲染的 Canvas 覆盖层 -->
    <canvas id="fx-canvas"></canvas>
  </div>

  <script>
    /**
     * 高温超临界 CO₂ 破岩物理粒子与剥落动力学引擎
     * 涵盖:高速超临界射流微团、热冲击驻点飞溅、岩石热应力片状剥落(Spallation Chips)、环空携屑上返流
     */
    (function() {
      const canvas = document.getElementById('fx-canvas');
      const ctx = canvas.getContext('2d');

      let width = 0;
      let height = 0;

      // 物理与工况状态
      const state = {
        temp: 680,       // °C
        speed: 265,      // m/s
        stressShow: true,
        burstMultiplier: 1.0,
        running: true
      };

      // 粒子容器
      const jetParticles = [];     // 射流高速微团
      const spallChips = [];       // 剥落的岩石薄片
      const returnParticles = [];  // 环空上返流携屑微团

      // 坐标映射辅助(将 SVG 1600x900 逻辑坐标转换到真实 Canvas 像素)
      function toCanvasCoord(svgX, svgY) {
        const svgRatio = 1600 / 900;
        const screenRatio = width / height;
        let renderW, renderH, offsetX, offsetY;

        if (screenRatio > svgRatio) {
          renderH = height;
          renderW = height * svgRatio;
          offsetX = (width - renderW) / 2;
          offsetY = 0;
        } else {
          renderW = width;
          renderH = width / svgRatio;
          offsetX = 0;
          offsetY = (height - renderH) / 2;
        }

        const scale = renderW / 1600;
        return {
          x: offsetX + svgX * scale,
          y: offsetY + svgY * scale,
          scale: scale
        };
      }

      function resize() {
        width = canvas.width = window.innerWidth;
        height = canvas.height = window.innerHeight;
      }
      window.addEventListener('resize', resize);
      resize();

      // 创建高温射流粒子
      function emitJetParticle() {
        const count = Math.round(4 * (state.temp / 600) * state.burstMultiplier);
        for (let i = 0; i < count; i++) {
          const spread = (Math.random() - 0.5) * 28;
          jetParticles.push({
            svgX: 800 + spread,
            svgY: 495,
            vx: (Math.random() - 0.5) * 1.5,
            vy: 14 + Math.random() * 8 + (state.speed - 200) * 0.05,
            size: 2 + Math.random() * 3.5,
            life: 1.0,
            decay: 0.03 + Math.random() * 0.02,
            temp: state.temp
          });
        }
      }

      // 创建剥落岩石薄片 (Spallation Flakes - 片状破岩创新特征)
      function triggerSpallation(svgX, svgY) {
        const count = Math.round((2 + Math.random() * 3) * state.burstMultiplier);
        for (let i = 0; i < count; i++) {
          const angle = Math.PI + (Math.random() - 0.5) * 1.8; // 向上反弹溅开
          const speed = 4 + Math.random() * 9;
          spallChips.push({
            svgX: svgX + (Math.random() - 0.5) * 40,
            svgY: svgY + (Math.random() - 0.5) * 10,
            vx: Math.cos(angle) * speed,
            vy: Math.sin(angle) * speed,
            rot: Math.random() * Math.PI * 2,
            vRot: (Math.random() - 0.5) * 0.3,
            w: 5 + Math.random() * 9, // 片状长宽比大
            h: 1.8 + Math.random() * 2.5,
            life: 1.0,
            decay: 0.008 + Math.random() * 0.012,
            carried: false // 是否被环空流捕获上返
          });
        }
      }

      // 动画主循环
      function animate() {
        ctx.clearRect(0, 0, width, height);

        // 1. 发射高速射流
        if (state.running) {
          emitJetParticle();
        }

        // 2. 渲染并更新射流粒子
        for (let i = jetParticles.length - 1; i >= 0; i--) {
          const p = jetParticles[i];
          p.svgX += p.vx;
          p.svgY += p.vy;
          // 随着下落射流稍微向外展宽
          p.vx += (p.svgX - 800) * 0.012;
          p.life -= p.decay;

          const pos = toCanvasCoord(p.svgX, p.svgY);
          const r = p.size * pos.scale;

          // 撞击井底岩面 (Y ~ 720~740)
          if (p.svgY >= 725) {
            // 触发热应力岩石剥落薄片
            if (Math.random() < 0.28) {
              triggerSpallation(p.svgX, p.svgY);
            }
            // 转化为环空返出微团
            returnParticles.push({
              svgX: p.svgX,
              svgY: 720,
              side: p.svgX < 800 ? -1 : 1,
              vx: (p.svgX < 800 ? -1 : 1) * (4 + Math.random() * 4),
              vy: -2 - Math.random() * 3,
              size: 2 + Math.random() * 2,
              life: 1.0,
              decay: 0.012 + Math.random() * 0.01
            });

            jetParticles.splice(i, 1);
            continue;
          }

          if (p.life <= 0) {
            jetParticles.splice(i, 1);
            continue;
          }

          // 绘制超临界微团光晕
          ctx.beginPath();
          ctx.arc(pos.x, pos.y, r * 1.8, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(255, ${Math.floor(120 + p.life * 135)}, ${Math.floor(p.life * 80)}, ${p.life * 0.7})`;
          ctx.fill();

          ctx.beginPath();
          ctx.arc(pos.x, pos.y, r * 0.8, 0, Math.PI * 2);
          ctx.fillStyle = `#ffffff`;
          ctx.fill();
        }

        // 3. 渲染剥落的片状岩屑 (Spallation Flakes)
        for (let i = spallChips.length - 1; i >= 0; i--) {
          const c = spallChips[i];
          c.svgX += c.vx;
          c.svgY += c.vy;
          c.rot += c.vRot;
          c.life -= c.decay;

          // 受到高密度超临界 CO₂ 环空流的携屑升力与侧向推力
          if (c.svgY < 700) {
            c.carried = true;
          }

          if (c.carried) {
            const targetX = c.svgX < 800 ? 580 : 1020;
            c.vx += (targetX - c.svgX) * 0.03; // 向环空收拢
            c.vy -= 0.45; // 强劲上返流加速上浮
          } else {
            c.vy += 0.2; // 微小重力
          }

          const pos = toCanvasCoord(c.svgX, c.svgY);
          const w = c.w * pos.scale;
          const h = c.h * pos.scale;

          ctx.save();
          ctx.translate(pos.x, pos.y);
          ctx.rotate(c.rot);
          
          // 刚剥落时带有高温红热余晖,随后冷却为岩石灰褐色
          const hotR = Math.floor(255 * c.life);
          const hotG = Math.floor(120 * c.life);
          ctx.fillStyle = `rgb(${Math.max(100, hotR)}, ${Math.max(80, hotG)}, 60)`;
          ctx.strokeStyle = `rgba(255, 200, 100, ${c.life * 0.8})`;
          ctx.lineWidth = 1;
          
          // 绘制片状微多边形
          ctx.beginPath();
          ctx.moveTo(-w/2, -h/2);
          ctx.lineTo(w/2, -h/3);
          ctx.lineTo(w/2.2, h/2);
          ctx.lineTo(-w/2.5, h/2.5);
          ctx.closePath();
          ctx.fill();
          ctx.stroke();

          ctx.restore();

          if (c.life <= 0 || c.svgY < -50) {
            spallChips.splice(i, 1);
          }
        }

        // 4. 渲染环空携屑超临界循环流微团
        for (let i = returnParticles.length - 1; i >= 0; i--) {
          const rp = returnParticles[i];
          rp.svgX += rp.vx;
          rp.svgY += rp.vy;
          rp.life -= rp.decay;

          // 环空约束流线
          if (rp.side === -1) {
            if (rp.svgX < 540) rp.vx += 0.6;
            if (rp.svgX > 620) rp.vx -= 0.6;
          } else {
            if (rp.svgX < 980) rp.vx += 0.6;
            if (rp.svgX > 1060) rp.vx -= 0.6;
          }

          // 向上返出加速
          rp.vy -= 0.35;

          const pos = toCanvasCoord(rp.svgX, rp.svgY);
          const r = rp.size * pos.scale;

          ctx.beginPath();
          ctx.arc(pos.x, pos.y, r, 0, Math.PI * 2);
          ctx.fillStyle = `rgba(0, 240, 255, ${rp.life * 0.45})`;
          ctx.fill();

          if (rp.life <= 0 || rp.svgY < -30) {
            returnParticles.splice(i, 1);
          }
        }

        // 恢复脉冲倍率平滑
        if (state.burstMultiplier > 1.0) {
          state.burstMultiplier -= 0.02;
        }

        requestAnimationFrame(animate);
      }

      // 启动自动播放
      requestAnimationFrame(animate);

      // UI 控件与数据动态响应
      const powerSlider = document.getElementById('power-slider');
      const powerVal = document.getElementById('power-val');
      const dispTemp = document.getElementById('disp-temp');
      const dispSpeed = document.getElementById('disp-speed');
      const dispStress = document.getElementById('disp-stress');
      const btnToggleStress = document.getElementById('btn-toggle-stress');
      const btnBurst = document.getElementById('btn-burst');
      const stressField = document.getElementById('stress-field');
      const crackNetwork = document.getElementById('crack-network');

      function updateParameters(temp) {
        state.temp = parseInt(temp);
        state.speed = Math.round(200 + (state.temp - 500) * 0.45);
        const stress = (state.temp * 0.21).toFixed(1);

        powerVal.innerText = `${state.temp} °C`;
        dispTemp.innerText = `${state.temp} °C`;
        dispSpeed.innerText = `${state.speed} m/s`;
        dispStress.innerText = `${stress} / 8.5 MPa`;

        // 动态调整 SVG 热应力场强度
        if (stressField) {
          stressField.style.opacity = (state.temp / 750) * 0.9;
        }
      }

      powerSlider.addEventListener('input', (e) => {
        updateParameters(e.target.value);
      });

      btnToggleStress.addEventListener('click', () => {
        state.stressShow = !state.stressShow;
        btnToggleStress.innerText = `热应力云图: ${state.stressShow ? '开' : '关'}`;
        stressField.style.display = state.stressShow ? 'block' : 'none';
        crackNetwork.style.display = state.stressShow ? 'block' : 'none';
      });

      btnBurst.addEventListener('click', () => {
        state.burstMultiplier = 3.5;
        // 激波闪烁动效
        const skin = document.getElementById('thermal-skin');
        if (skin) {
          skin.style.transform = 'scale(1.15)';
          skin.style.transformOrigin = '800px 720px';
          setTimeout(() => {
            skin.style.transform = 'scale(1.0)';
          }, 300);
        }
      });

    })();
  </script>
</body>
</html>
积分规则:每轮对话扣10分