分享图
A
动画渲染工坊
就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮毂直驱系统 · IFR 最终理想解原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#050a14;--bg2:#0a1628;--cyan:#00d4ff;--cyan-dim:rgba(0,212,255,0.12);
  --orange:#ff6b2b;--green:#00ff88;--yellow:#ffd600;--red:#ff3d5a;
  --white:#dce4f0;--muted:#3e5278;--struct:#14203a;--carbon:#0e1830;
  --border:#1a2a48;
}
body{background:var(--bg);color:var(--white);font-family:'JetBrains Mono',monospace;overflow:hidden;height:100vh;display:flex;flex-direction:column;user-select:none}
header{padding:12px 28px;display:flex;align-items:baseline;gap:18px;border-bottom:1px solid var(--border);background:linear-gradient(180deg,rgba(10,22,40,0.95),transparent);position:relative;z-index:2}
header h1{font-family:'Orbitron',sans-serif;font-size:18px;font-weight:700;letter-spacing:2px;color:var(--cyan);text-shadow:0 0 20px rgba(0,212,255,0.3)}
header p{font-size:11px;color:var(--muted);letter-spacing:1px}
#svg-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative}
#main-svg{width:100%;height:100%;max-height:calc(100vh - 110px)}
#controls{padding:10px 24px;display:flex;align-items:center;gap:14px;border-top:1px solid var(--border);background:linear-gradient(0deg,rgba(10,22,40,0.98),rgba(10,22,40,0.85));flex-wrap:wrap;justify-content:center}
.phase-btn{padding:7px 16px;border:1px solid var(--border);border-radius:6px;background:var(--carbon);color:var(--muted);font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer;transition:all .25s;letter-spacing:0.5px;display:flex;align-items:center;gap:6px}
.phase-btn:hover{border-color:var(--cyan);color:var(--white)}
.phase-btn.active{border-color:var(--cyan);color:var(--cyan);background:var(--cyan-dim);box-shadow:0 0 12px rgba(0,212,255,0.15)}
.phase-btn i{font-size:10px}
.sep{width:1px;height:24px;background:var(--border);margin:0 4px}
.slider-group{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--muted)}
.slider-group label{white-space:nowrap}
.slider-group input[type=range]{-webkit-appearance:none;width:110px;height:4px;background:var(--border);border-radius:2px;outline:none}
.slider-group input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--cyan);border-radius:50%;cursor:pointer;box-shadow:0 0 6px rgba(0,212,255,0.4)}
.slider-val{color:var(--cyan);min-width:36px;text-align:right;font-weight:700}
.param-group{display:flex;gap:16px;margin-left:auto}
.param-item{text-align:center}
.param-item .val{font-size:16px;font-weight:700;font-family:'Orbitron',sans-serif;line-height:1.2}
.param-item .lbl{font-size:9px;color:var(--muted);letter-spacing:0.5px}
.val-cyan{color:var(--cyan)}.val-orange{color:var(--orange)}.val-green{color:var(--green)}.val-yellow{color:var(--yellow)}
@keyframes pulse{0%,100%{opacity:.6}50%{opacity:1}}
@keyframes dashFlow{to{stroke-dashoffset:-40}}
</style>
</head>
<body>
<header>
  <h1>HUB-DIRECT DRIVE</h1>
  <p>IFR 最终理想解 · 零传动链原理动画</p>
</header>
<div id="svg-wrap">
<svg id="main-svg" viewBox="0 0 1400 850" preserveAspectRatio="xMidYMid meet">
<defs>
  <!-- 碳纤维图案 -->
  <pattern id="carbon" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
    <rect width="8" height="8" fill="#0e1830"/>
    <rect width="4" height="8" fill="#13203e"/>
  </pattern>
  <!-- 网格背景 -->
  <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
    <path d="M40 0L0 0 0 40" fill="none" stroke="#0c1828" stroke-width="0.5"/>
  </pattern>
  <!-- 辉光滤镜 -->
  <filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
    <feFlood flood-color="#00d4ff" flood-opacity="0.5"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feFlood flood-color="#ff6b2b" flood-opacity="0.45"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glow-green" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feFlood flood-color="#00ff88" flood-opacity="0.45"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="softglow" x="-30%" y="-30%" width="160%" height="160%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <!-- 箭头标记 -->
  <marker id="arrow-cyan" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00d4ff"/></marker>
  <marker id="arrow-orange" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#ff6b2b"/></marker>
  <marker id="arrow-green" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00ff88"/></marker>
  <marker id="arrow-white" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="8" markerHeight="5" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#dce4f0"/></marker>
  <!-- 金属渐变 -->
  <linearGradient id="metal" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#3a4a6a"/><stop offset="50%" stop-color="#5a6a8a"/><stop offset="100%" stop-color="#2a3a5a"/></linearGradient>
  <radialGradient id="hub-grad" cx="50%" cy="45%"><stop offset="0%" stop-color="#2a4060"/><stop offset="70%" stop-color="#14203a"/><stop offset="100%" stop-color="#0a1428"/></radialGradient>
  <radialGradient id="tire-grad" cx="50%" cy="45%"><stop offset="0%" stop-color="#1a1a2a"/><stop offset="80%" stop-color="#0a0a14"/><stop offset="100%" stop-color="#050508"/></radialGradient>
</defs>

<!-- 背景 -->
<rect width="1400" height="850" fill="url(#grid)"/>
<!-- 底部大气辉光 -->
<ellipse cx="500" cy="700" rx="500" ry="120" fill="rgba(0,212,255,0.02)"/>

<!-- ========== 轨道 ========== -->
<g id="track-group">
  <line x1="0" y1="638" x2="920" y2="638" stroke="#1a2a48" stroke-width="3"/>
  <line x1="0" y1="644" x2="920" y2="644" stroke="#1a2a48" stroke-width="1.5"/>
  <g id="track-ties"></g>
</g>

<!-- ========== 速度线 ========== -->
<g id="speed-lines"></g>

<!-- ========== 车辆主体 ========== -->
<g id="vehicle-group">
  <!-- 碳纤维底盘桁架 -->
  <g id="chassis" stroke="#1e3050" stroke-width="3" fill="none">
    <!-- 上弦杆 -->
    <line x1="310" y1="465" x2="690" y2="465" stroke="#2a4060" stroke-width="4"/>
    <!-- 下弦杆 -->
    <line x1="290" y1="540" x2="710" y2="540" stroke="#2a4060" stroke-width="4"/>
    <!-- 竖杆 -->
    <line x1="350" y1="465" x2="340" y2="540"/>
    <line x1="430" y1="465" x2="420" y2="540"/>
    <line x1="510" y1="465" x2="510" y2="540"/>
    <line x1="590" y1="465" x2="600" y2="540"/>
    <line x1="670" y1="465" x2="680" y2="540"/>
    <!-- 斜杆 -->
    <line x1="340" y1="540" x2="430" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="420" y1="540" x2="510" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="510" y1="540" x2="590" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="600" y1="540" x2="670" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="350" y1="465" x2="420" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="430" y1="465" x2="510" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="510" y1="465" x2="600" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="590" y1="465" x2="680" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <!-- 节点 -->
    <g fill="#2a4a70">
      <circle cx="350" cy="465" r="4"/><circle cx="430" cy="465" r="4"/>
      <circle cx="510" cy="465" r="4"/><circle cx="590" cy="465" r="4"/>
      <circle cx="670" cy="465" r="4"/><circle cx="340" cy="540" r="4"/>
      <circle cx="420" cy="540" r="4"/><circle cx="510" cy="540" r="4"/>
      <circle cx="600" cy="540" r="4"/><circle cx="680" cy="540" r="4"/>
    </g>
  </g>
  <!-- 碳纤维纹理覆盖 -->
  <rect x="305" y="468" width="390" height="68" fill="url(#carbon)" opacity="0.4" rx="2"/>

  <!-- 控制器盒 -->
  <rect x="460" y="488" width="100" height="36" rx="4" fill="#0c1828" stroke="#2a4060" stroke-width="1.5"/>
  <text x="510" y="510" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono">CTRL</text>
  <rect id="ctrl-led" x="466" y="494" width="6" height="6" rx="3" fill="#1a2a40"/>

  <!-- 电池 -->
  <rect x="360" y="492" width="70" height="30" rx="3" fill="#0c1424" stroke="#1e3050" stroke-width="1"/>
  <text x="395" y="511" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">BAT 48V</text>
  <rect id="bat-bar" x="366" y="496" width="4" height="20" rx="1" fill="#1a3a20"/>

  <!-- 货叉 -->
  <g id="fork-group">
    <rect x="690" y="475" width="160" height="14" rx="2" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.2"/>
    <rect x="690" y="520" width="160" height="14" rx="2" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.2"/>
    <line x1="700" y1="489" x2="700" y2="520" stroke="#1e3050" stroke-width="2"/>
    <line x1="730" y1="489" x2="730" y2="520" stroke="#1e3050" stroke-width="1.5"/>
    <text x="770" y="510" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono" letter-spacing="1">CARBON FORK</text>
  </g>

  <!-- ===== 后轮:轮毂电机(主角)===== -->
  <g id="hub-motor-group">
    <!-- 轮胎 -->
    <circle cx="390" cy="590" r="52" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="2"/>
    <!-- 轮辋 -->
    <circle cx="390" cy="590" r="42" fill="none" stroke="#2a3a5a" stroke-width="2.5"/>
    <!-- 转子外环(磁钢) -->
    <circle cx="390" cy="590" r="36" fill="none" stroke="#1e3050" stroke-width="1"/>
    <g id="rotor-magnets">
      <!-- 12个磁钢交替N/S -->
    </g>
    <!-- 气隙 -->
    <circle cx="390" cy="590" r="28" fill="none" stroke="#0a1428" stroke-width="0.5" stroke-dasharray="2,2"/>
    <!-- 定子铁芯+线圈 -->
    <circle cx="390" cy="590" r="24" fill="#0c1424" stroke="#1a2a44" stroke-width="1"/>
    <g id="stator-coils">
      <!-- 9个线圈 -->
    </g>
    <!-- 轮毂轴 -->
    <circle cx="390" cy="590" r="8" fill="#14203a" stroke="#2a4060" stroke-width="1.5"/>
    <circle cx="390" cy="590" r="3" fill="#2a4060"/>
    <!-- 辐条 -->
    <g stroke="#1e3050" stroke-width="1.5" id="spokes-rear">
      <line x1="390" y1="566" x2="390" y2="548"/>
      <line x1="390" y1="614" x2="390" y2="632"/>
      <line x1="366" y1="590" x2="348" y2="590"/>
      <line x1="414" y1="590" x2="432" y2="590"/>
      <line x1="373" y1="573" x2="360" y2="560"/>
      <line x1="407" y1="607" x2="420" y2="620"/>
      <line x1="373" y1="607" x2="360" y2="620"/>
      <line x1="407" y1="573" x2="420" y2="560"/>
    </g>
    <!-- 电磁场力线(动画) -->
    <g id="em-field" opacity="0"></g>
    <!-- 电机标签 -->
    <text x="390" y="530" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono" letter-spacing="0.5">HUB MOTOR</text>
    <text x="390" y="660" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">≤4kg × 2</text>
  </g>

  <!-- ===== 前轮:从动轮 ===== -->
  <g id="passive-wheel-group">
    <circle cx="670" cy="595" r="42" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="1.5"/>
    <circle cx="670" cy="595" r="34" fill="none" stroke="#1a2a40" stroke-width="1.5"/>
    <circle cx="670" cy="595" r="6" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <g stroke="#141e30" stroke-width="1" id="spokes-front">
      <line x1="670" y1="563" x2="670" y2="553"/>
      <line x1="670" y1="627" x2="670" y2="637"/>
      <line x1="638" y1="595" x2="628" y2="595"/>
      <line x1="702" y1="595" x2="712" y2="595"/>
    </g>
    <text x="670" y="655" text-anchor="middle" fill="#141e30" font-size="7" font-family="JetBrains Mono">PASSIVE</text>
  </g>

  <!-- "零传动链"标注区 -->
  <g id="no-shaft-label" opacity="0.6">
    <line x1="430" y1="590" x2="630" y2="590" stroke="#1e3050" stroke-width="1" stroke-dasharray="6,4"/>
    <text x="530" y="585" text-anchor="middle" fill="#2a4060" font-size="8" font-family="Orbitron" letter-spacing="1">ZERO DRIVE SHAFT</text>
    <!-- 禁止符号 -->
    <circle cx="530" cy="598" r="8" fill="none" stroke="#2a4060" stroke-width="1"/>
    <line x1="524" y1="604" x2="536" y2="592" stroke="#2a4060" stroke-width="1"/>
  </g>
</g>

<!-- ========== 电力流向线 ========== -->
<g id="power-flow-group">
  <!-- 电池→控制器 -->
  <path id="power-path-bc" d="M430,507 L460,507" fill="none" stroke="#2a4060" stroke-width="2" stroke-dasharray="4,4" opacity="0.5"/>
  <!-- 控制器→轮毂电机(上方路径) -->
  <path id="power-path-cm1" d="M460,495 Q440,460 390,460 Q350,460 350,530 Q350,565 365,575" fill="none" stroke="#2a4060" stroke-width="2" stroke-dasharray="4,6" opacity="0.5"/>
  <!-- 控制器→轮毂电机(下方路径) -->
  <path id="power-path-cm2" d="M460,520 Q420,555 400,570" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,5" opacity="0.3"/>
</g>

<!-- ========== 接触力箭头 ========== -->
<g id="force-arrows">
  <g id="drive-force" opacity="0">
    <line x1="335" y1="640" x2="280" y2="640" stroke="#00d4ff" stroke-width="3" marker-end="url(#arrow-cyan)"/>
    <text x="305" y="656" text-anchor="middle" fill="#00d4ff" font-size="9" font-family="Orbitron">F</text>
  </g>
  <g id="regen-force" opacity="0">
    <line x1="280" y1="640" x2="335" y2="640" stroke="#00ff88" stroke-width="3" marker-end="url(#arrow-green)"/>
    <text x="305" y="656" text-anchor="middle" fill="#00ff88" font-size="9" font-family="Orbitron">REGEN</text>
  </g>
</g>

<!-- ========== 阶段指示 ========== -->
<g id="phase-indicator" transform="translate(50,40)">
  <rect x="0" y="0" width="200" height="44" rx="6" fill="rgba(10,22,40,0.85)" stroke="#1a2a48" stroke-width="1"/>
  <text id="phase-text" x="100" y="18" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono" letter-spacing="1">PHASE</text>
  <text id="phase-name" x="100" y="35" text-anchor="middle" fill="#00d4ff" font-size="14" font-family="Orbitron" font-weight="700">STANDBY</text>
</g>

<!-- ========== 右侧面板:俯视图 ========== -->
<g transform="translate(940,20)">
  <rect x="0" y="0" width="440" height="260" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">TOP VIEW · ELECTRONIC DIFFERENTIAL</text>
  <!-- 车体轮廓 -->
  <rect x="130" y="50" width="180" height="180" rx="6" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.5" opacity="0.6"/>
  <!-- 货叉 -->
  <rect x="310" y="80" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
  <rect x="310" y="186" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
  <!-- 控制器 -->
  <rect x="190" y="120" width="60" height="40" rx="3" fill="#0c1828" stroke="#2a4060" stroke-width="1"/>
  <text x="220" y="144" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">ECU</text>
  <!-- 左轮毂电机 -->
  <g id="top-left-motor">
    <circle cx="130" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="130" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="130" cy="140" r="5" fill="#14203a"/>
    <text x="100" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">L-HUB</text>
  </g>
  <!-- 右轮毂电机 -->
  <g id="top-right-motor">
    <circle cx="310" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="310" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="310" cy="140" r="5" fill="#14203a"/>
    <text x="340" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">R-HUB</text>
  </g>
  <!-- 从动轮 -->
  <circle cx="170" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="170" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <!-- 差速控制线 -->
  <path id="diff-line-l" d="M190,140 L155,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <path id="diff-line-r" d="M250,140 L285,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <!-- 同步指示 -->
  <g id="sync-indicator" opacity="0">
    <text x="220" y="200" text-anchor="middle" fill="#00d4ff" font-size="8" font-family="Orbitron" letter-spacing="1">SYNC</text>
    <rect x="185" y="205" width="70" height="3" rx="1.5" fill="#0a1428"/>
    <rect id="sync-bar" x="185" y="205" width="70" height="3" rx="1.5" fill="#00d4ff" opacity="0.6"/>
  </g>
  <!-- 方向箭头 -->
  <g id="direction-arrow" opacity="0">
    <line x1="220" y1="30" x2="220" y2="10" stroke="#00d4ff" stroke-width="2" marker-end="url(#arrow-cyan)"/>
  </g>
</g>

<!-- ========== 右侧面板:轮毂电机剖面 ========== -->
<g transform="translate(940,300)">
  <rect x="0" y="0" width="440" height="280" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">HUB MOTOR CROSS-SECTION</text>
  <!-- 电机剖面图 -->
  <g transform="translate(160,155)">
    <!-- 轮胎 -->
    <circle r="100" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="2"/>
    <!-- 轮辋 -->
    <circle r="85" fill="none" stroke="#2a3a5a" stroke-width="2"/>
    <!-- 转子环 -->
    <circle r="75" fill="none" stroke="#1e3050" stroke-width="6" id="rotor-ring"/>
    <!-- 磁钢(剖面中为矩形块) -->
    <g id="detail-magnets"></g>
    <!-- 气隙 -->
    <circle r="60" fill="none" stroke="rgba(0,212,255,0.1)" stroke-width="2" stroke-dasharray="2,3"/>
    <!-- 定子铁芯 -->
    <circle r="52" fill="#0c1424" stroke="#1a2a44" stroke-width="1.5"/>
    <!-- 定子齿+线圈 -->
    <g id="detail-stator"></g>
    <!-- 轴 -->
    <circle r="14" fill="#14203a" stroke="#2a4060" stroke-width="2"/>
    <circle r="5" fill="#1e3050"/>
    <!-- 电磁力线(动画层) -->
    <g id="detail-em-field" opacity="0"></g>
    <!-- 力矩标注 -->
    <g id="torque-arc" opacity="0">
      <path d="M-40,-90 A98,98 0 0,1 40,-90" fill="none" stroke="#00d4ff" stroke-width="2.5" marker-end="url(#arrow-cyan)"/>
      <text x="0" y="-96" text-anchor="middle" fill="#00d4ff" font-size="10" font-family="Orbitron" font-weight="700">TORQUE</text>
    </g>
    <!-- 再生制动力矩 -->
    <g id="regen-arc" opacity="0">
      <path d="M40,-90 A98,98 0 0,1 -40,-90" fill="none" stroke="#00ff88" stroke-width="2.5" marker-end="url(#arrow-green)"/>
      <text x="0" y="-96" text-anchor="middle" fill="#00ff88" font-size="10" font-family="Orbitron" font-weight="700">REGEN</text>
    </g>
  </g>
  <!-- 右侧说明 -->
  <g transform="translate(310,60)" fill="#3e5278" font-size="8" font-family="JetBrains Mono">
    <text y="0" fill="#2a4060">STRUCTURE</text>
    <circle cx="-8" cy="16" r="3" fill="#1a1a2a"/><text x="2" y="20">Tire</text>
    <circle cx="-8" cy="32" r="3" fill="#2a3a5a"/><text x="2" y="36">Rim</text>
    <circle cx="-8" cy="48" r="3" fill="#ff3d5a" opacity="0.6"/><text x="2" y="52">Rotor Mag</text>
    <circle cx="-8" cy="64" r="3" fill="#00d4ff" opacity="0.6"/><text x="2" y="68">Stator Coil</text>
    <circle cx="-8" cy="80" r="3" fill="#14203a"/><text x="2" y="84">Axle</text>
  </g>
</g>

<!-- ========== 右侧面板:IFR 原则 ========== -->
<g transform="translate(940,600)">
  <rect x="0" y="0" width="440" height="230" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">IFR · IDEAL FINAL RESULT</text>
  <!-- IFR核心原则 -->
  <g transform="translate(24,40)" font-family="JetBrains Mono" font-size="10">
    <text fill="#00d4ff" font-size="11" font-weight="700" font-family="Orbitron">Wheel = Motor</text>
    <text y="20" fill="#5a7aaa">轮即电机,动力直达轮缘</text>
    <text y="40" fill="#5a7aaa">零传动链 · 零机械间隙 · 零中间损耗</text>
    <line x1="0" y1="52" x2="392" y2="52" stroke="#1a2a48" stroke-width="0.5"/>
    <!-- 重量再分配 -->
    <text y="70" fill="#2a4060" font-size="8" letter-spacing="1">WEIGHT REALLOCATION</text>
    <g transform="translate(0,82)">
      <rect width="120" height="24" rx="4" fill="rgba(255,107,43,0.1)" stroke="#ff6b2b" stroke-width="0.8"/>
      <text x="60" y="16" text-anchor="middle" fill="#ff6b2b" font-size="9">传动系统 15kg</text>
      <text x="145" y="16" fill="#3e5278" font-size="14">→</text>
      <rect x="170" width="120" height="24" rx="4" fill="rgba(0,255,136,0.08)" stroke="#00ff88" stroke-width="0.8"/>
      <text x="230" y="16" text-anchor="middle" fill="#00ff88" font-size="9">结构强度 +15kg</text>
    </g>
    <line x1="0" y1="116" x2="392" y2="116" stroke="#1a2a48" stroke-width="0.5"/>
    <!-- 边界条件 -->
    <text y="134" fill="#2a4060" font-size="8" letter-spacing="1">BOUNDARY / RISK</text>
    <text y="152" fill="#5a3a3a" font-size="9">⚠ 长时间极限制动 → 磁钢退磁风险</text>
    <text y="168" fill="#5a3a3a" font-size="9">⚠ 5m/s 轨道接缝冲击 → 轴承疲劳</text>
    <text y="184" fill="#5a3a3a" font-size="9">⚠ 粉尘/湿滑轨道 → 打滑失控</text>
  </g>
</g>

<!-- ========== 底部参数条 ========== -->
<g id="svg-params" transform="translate(50,790)" font-family="Orbitron" font-size="10">
  <g transform="translate(0,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">SPEED</text>
    <text id="svg-speed" y="18" fill="#00d4ff" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s</text>
  </g>
  <g transform="translate(120,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">ACCEL</text>
    <text id="svg-accel" y="18" fill="#ff6b2b" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s²</text>
  </g>
  <g transform="translate(240,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">TORQUE</text>
    <text id="svg-torque" y="18" fill="#00d4ff" font-size="16" font-weight="700">0</text>
    <text x="38" y="18" fill="#3e5278" font-size="8">Nm</text>
  </g>
  <g transform="translate(350,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">REGEN</text>
    <text id="svg-regen" y="18" fill="#00ff88" font-size="16" font-weight="700">0</text>
    <text x="44" y="18" fill="#3e5278" font-size="8">W</text>
  </g>
  <g transform="translate(460,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">MOTOR TEMP</text>
    <text id="svg-temp" y="18" fill="#ffd600" font-size="16" font-weight="700">25</text>
    <text x="42" y="18" fill="#3e5278" font-size="8">°C</text>
  </g>
</g>

</svg>
</div>

<!-- 控制面板 -->
<div id="controls">
  <button class="phase-btn active" data-phase="standby"><i class="fas fa-power-off"></i>待机</button>
  <button class="phase-btn" data-phase="accelerate"><i class="fas fa-bolt"></i>起步加速</button>
  <button class="phase-btn" data-phase="cruise"><i class="fas fa-gauge-high"></i>稳速行驶</button>
  <button class="phase-btn" data-phase="brake"><i class="fas fa-rotate-left"></i>再生制动</button>
  <button class="phase-btn" data-phase="stop"><i class="fas fa-stop"></i>抱刹停止</button>
  <div class="sep"></div>
  <div class="slider-group">
    <label>目标速度</label>
    <input type="range" id="speed-slider" min="1" max="7" step="0.5" value="5"/>
    <span class="slider-val" id="speed-val">5.0 m/s</span>
  </div>
  <div class="slider-group">
    <label>轨道摩擦</label>
    <input type="range" id="friction-slider" min="0.3" max="1" step="0.1" value="0.8"/>
    <span class="slider-val" id="friction-val">0.8</span>
  </div>
</div>

<script>
const SVG_NS = 'http://www.w3.org/2000/svg';
const svg = document.getElementById('main-svg');

// ===== 状态管理 =====
const state = {
  phase: 'standby',
  speed: 0,
  targetSpeed: 5,
  friction: 0.8,
  acceleration: 0,
  torque: 0,
  regenPower: 0,
  motorTemp: 25,
  trackOffset: 0,
  wheelAngle: 0,
  time: 0,
  phaseTime: 0,
  powerFlowOffset: 0,
  emFieldAngle: 0,
};

// ===== 初始化 SVG 动态元素 =====
function initDynamicElements() {
  // 轨道枕木
  const tiesGroup = document.getElementById('track-ties');
  for (let i = 0; i < 40; i++) {
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', i * 50);
    rect.setAttribute('y', '632');
    rect.setAttribute('width', '20');
    rect.setAttribute('height', '16');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', '#0e1830');
    rect.setAttribute('stroke', '#1a2a44');
    rect.setAttribute('stroke-width', '0.5');
    rect.setAttribute('class', 'track-tie');
    tiesGroup.appendChild(rect);
  }

  // 轮毂电机磁钢(主视图)
  const rotorG = document.getElementById('rotor-magnets');
  for (let i = 0; i < 12; i++) {
    const angle = (i * 30) * Math.PI / 180;
    const r = 36;
    const x = 390 + Math.cos(angle) * r;
    const y = 590 + Math.sin(angle) * r;
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', x - 4);
    rect.setAttribute('y', y - 3);
    rect.setAttribute('width', '8');
    rect.setAttribute('height', '6');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    rect.setAttribute('opacity', '0.5');
    rect.setAttribute('transform', `rotate(${i * 30}, ${x}, ${y})`);
    rotorG.appendChild(rect);
  }

  // 轮毂电机定子线圈(主视图)
  const statorG = document.getElementById('stator-coils');
  for (let i = 0; i < 9; i++) {
    const angle = (i * 40) * Math.PI / 180;
    const r = 22;
    const x = 390 + Math.cos(angle) * r;
    const y = 590 + Math.sin(angle) * r;
    const circle = document.createElementNS(SVG_NS, 'circle');
    circle.setAttribute('cx', x);
    circle.setAttribute('cy', y);
    circle.setAttribute('r', '4');
    circle.setAttribute('fill', '#0a1428');
    circle.setAttribute('stroke', '#00d4ff');
    circle.setAttribute('stroke-width', '0.8');
    circle.setAttribute('opacity', '0.4');
    circle.setAttribute('class', 'stator-coil');
    statorG.appendChild(circle);
  }

  // 剖面图磁钢
  const detailMag = document.getElementById('detail-magnets');
  for (let i = 0; i < 20; i++) {
    const angle = (i * 18) * Math.PI / 180;
    const r = 75;
    const x = Math.cos(angle) * r;
    const y = Math.sin(angle) * r;
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', x - 5);
    rect.setAttribute('y', y - 3.5);
    rect.setAttribute('width', '10');
    rect.setAttribute('height', '7');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    rect.setAttribute('opacity', '0.45');
    rect.setAttribute('transform', `rotate(${i * 18}, ${x}, ${y})`);
    detailMag.appendChild(rect);
  }

  // 剖面图定子齿+线圈
  const detailStator = document.getElementById('detail-stator');
  for (let i = 0; i < 12; i++) {
    const angle = (i * 30) * Math.PI / 180;
    const g = document.createElementNS(SVG_NS, 'g');
    g.setAttribute('transform', `rotate(${i * 30})`);
    // 齿
    const tooth = document.createElementNS(SVG_NS, 'rect');
    tooth.setAttribute('x', '-3');
    tooth.setAttribute('y', '-52');
    tooth.setAttribute('width', '6');
    tooth.setAttribute('height', '14');
    tooth.setAttribute('rx', '1');
    tooth.setAttribute('fill', '#1a2a44');
    g.appendChild(tooth);
    // 线圈
    const coil = document.createElementNS(SVG_NS, 'rect');
    coil.setAttribute('x', '-6');
    coil.setAttribute('y', '-48');
    coil.setAttribute('width', '12');
    coil.setAttribute('height', '8');
    coil.setAttribute('rx', '2');
    coil.setAttribute('fill', 'none');
    coil.setAttribute('stroke', '#00d4ff');
    coil.setAttribute('stroke-width', '0.8');
    coil.setAttribute('opacity', '0.3');
    coil.setAttribute('class', 'detail-coil');
    g.appendChild(coil);
    detailStator.appendChild(g);
  }

  // 速度线
  const speedG = document.getElementById('speed-lines');
  for (let i = 0; i < 20; i++) {
    const line = document.createElementNS(SVG_NS, 'line');
    line.setAttribute('x1', '0');
    line.setAttribute('y1', String(350 + Math.random() * 280));
    line.setAttribute('x2', String(30 + Math.random() * 80));
    line.setAttribute('y2', String(350 + Math.random() * 280));
    line.setAttribute('stroke', '#00d4ff');
    line.setAttribute('stroke-width', '1');
    line.setAttribute('opacity', '0');
    line.setAttribute('class', 'speed-line');
    speedG.appendChild(line);
  }
}

// ===== 阶段切换 =====
function setPhase(newPhase) {
  state.phase = newPhase;
  state.phaseTime = 0;
  // 更新按钮状态
  document.querySelectorAll('.phase-btn').forEach(btn => {
    btn.classList.toggle('active', btn.dataset.phase === newPhase);
  });
  // 更新阶段指示
  const names = {standby:'STANDBY', accelerate:'ACCELERATE', cruise:'CRUISE', brake:'REGEN BRAKE', stop:'FULL STOP'};
  const colors = {standby:'#3e5278', accelerate:'#00d4ff', cruise:'#ffd600', brake:'#00ff88', stop:'#ff3d5a'};
  document.getElementById('phase-name').textContent = names[newPhase];
  document.getElementById('phase-name').setAttribute('fill', colors[newPhase]);
}

// ===== 状态更新 =====
function updateState(dt) {
  state.time += dt;
  state.phaseTime += dt;

  switch (state.phase) {
    case 'standby':
      state.speed = Math.max(0, state.speed - 3 * dt);
      state.torque = 0;
      state.acceleration = -3;
      state.regenPower = 0;
      break;
    case 'accelerate': {
      const maxA = 2.5 * state.friction;
      state.acceleration = maxA;
      state.speed = Math.min(state.targetSpeed, state.speed + maxA * dt);
      state.torque = 100 * (1 - state.speed / state.targetSpeed * 0.4) * state.friction;
      state.regenPower = 0;
      if (state.speed >= state.targetSpeed * 0.98) setPhase('cruise');
      break;
    }
    case 'cruise':
      state.speed = state.targetSpeed;
      state.acceleration = 0;
      state.torque = 15;
      state.regenPower = 0;
      break;
    case 'brake': {
      const brakeA = -4 * state.friction;
      state.acceleration = brakeA;
      state.speed = Math.max(0, state.speed + brakeA * dt);
      state.torque = -80 * state.friction;
      state.regenPower = Math.abs(state.speed * state.torque * 0.08);
      state.motorTemp = Math.min(135, state.motorTemp + 20 * dt);
      if (state.speed <= 0.05) setPhase('stop');
      break;
    }
    case 'stop':
      state.speed = 0;
      state.acceleration = 0;
      state.torque = 0;
      state.regenPower = 0;
      break;
  }

  // 电机冷却
  if (state.phase !== 'brake') {
    state.motorTemp = Math.max(25, state.motorTemp - 3 * dt);
  }

  // 轨道偏移
  state.trackOffset = (state.trackOffset + state.speed * 25 * dt) % 50;
  // 轮子旋转
  state.wheelAngle += state.speed * 3 * dt;
  // 电力流动偏移
  state.powerFlowOffset = (state.powerFlowOffset + state.speed * 80 * dt) % 40;
  // 电磁场旋转
  state.emFieldAngle += (state.speed * 2 + (state.phase === 'accelerate' ? 3 : 0)) * dt;
}

// ===== 渲染 =====
function render() {
  const isAccel = state.phase === 'accelerate';
  const isCruise = state.phase === 'cruise';
  const isBrake = state.phase === 'brake';
  const isStop = state.phase === 'stop';
  const isStandby = state.phase === 'standby';
  const isActive = isAccel || isCruise;
  const speedRatio = state.speed / 7;

  // 轨道枕木滚动
  const ties = document.querySelectorAll('.track-tie');
  ties.forEach((tie, i) => {
    const x = (i * 50 - state.trackOffset + 920) % (50 * 40) - 50;
    tie.setAttribute('x', String(x));
  });

  // 后轮旋转
  const rearSpokes = document.getElementById('spokes-rear');
  rearSpokes.setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI}, 390, 590)`);
  const rotorMag = document.getElementById('rotor-magnets');
  rotorMag.setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI * 0.95}, 390, 590)`);

  // 前轮旋转
  const frontSpokes = document.getElementById('spokes-front');
  frontSpokes.setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI}, 670, 595)`);

  // 定子线圈高亮
  const coils = document.querySelectorAll('.stator-coil');
  coils.forEach((c, i) => {
    const phase = (state.emFieldAngle * 3 + i * 0.7) % (Math.PI * 2);
    const bright = isActive ? 0.3 + 0.7 * Math.max(0, Math.sin(phase)) : 0.15;
    c.setAttribute('opacity', String(bright));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });

  // 剖面图线圈高亮
  const detailCoils = document.querySelectorAll('.detail-coil');
  detailCoils.forEach((c, i) => {
    const phase = (state.emFieldAngle * 3 + i * 0.5) % (Math.PI * 2);
    const bright = isActive || isBrake ? 0.2 + 0.8 * Math.max(0, Math.sin(phase)) : 0.1;
    c.setAttribute('opacity', String(bright));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });

  // 电力路径流动
  ['power-path-cm1', 'power-path-cm2', 'power-path-bc'].forEach(id => {
    const el = document.getElementById(id);
    if (isActive) {
      el.setAttribute('stroke', '#00d4ff');
      el.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
      el.setAttribute('opacity', String(0.4 + speedRatio * 0.5));
    } else if (isBrake) {
      el.setAttribute('stroke', '#00ff88');
      el.setAttribute('stroke-dashoffset', String(state.powerFlowOffset));
      el.setAttribute('opacity', String(0.3 + speedRatio * 0.4));
    } else {
      el.setAttribute('stroke', '#2a4060');
      el.setAttribute('opacity', '0.25');
    }
  });

  // 驱动力/再生力箭头
  const driveForce = document.getElementById('drive-force');
  const regenForce = document.getElementById('regen-force');
  driveForce.setAttribute('opacity', String(isActive ? Math.min(1, Math.abs(state.torque) / 60) : 0));
  regenForce.setAttribute('opacity', String(isBrake ? Math.min(1, Math.abs(state.torque) / 60) : 0));

  // 力矩弧线
  document.getElementById('torque-arc').setAttribute('opacity', String(isActive ? 0.8 : 0));
  document.getElementById('regen-arc').setAttribute('opacity', String(isBrake ? 0.8 : 0));

  // 控制器LED
  const led = document.getElementById('ctrl-led');
  if (isActive) {
    led.setAttribute('fill', '#00d4ff');
    led.setAttribute('filter', 'url(#softglow)');
  } else if (isBrake) {
    led.setAttribute('fill', '#00ff88');
    led.setAttribute('filter', 'url(#softglow)');
  } else if (isStop) {
    led.setAttribute('fill', '#ff3d5a');
    led.removeAttribute('filter');
  } else {
    led.setAttribute('fill', '#1a2a40');
    led.removeAttribute('filter');
  }

  // 电池条
  const batBar = document.getElementById('bat-bar');
  const batLevel = isBrake ? Math.min(1, 0.5 + state.regenPower / 80) : Math.max(0.2, 0.8 - speedRatio * 0.3);
  batBar.setAttribute('height', String(20 * batLevel));
  batBar.setAttribute('fill', isBrake ? '#00ff88' : '#1a4a2a');

  // 俯视图差速线
  const diffL = document.getElementById('diff-line-l');
  const diffR = document.getElementById('diff-line-r');
  if (isActive || isBrake) {
    const color = isBrake ? '#00ff88' : '#00d4ff';
    diffL.setAttribute('stroke', color);
    diffR.setAttribute('stroke', color);
    diffL.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    diffR.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    diffL.setAttribute('opacity', '0.8');
    diffR.setAttribute('opacity', '0.8');
  } else {
    diffL.setAttribute('stroke', '#2a4060');
    diffR.setAttribute('stroke', '#2a4060');
    diffL.setAttribute('opacity', '0.4');
    diffR.setAttribute('opacity', '0.4');
  }

  // 同步指示
  const syncInd = document.getElementById('sync-indicator');
  syncInd.setAttribute('opacity', String(isActive || isCruise ? 0.9 : 0));

  // 方向箭头
  const dirArrow = document.getElementById('direction-arrow');
  dirArrow.setAttribute('opacity', String(state.speed > 0.1 ? 0.8 : 0));

  // 速度线
  const speedLines = document.querySelectorAll('.speed-line');
  speedLines.forEach((line, i) => {
    if (state.speed > 1) {
      const alpha = Math.min(0.5, (state.speed - 1) / 6) * (0.3 + Math.random() * 0.7);
      line.setAttribute('opacity', String(alpha));
      line.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
      const y = 360 + ((i * 47 + state.time * 200) % 260);
      const len = 30 + state.speed * 15 + Math.random() * 40;
      const x = -len - Math.random() * 200;
      line.setAttribute('y1', String(y));
      line.setAttribute('y2', String(y));
      line.setAttribute('x1', String(x));
      line.setAttribute('x2', String(x + len));
    } else {
      line.setAttribute('opacity', '0');
    }
  });

  // 轮毂电机发光
  const hubGroup = document.getElementById('hub-motor-group');
  if (isActive) {
    hubGroup.setAttribute('filter', 'url(#glow-cyan)');
  } else if (isBrake) {
    hubGroup.setAttribute('filter', 'url(#glow-green)');
  } else {
    hubGroup.removeAttribute('filter');
  }

  // 零传动链标注
  const noShaft = document.getElementById('no-shaft-label');
  noShaft.setAttribute('opacity', String(0.35 + speedRatio * 0.35));

  // 俯视图电机高亮
  ['top-left-motor', 'top-right-motor'].forEach(id => {
    const g = document.getElementById(id);
    const circle = g.querySelector('circle:nth-child(2)');
    if (isActive) {
      circle.setAttribute('stroke', '#00d4ff');
      circle.setAttribute('stroke-width', '2');
    } else if (isBrake) {
      circle.setAttribute('stroke', '#00ff88');
      circle.setAttribute('stroke-width', '2');
    } else {
      circle.setAttribute('stroke', '#1e3050');
      circle.setAttribute('stroke-width', '1');
    }
  });

  // 参数更新
  document.getElementById('svg-speed').textContent = state.speed.toFixed(1);
  document.getElementById('svg-accel').textContent = Math.abs(state.acceleration).toFixed(1);
  document.getElementById('svg-torque').textContent = Math.abs(Math.round(state.torque));
  document.getElementById('svg-regen').textContent = Math.round(state.regenPower);
  document.getElementById('svg-temp').textContent = Math.round(state.motorTemp);

  // 温度颜色
  const tempEl = document.getElementById('svg-temp');
  if (state.motorTemp > 100) tempEl.setAttribute('fill', '#ff3d5a');
  else if (state.motorTemp > 70) tempEl.setAttribute('fill', '#ff6b2b');
  else if (state.motorTemp > 45) tempEl.setAttribute('fill', '#ffd600');
  else tempEl.setAttribute('fill', '#ffd600');

  // 加速度颜色
  const accelEl = document.getElementById('svg-accel');
  accelEl.setAttribute('fill', state.acceleration >= 0 ? '#00d4ff' : '#ff6b2b');

  // 力矩颜色
  const torqueEl = document.getElementById('svg-torque');
  torqueEl.setAttribute('fill', state.torque >= 0 ? '#00d4ff' : '#00ff88');
}

// ===== 动画循环 =====
let lastTime = 0;
function animate(timestamp) {
  const dt = Math.min(0.05, (timestamp - lastTime) / 1000);
  lastTime = timestamp;
  updateState(dt);
  render();
  requestAnimationFrame(animate);
}

// ===== 事件绑定 =====
document.querySelectorAll('.phase-btn').forEach(btn => {
  btn.addEventListener('click', () => setPhase(btn.dataset.phase));
});

document.getElementById('speed-slider').addEventListener('input', e => {
  state.targetSpeed = parseFloat(e.target.value);
  document.getElementById('speed-val').textContent = state.targetSpeed.toFixed(1) + ' m/s';
});

document.getElementById('friction-slider').addEventListener('input', e => {
  state.friction = parseFloat(e.target.value);
  document.getElementById('friction-val').textContent = state.friction.toFixed(1);
});

// ===== 启动 =====
initDynamicElements();
setPhase('standby');
requestAnimationFrame(animate);
</script>
</body>
</html>

实现说明

本动画以 TRIZ 的"最终理想解 (IFR)"思想为核心设计线索,聚焦展示轮毂直驱系统"轮即电机、动力直达轮缘"的本质机理:

  1. IFR 聚焦:主视图直接呈现消除传动链后的理想构型——轮毂电机内部定子线圈与转子磁钢直接耦合,电磁力不经任何中间环节即转化为轮缘驱动力。两轮之间标注"ZERO DRIVE SHAFT"并附禁止符号,视觉强化"零传动链"概念。

  2. 资源利用可视化:右下角 IFR 面板以箭头动画展示"传动系统重量 → 结构强度"的再分配逻辑——将省下的 15kg 传动系统重量让渡给碳纤维承载结构,极致压榨推重比。

  3. 动态视觉引导

    • 加速阶段:青色电力流动线从控制器直达轮毂电机,定子线圈按三相时序明灭,力矩弧线标注"TORQUE"
    • 制动阶段:流动线反转为绿色,标注"REGEN",能量回馈电池
    • 俯视差速图:双轮毂电机同步脉冲可视化,"SYNC"指示器确认电子差速协同
  4. 交互性:底部控制面板可手动切换五个运行阶段(待机/起步加速/稳速/再生制动/抱刹),滑块可调目标速度(1-7 m/s)和轨道摩擦系数,摩擦降低时加速度与制动力相应衰减,模拟打滑边界。

  5. 剖面细节:右侧轮毂电机剖面图展示轮胎→轮辋→转子磁钢(红蓝交替)→气隙→定子齿+线圈→中心轴的完整结构,线圈按电磁相位实时明灭,直观呈现"电机即车轮"的 IFR 本质。

缺少货叉伸缩动画
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮毂直驱系统 · IFR 最终理想解原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#050a14;--bg2:#0a1628;--cyan:#00d4ff;--cyan-dim:rgba(0,212,255,0.12);
  --orange:#ff6b2b;--green:#00ff88;--yellow:#ffd600;--red:#ff3d5a;
  --white:#dce4f0;--muted:#3e5278;--struct:#14203a;--carbon:#0e1830;
  --border:#1a2a48;
}
body{background:var(--bg);color:var(--white);font-family:'JetBrains Mono',monospace;overflow:hidden;height:100vh;display:flex;flex-direction:column;user-select:none}
header{padding:12px 28px;display:flex;align-items:baseline;gap:18px;border-bottom:1px solid var(--border);background:linear-gradient(180deg,rgba(10,22,40,0.95),transparent);position:relative;z-index:2}
header h1{font-family:'Orbitron',sans-serif;font-size:18px;font-weight:700;letter-spacing:2px;color:var(--cyan);text-shadow:0 0 20px rgba(0,212,255,0.3)}
header p{font-size:11px;color:var(--muted);letter-spacing:1px}
#svg-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative}
#main-svg{width:100%;height:100%;max-height:calc(100vh - 120px)}
#controls{padding:10px 24px;display:flex;align-items:center;gap:14px;border-top:1px solid var(--border);background:linear-gradient(0deg,rgba(10,22,40,0.98),rgba(10,22,40,0.85));flex-wrap:wrap;justify-content:center}
.ctrl-section{display:flex;align-items:center;gap:10px}
.ctrl-label{font-size:9px;color:#2a4060;font-family:'Orbitron',sans-serif;letter-spacing:1px;text-transform:uppercase;writing-mode:vertical-lr;text-orientation:mixed}
.phase-btn{padding:7px 16px;border:1px solid var(--border);border-radius:6px;background:var(--carbon);color:var(--muted);font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer;transition:all .25s;letter-spacing:0.5px;display:flex;align-items:center;gap:6px}
.phase-btn:hover{border-color:var(--cyan);color:var(--white)}
.phase-btn.active{border-color:var(--cyan);color:var(--cyan);background:var(--cyan-dim);box-shadow:0 0 12px rgba(0,212,255,0.15)}
.phase-btn i{font-size:10px}
.sep{width:1px;height:28px;background:var(--border);margin:0 6px;flex-shrink:0}
.slider-group{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--muted)}
.slider-group label{white-space:nowrap}
.slider-group input[type=range]{-webkit-appearance:none;width:100px;height:4px;background:var(--border);border-radius:2px;outline:none}
.slider-group input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--cyan);border-radius:50%;cursor:pointer;box-shadow:0 0 6px rgba(0,212,255,0.4)}
.slider-val{color:var(--cyan);min-width:36px;text-align:right;font-weight:700;font-size:11px}
.fork-btn{padding:7px 18px;border:1px solid var(--border);border-radius:6px;background:var(--carbon);color:var(--muted);font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer;transition:all .25s;display:flex;align-items:center;gap:6px}
.fork-btn:hover{border-color:var(--orange);color:var(--white)}
.fork-btn.extending{border-color:var(--orange);color:var(--orange);background:rgba(255,107,43,0.1);box-shadow:0 0 12px rgba(255,107,43,0.15)}
.fork-btn.retracting{border-color:var(--green);color:var(--green);background:rgba(0,255,136,0.08)}
@keyframes pulse{0%,100%{opacity:.6}50%{opacity:1}}
</style>
</head>
<body>
<header>
  <h1>HUB-DIRECT DRIVE</h1>
  <p>IFR 最终理想解 · 零传动链原理动画</p>
</header>
<div id="svg-wrap">
<svg id="main-svg" viewBox="0 0 1400 850" preserveAspectRatio="xMidYMid meet">
<defs>
  <pattern id="carbon" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
    <rect width="8" height="8" fill="#0e1830"/>
    <rect width="4" height="8" fill="#13203e"/>
  </pattern>
  <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
    <path d="M40 0L0 0 0 40" fill="none" stroke="#0c1828" stroke-width="0.5"/>
  </pattern>
  <filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
    <feFlood flood-color="#00d4ff" flood-opacity="0.5"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glow-orange" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feFlood flood-color="#ff6b2b" flood-opacity="0.45"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glow-green" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feFlood flood-color="#00ff88" flood-opacity="0.45"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="softglow" x="-30%" y="-30%" width="160%" height="160%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <marker id="arrow-cyan" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00d4ff"/></marker>
  <marker id="arrow-orange" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#ff6b2b"/></marker>
  <marker id="arrow-green" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00ff88"/></marker>
  <linearGradient id="metal" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#3a4a6a"/><stop offset="50%" stop-color="#5a6a8a"/><stop offset="100%" stop-color="#2a3a5a"/></linearGradient>
  <radialGradient id="hub-grad" cx="50%" cy="45%"><stop offset="0%" stop-color="#2a4060"/><stop offset="70%" stop-color="#14203a"/><stop offset="100%" stop-color="#0a1428"/></radialGradient>
  <radialGradient id="tire-grad" cx="50%" cy="45%"><stop offset="0%" stop-color="#1a1a2a"/><stop offset="80%" stop-color="#0a0a14"/><stop offset="100%" stop-color="#050508"/></radialGradient>
  <!-- 货叉导轨渐变 -->
  <linearGradient id="rail-grad" x1="0" y1="0" x2="1" y2="0">
    <stop offset="0%" stop-color="#1e3050"/><stop offset="50%" stop-color="#2a4568"/><stop offset="100%" stop-color="#1e3050"/>
  </linearGradient>
  <linearGradient id="rail-glow-grad" x1="0" y1="0" x2="1" y2="0">
    <stop offset="0%" stop-color="#ff6b2b" stop-opacity="0"/><stop offset="20%" stop-color="#ff6b2b" stop-opacity="0.6"/><stop offset="80%" stop-color="#ff6b2b" stop-opacity="0.6"/><stop offset="100%" stop-color="#ff6b2b" stop-opacity="0"/>
  </linearGradient>
</defs>

<!-- 背景 -->
<rect width="1400" height="850" fill="url(#grid)"/>
<ellipse cx="500" cy="700" rx="500" ry="120" fill="rgba(0,212,255,0.02)"/>

<!-- ===== 轨道 ===== -->
<g id="track-group">
  <line x1="0" y1="638" x2="920" y2="638" stroke="#1a2a48" stroke-width="3"/>
  <line x1="0" y1="644" x2="920" y2="644" stroke="#1a2a48" stroke-width="1.5"/>
  <g id="track-ties"></g>
</g>

<!-- ===== 速度线 ===== -->
<g id="speed-lines"></g>

<!-- ===== 车辆主体 ===== -->
<g id="vehicle-group">
  <!-- 碳纤维底盘桁架 -->
  <g id="chassis" stroke="#1e3050" stroke-width="3" fill="none">
    <line x1="310" y1="465" x2="690" y2="465" stroke="#2a4060" stroke-width="4"/>
    <line x1="290" y1="540" x2="710" y2="540" stroke="#2a4060" stroke-width="4"/>
    <line x1="350" y1="465" x2="340" y2="540"/>
    <line x1="430" y1="465" x2="420" y2="540"/>
    <line x1="510" y1="465" x2="510" y2="540"/>
    <line x1="590" y1="465" x2="600" y2="540"/>
    <line x1="670" y1="465" x2="680" y2="540"/>
    <line x1="340" y1="540" x2="430" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="420" y1="540" x2="510" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="510" y1="540" x2="590" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="600" y1="540" x2="670" y2="465" stroke="#1e3050" stroke-width="2"/>
    <line x1="350" y1="465" x2="420" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="430" y1="465" x2="510" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="510" y1="465" x2="600" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <line x1="590" y1="465" x2="680" y2="540" stroke="#1e3050" stroke-width="2" stroke-dasharray="4,4"/>
    <g fill="#2a4a70">
      <circle cx="350" cy="465" r="4"/><circle cx="430" cy="465" r="4"/>
      <circle cx="510" cy="465" r="4"/><circle cx="590" cy="465" r="4"/>
      <circle cx="670" cy="465" r="4"/><circle cx="340" cy="540" r="4"/>
      <circle cx="420" cy="540" r="4"/><circle cx="510" cy="540" r="4"/>
      <circle cx="600" cy="540" r="4"/><circle cx="680" cy="540" r="4"/>
    </g>
  </g>
  <rect x="305" y="468" width="390" height="68" fill="url(#carbon)" opacity="0.4" rx="2"/>

  <!-- 控制器盒 -->
  <rect x="460" y="488" width="100" height="36" rx="4" fill="#0c1828" stroke="#2a4060" stroke-width="1.5"/>
  <text x="510" y="510" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono">CTRL</text>
  <rect id="ctrl-led" x="466" y="494" width="6" height="6" rx="3" fill="#1a2a40"/>

  <!-- 电池 -->
  <rect x="360" y="492" width="70" height="30" rx="3" fill="#0c1424" stroke="#1e3050" stroke-width="1"/>
  <text x="395" y="511" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">BAT 48V</text>
  <rect id="bat-bar" x="366" y="496" width="4" height="20" rx="1" fill="#1a3a20"/>

  <!-- ===== 货叉系统(可伸缩)===== -->
  <g id="fork-system">
    <!-- 导轨(固定在车架上) -->
    <g id="fork-rails">
      <!-- 上导轨 -->
      <rect x="690" y="473" width="200" height="4" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="690" y="487" width="200" height="4" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <!-- 下导轨 -->
      <rect x="690" y="518" width="200" height="4" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="690" y="532" width="200" height="4" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <!-- 导轨端盖 -->
      <rect x="886" y="470" width="6" height="24" rx="2" fill="#1a2a44"/>
      <rect x="886" y="515" width="6" height="24" rx="2" fill="#1a2a44"/>
    </g>

    <!-- 导轨发光层(伸缩时激活) -->
    <g id="rail-glow" opacity="0">
      <rect x="690" y="473" width="200" height="18" rx="1" fill="url(#rail-glow-grad)" opacity="0.15"/>
      <rect x="690" y="518" width="200" height="18" rx="1" fill="url(#rail-glow-grad)" opacity="0.15"/>
    </g>

    <!-- 伸缩货叉 - 上层 -->
    <g id="fork-upper">
      <rect x="690" y="477" width="200" height="10" rx="1.5" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.2"/>
      <!-- 碳纤维纹理线 -->
      <line x1="700" y1="479" x2="880" y2="479" stroke="#1a2a44" stroke-width="0.5"/>
      <line x1="700" y1="485" x2="880" y2="485" stroke="#1a2a44" stroke-width="0.5"/>
      <!-- 叉尖 -->
      <path d="M890,477 L910,480 L910,484 L890,487Z" fill="#14203a" stroke="#1e3050" stroke-width="0.8"/>
      <!-- 限位标记 -->
      <g id="fork-marks-upper" fill="#1e3050" font-size="6" font-family="JetBrains Mono">
        <text x="720" y="485">0</text>
        <text x="770" y="485">50</text>
        <text x="820" y="485">100</text>
        <text x="860" y="485">150</text>
      </g>
    </g>

    <!-- 伸缩货叉 - 下层 -->
    <g id="fork-lower">
      <rect x="690" y="522" width="200" height="10" rx="1.5" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.2"/>
      <line x1="700" y1="524" x2="880" y2="524" stroke="#1a2a44" stroke-width="0.5"/>
      <line x1="700" y1="530" x2="880" y2="530" stroke="#1a2a44" stroke-width="0.5"/>
      <path d="M890,522 L910,525 L910,529 L890,532Z" fill="#14203a" stroke="#1e3050" stroke-width="0.8"/>
      <g id="fork-marks-lower" fill="#1e3050" font-size="6" font-family="JetBrains Mono">
        <text x="720" y="530">0</text>
        <text x="770" y="530">50</text>
        <text x="820" y="530">100</text>
        <text x="860" y="530">150</text>
      </g>
    </g>

    <!-- 竖向连接件(随货叉移动) -->
    <g id="fork-verticals">
      <line x1="700" y1="487" x2="700" y2="522" stroke="#1e3050" stroke-width="2.5"/>
      <line x1="735" y1="487" x2="735" y2="522" stroke="#1e3050" stroke-width="1.5"/>
    </g>

    <!-- 伸缩位移标注 -->
    <g id="fork-dimension" opacity="0">
      <!-- 标注线 -->
      <line x1="690" y1="460" x2="690" y2="455" stroke="#ff6b2b" stroke-width="0.8"/>
      <line id="fork-dim-end" x1="690" y1="460" x2="690" y2="455" stroke="#ff6b2b" stroke-width="0.8"/>
      <line x1="690" y1="457" x2="690" y2="457" stroke="#ff6b2b" stroke-width="0.8" marker-end="url(#arrow-orange)" marker-start="url(#arrow-orange)"/>
      <text id="fork-dim-text" x="690" y="452" text-anchor="middle" fill="#ff6b2b" font-size="9" font-family="Orbitron" font-weight="700">0mm</text>
    </g>

    <!-- 驱动指示(微型电动推杆) -->
    <g id="fork-actuator" opacity="0.5">
      <rect x="692" y="498" width="50" height="6" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="0.8"/>
      <rect id="fork-actuator-rod" x="740" y="499.5" width="30" height="3" rx="1" fill="#2a4060"/>
    </g>

    <!-- 货叉标签 -->
    <text x="790" y="510" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono" letter-spacing="1" id="fork-label-text">CARBON FORK</text>
  </g>

  <!-- ===== 后轮:轮毂电机 ===== -->
  <g id="hub-motor-group">
    <circle cx="390" cy="590" r="52" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="2"/>
    <circle cx="390" cy="590" r="42" fill="none" stroke="#2a3a5a" stroke-width="2.5"/>
    <circle cx="390" cy="590" r="36" fill="none" stroke="#1e3050" stroke-width="1"/>
    <g id="rotor-magnets"></g>
    <circle cx="390" cy="590" r="28" fill="none" stroke="#0a1428" stroke-width="0.5" stroke-dasharray="2,2"/>
    <circle cx="390" cy="590" r="24" fill="#0c1424" stroke="#1a2a44" stroke-width="1"/>
    <g id="stator-coils"></g>
    <circle cx="390" cy="590" r="8" fill="#14203a" stroke="#2a4060" stroke-width="1.5"/>
    <circle cx="390" cy="590" r="3" fill="#2a4060"/>
    <g stroke="#1e3050" stroke-width="1.5" id="spokes-rear">
      <line x1="390" y1="566" x2="390" y2="548"/>
      <line x1="390" y1="614" x2="390" y2="632"/>
      <line x1="366" y1="590" x2="348" y2="590"/>
      <line x1="414" y1="590" x2="432" y2="590"/>
      <line x1="373" y1="573" x2="360" y2="560"/>
      <line x1="407" y1="607" x2="420" y2="620"/>
      <line x1="373" y1="607" x2="360" y2="620"/>
      <line x1="407" y1="573" x2="420" y2="560"/>
    </g>
    <text x="390" y="530" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono" letter-spacing="0.5">HUB MOTOR</text>
    <text x="390" y="660" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">≤4kg × 2</text>
  </g>

  <!-- ===== 前轮:从动轮 ===== -->
  <g id="passive-wheel-group">
    <circle cx="670" cy="595" r="42" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="1.5"/>
    <circle cx="670" cy="595" r="34" fill="none" stroke="#1a2a40" stroke-width="1.5"/>
    <circle cx="670" cy="595" r="6" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <g stroke="#141e30" stroke-width="1" id="spokes-front">
      <line x1="670" y1="563" x2="670" y2="553"/>
      <line x1="670" y1="627" x2="670" y2="637"/>
      <line x1="638" y1="595" x2="628" y2="595"/>
      <line x1="702" y1="595" x2="712" y2="595"/>
    </g>
    <text x="670" y="655" text-anchor="middle" fill="#141e30" font-size="7" font-family="JetBrains Mono">PASSIVE</text>
  </g>

  <!-- "零传动链"标注 -->
  <g id="no-shaft-label" opacity="0.6">
    <line x1="430" y1="590" x2="630" y2="590" stroke="#1e3050" stroke-width="1" stroke-dasharray="6,4"/>
    <text x="530" y="585" text-anchor="middle" fill="#2a4060" font-size="8" font-family="Orbitron" letter-spacing="1">ZERO DRIVE SHAFT</text>
    <circle cx="530" cy="598" r="8" fill="none" stroke="#2a4060" stroke-width="1"/>
    <line x1="524" y1="604" x2="536" y2="592" stroke="#2a4060" stroke-width="1"/>
  </g>
</g>

<!-- ===== 电力流向线 ===== -->
<g id="power-flow-group">
  <path id="power-path-bc" d="M430,507 L460,507" fill="none" stroke="#2a4060" stroke-width="2" stroke-dasharray="4,4" opacity="0.5"/>
  <path id="power-path-cm1" d="M460,495 Q440,460 390,460 Q350,460 350,530 Q350,565 365,575" fill="none" stroke="#2a4060" stroke-width="2" stroke-dasharray="4,6" opacity="0.5"/>
  <path id="power-path-cm2" d="M460,520 Q420,555 400,570" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,5" opacity="0.3"/>
</g>

<!-- ===== 接触力箭头 ===== -->
<g id="force-arrows">
  <g id="drive-force" opacity="0">
    <line x1="335" y1="640" x2="280" y2="640" stroke="#00d4ff" stroke-width="3" marker-end="url(#arrow-cyan)"/>
    <text x="305" y="656" text-anchor="middle" fill="#00d4ff" font-size="9" font-family="Orbitron">F</text>
  </g>
  <g id="regen-force" opacity="0">
    <line x1="280" y1="640" x2="335" y2="640" stroke="#00ff88" stroke-width="3" marker-end="url(#arrow-green)"/>
    <text x="305" y="656" text-anchor="middle" fill="#00ff88" font-size="9" font-family="Orbitron">REGEN</text>
  </g>
</g>

<!-- ===== 阶段指示 ===== -->
<g id="phase-indicator" transform="translate(50,40)">
  <rect x="0" y="0" width="200" height="44" rx="6" fill="rgba(10,22,40,0.85)" stroke="#1a2a48" stroke-width="1"/>
  <text id="phase-text" x="100" y="18" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono" letter-spacing="1">PHASE</text>
  <text id="phase-name" x="100" y="35" text-anchor="middle" fill="#00d4ff" font-size="14" font-family="Orbitron" font-weight="700">STANDBY</text>
</g>

<!-- ===== 货叉伸缩状态指示 ===== -->
<g id="fork-status" transform="translate(50,92)">
  <rect x="0" y="0" width="200" height="38" rx="6" fill="rgba(10,22,40,0.85)" stroke="#1a2a48" stroke-width="1"/>
  <text x="100" y="16" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono" letter-spacing="1">FORK EXTENSION</text>
  <text id="fork-status-val" x="100" y="32" text-anchor="middle" fill="#ff6b2b" font-size="13" font-family="Orbitron" font-weight="700">0 mm</text>
</g>

<!-- ===== 右侧面板:俯视图 ===== -->
<g transform="translate(940,20)">
  <rect x="0" y="0" width="440" height="260" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">TOP VIEW · ELECTRONIC DIFFERENTIAL</text>
  <!-- 车体轮廓 -->
  <rect x="130" y="50" width="180" height="180" rx="6" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.5" opacity="0.6"/>
  <!-- 俯视货叉(可伸缩) -->
  <g id="fork-top-group">
    <rect id="fork-top-upper" x="310" y="80" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <rect id="fork-top-lower" x="310" y="186" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <!-- 俯视叉尖 -->
    <path id="fork-top-tip-u" d="M410,80 L425,83 L425,91 L410,94Z" fill="#14203a" stroke="#1e3050" stroke-width="0.6"/>
    <path id="fork-top-tip-l" d="M410,186 L425,189 L425,197 L410,200Z" fill="#14203a" stroke="#1e3050" stroke-width="0.6"/>
  </g>
  <!-- 控制器 -->
  <rect x="190" y="120" width="60" height="40" rx="3" fill="#0c1828" stroke="#2a4060" stroke-width="1"/>
  <text x="220" y="144" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">ECU</text>
  <!-- 左轮毂电机 -->
  <g id="top-left-motor">
    <circle cx="130" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="130" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="130" cy="140" r="5" fill="#14203a"/>
    <text x="100" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">L-HUB</text>
  </g>
  <!-- 右轮毂电机 -->
  <g id="top-right-motor">
    <circle cx="310" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="310" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="310" cy="140" r="5" fill="#14203a"/>
    <text x="340" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">R-HUB</text>
  </g>
  <!-- 从动轮 -->
  <circle cx="170" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="170" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <!-- 差速控制线 -->
  <path id="diff-line-l" d="M190,140 L155,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <path id="diff-line-r" d="M250,140 L285,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <!-- 同步指示 -->
  <g id="sync-indicator" opacity="0">
    <text x="220" y="200" text-anchor="middle" fill="#00d4ff" font-size="8" font-family="Orbitron" letter-spacing="1">SYNC</text>
    <rect x="185" y="205" width="70" height="3" rx="1.5" fill="#0a1428"/>
    <rect id="sync-bar" x="185" y="205" width="70" height="3" rx="1.5" fill="#00d4ff" opacity="0.6"/>
  </g>
  <!-- 方向箭头 -->
  <g id="direction-arrow" opacity="0">
    <line x1="220" y1="30" x2="220" y2="10" stroke="#00d4ff" stroke-width="2" marker-end="url(#arrow-cyan)"/>
  </g>
</g>

<!-- ===== 右侧面板:轮毂电机剖面 ===== -->
<g transform="translate(940,300)">
  <rect x="0" y="0" width="440" height="280" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">HUB MOTOR CROSS-SECTION</text>
  <g transform="translate(160,155)">
    <circle r="100" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="2"/>
    <circle r="85" fill="none" stroke="#2a3a5a" stroke-width="2"/>
    <circle r="75" fill="none" stroke="#1e3050" stroke-width="6" id="rotor-ring"/>
    <g id="detail-magnets"></g>
    <circle r="60" fill="none" stroke="rgba(0,212,255,0.1)" stroke-width="2" stroke-dasharray="2,3"/>
    <circle r="52" fill="#0c1424" stroke="#1a2a44" stroke-width="1.5"/>
    <g id="detail-stator"></g>
    <circle r="14" fill="#14203a" stroke="#2a4060" stroke-width="2"/>
    <circle r="5" fill="#1e3050"/>
    <g id="torque-arc" opacity="0">
      <path d="M-40,-90 A98,98 0 0,1 40,-90" fill="none" stroke="#00d4ff" stroke-width="2.5" marker-end="url(#arrow-cyan)"/>
      <text x="0" y="-96" text-anchor="middle" fill="#00d4ff" font-size="10" font-family="Orbitron" font-weight="700">TORQUE</text>
    </g>
    <g id="regen-arc" opacity="0">
      <path d="M40,-90 A98,98 0 0,1 -40,-90" fill="none" stroke="#00ff88" stroke-width="2.5" marker-end="url(#arrow-green)"/>
      <text x="0" y="-96" text-anchor="middle" fill="#00ff88" font-size="10" font-family="Orbitron" font-weight="700">REGEN</text>
    </g>
  </g>
  <g transform="translate(310,60)" fill="#3e5278" font-size="8" font-family="JetBrains Mono">
    <text y="0" fill="#2a4060">STRUCTURE</text>
    <circle cx="-8" cy="16" r="3" fill="#1a1a2a"/><text x="2" y="20">Tire</text>
    <circle cx="-8" cy="32" r="3" fill="#2a3a5a"/><text x="2" y="36">Rim</text>
    <circle cx="-8" cy="48" r="3" fill="#ff3d5a" opacity="0.6"/><text x="2" y="52">Rotor Mag</text>
    <circle cx="-8" cy="64" r="3" fill="#00d4ff" opacity="0.6"/><text x="2" y="68">Stator Coil</text>
    <circle cx="-8" cy="80" r="3" fill="#14203a"/><text x="2" y="84">Axle</text>
  </g>
</g>

<!-- ===== 右侧面板:IFR 原则 ===== -->
<g transform="translate(940,600)">
  <rect x="0" y="0" width="440" height="230" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">IFR · IDEAL FINAL RESULT</text>
  <g transform="translate(24,40)" font-family="JetBrains Mono" font-size="10">
    <text fill="#00d4ff" font-size="11" font-weight="700" font-family="Orbitron">Wheel = Motor</text>
    <text y="20" fill="#5a7aaa">轮即电机,动力直达轮缘</text>
    <text y="40" fill="#5a7aaa">零传动链 · 零机械间隙 · 零中间损耗</text>
    <line x1="0" y1="52" x2="392" y2="52" stroke="#1a2a48" stroke-width="0.5"/>
    <text y="70" fill="#2a4060" font-size="8" letter-spacing="1">WEIGHT REALLOCATION</text>
    <g transform="translate(0,82)">
      <rect width="120" height="24" rx="4" fill="rgba(255,107,43,0.1)" stroke="#ff6b2b" stroke-width="0.8"/>
      <text x="60" y="16" text-anchor="middle" fill="#ff6b2b" font-size="9">传动系统 15kg</text>
      <text x="145" y="16" fill="#3e5278" font-size="14">→</text>
      <rect x="170" width="120" height="24" rx="4" fill="rgba(0,255,136,0.08)" stroke="#00ff88" stroke-width="0.8"/>
      <text x="230" y="16" text-anchor="middle" fill="#00ff88" font-size="9">结构强度 +15kg</text>
    </g>
    <line x1="0" y1="116" x2="392" y2="116" stroke="#1a2a48" stroke-width="0.5"/>
    <text y="134" fill="#2a4060" font-size="8" letter-spacing="1">BOUNDARY / RISK</text>
    <text y="152" fill="#5a3a3a" font-size="9">⚠ 长时间极限制动 → 磁钢退磁风险</text>
    <text y="168" fill="#5a3a3a" font-size="9">⚠ 5m/s 轨道接缝冲击 → 轴承疲劳</text>
    <text y="184" fill="#5a3a3a" font-size="9">⚠ 粉尘/湿滑轨道 → 打滑失控</text>
  </g>
</g>

<!-- ===== 底部参数条 ===== -->
<g id="svg-params" transform="translate(50,790)" font-family="Orbitron" font-size="10">
  <g transform="translate(0,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">SPEED</text>
    <text id="svg-speed" y="18" fill="#00d4ff" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s</text>
  </g>
  <g transform="translate(120,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">ACCEL</text>
    <text id="svg-accel" y="18" fill="#ff6b2b" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s²</text>
  </g>
  <g transform="translate(240,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">TORQUE</text>
    <text id="svg-torque" y="18" fill="#00d4ff" font-size="16" font-weight="700">0</text>
    <text x="38" y="18" fill="#3e5278" font-size="8">Nm</text>
  </g>
  <g transform="translate(350,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">REGEN</text>
    <text id="svg-regen" y="18" fill="#00ff88" font-size="16" font-weight="700">0</text>
    <text x="44" y="18" fill="#3e5278" font-size="8">W</text>
  </g>
  <g transform="translate(460,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">MOTOR TEMP</text>
    <text id="svg-temp" y="18" fill="#ffd600" font-size="16" font-weight="700">25</text>
    <text x="42" y="18" fill="#3e5278" font-size="8">°C</text>
  </g>
  <g transform="translate(590,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">FORK</text>
    <text id="svg-fork" y="18" fill="#ff6b2b" font-size="16" font-weight="700">0</text>
    <text x="38" y="18" fill="#3e5278" font-size="8">mm</text>
  </g>
</g>

</svg>
</div>

<!-- 控制面板 -->
<div id="controls">
  <div class="ctrl-section">
    <span class="ctrl-label">驱动</span>
    <button class="phase-btn active" data-phase="standby"><i class="fas fa-power-off"></i>待机</button>
    <button class="phase-btn" data-phase="accelerate"><i class="fas fa-bolt"></i>起步加速</button>
    <button class="phase-btn" data-phase="cruise"><i class="fas fa-gauge-high"></i>稳速行驶</button>
    <button class="phase-btn" data-phase="brake"><i class="fas fa-rotate-left"></i>再生制动</button>
    <button class="phase-btn" data-phase="stop"><i class="fas fa-stop"></i>抱刹停止</button>
  </div>
  <div class="sep"></div>
  <div class="ctrl-section">
    <span class="ctrl-label">货叉</span>
    <button class="fork-btn" id="fork-extend-btn"><i class="fas fa-arrows-left-right"></i>伸出货叉</button>
    <button class="fork-btn" id="fork-retract-btn"><i class="fas fa-compress"></i>缩回货叉</button>
    <div class="slider-group">
      <label>伸缩量</label>
      <input type="range" id="fork-slider" min="0" max="150" step="5" value="0"/>
      <span class="slider-val" id="fork-val">0 mm</span>
    </div>
  </div>
  <div class="sep"></div>
  <div class="ctrl-section">
    <span class="ctrl-label">参数</span>
    <div class="slider-group">
      <label>目标速度</label>
      <input type="range" id="speed-slider" min="1" max="7" step="0.5" value="5"/>
      <span class="slider-val" id="speed-val">5.0 m/s</span>
    </div>
    <div class="slider-group">
      <label>轨道摩擦</label>
      <input type="range" id="friction-slider" min="0.3" max="1" step="0.1" value="0.8"/>
      <span class="slider-val" id="friction-val">0.8</span>
    </div>
  </div>
</div>

<script>
const SVG_NS = 'http://www.w3.org/2000/svg';

// ===== 状态管理 =====
const state = {
  phase: 'standby',
  speed: 0,
  targetSpeed: 5,
  friction: 0.8,
  acceleration: 0,
  torque: 0,
  regenPower: 0,
  motorTemp: 25,
  trackOffset: 0,
  wheelAngle: 0,
  time: 0,
  phaseTime: 0,
  powerFlowOffset: 0,
  emFieldAngle: 0,
  // 货叉状态
  forkExtension: 0,        // 当前伸缩量(像素单位,0-150)
  forkTarget: 0,           // 目标伸缩量
  forkSpeed: 0,            // 伸缩速度
  forkMoving: false,       // 是否正在伸缩
  forkDirection: 0,        // 1=伸出, -1=缩回, 0=静止
};

// 货叉伸缩的物理参数
const FORK_MAX = 150;       // 最大伸缩像素
const FORK_SPEED = 80;      // 伸缩速度 px/s
const FORK_SCALE = 1.0;     // 1px = 1mm(标注用)

// ===== 初始化 SVG 动态元素 =====
function initDynamicElements() {
  // 轨道枕木
  const tiesGroup = document.getElementById('track-ties');
  for (let i = 0; i < 40; i++) {
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', i * 50);
    rect.setAttribute('y', '632');
    rect.setAttribute('width', '20');
    rect.setAttribute('height', '16');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', '#0e1830');
    rect.setAttribute('stroke', '#1a2a44');
    rect.setAttribute('stroke-width', '0.5');
    rect.setAttribute('class', 'track-tie');
    tiesGroup.appendChild(rect);
  }

  // 轮毂电机磁钢
  const rotorG = document.getElementById('rotor-magnets');
  for (let i = 0; i < 12; i++) {
    const angle = (i * 30) * Math.PI / 180;
    const r = 36;
    const x = 390 + Math.cos(angle) * r;
    const y = 590 + Math.sin(angle) * r;
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', x - 4);
    rect.setAttribute('y', y - 3);
    rect.setAttribute('width', '8');
    rect.setAttribute('height', '6');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    rect.setAttribute('opacity', '0.5');
    rect.setAttribute('transform', `rotate(${i * 30}, ${x}, ${y})`);
    rotorG.appendChild(rect);
  }

  // 定子线圈
  const statorG = document.getElementById('stator-coils');
  for (let i = 0; i < 9; i++) {
    const angle = (i * 40) * Math.PI / 180;
    const r = 22;
    const x = 390 + Math.cos(angle) * r;
    const y = 590 + Math.sin(angle) * r;
    const circle = document.createElementNS(SVG_NS, 'circle');
    circle.setAttribute('cx', x);
    circle.setAttribute('cy', y);
    circle.setAttribute('r', '4');
    circle.setAttribute('fill', '#0a1428');
    circle.setAttribute('stroke', '#00d4ff');
    circle.setAttribute('stroke-width', '0.8');
    circle.setAttribute('opacity', '0.4');
    circle.setAttribute('class', 'stator-coil');
    statorG.appendChild(circle);
  }

  // 剖面图磁钢
  const detailMag = document.getElementById('detail-magnets');
  for (let i = 0; i < 20; i++) {
    const angle = (i * 18) * Math.PI / 180;
    const r = 75;
    const x = Math.cos(angle) * r;
    const y = Math.sin(angle) * r;
    const rect = document.createElementNS(SVG_NS, 'rect');
    rect.setAttribute('x', x - 5);
    rect.setAttribute('y', y - 3.5);
    rect.setAttribute('width', '10');
    rect.setAttribute('height', '7');
    rect.setAttribute('rx', '1');
    rect.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    rect.setAttribute('opacity', '0.45');
    rect.setAttribute('transform', `rotate(${i * 18}, ${x}, ${y})`);
    detailMag.appendChild(rect);
  }

  // 剖面图定子齿+线圈
  const detailStator = document.getElementById('detail-stator');
  for (let i = 0; i < 12; i++) {
    const g = document.createElementNS(SVG_NS, 'g');
    g.setAttribute('transform', `rotate(${i * 30})`);
    const tooth = document.createElementNS(SVG_NS, 'rect');
    tooth.setAttribute('x', '-3');
    tooth.setAttribute('y', '-52');
    tooth.setAttribute('width', '6');
    tooth.setAttribute('height', '14');
    tooth.setAttribute('rx', '1');
    tooth.setAttribute('fill', '#1a2a44');
    g.appendChild(tooth);
    const coil = document.createElementNS(SVG_NS, 'rect');
    coil.setAttribute('x', '-6');
    coil.setAttribute('y', '-48');
    coil.setAttribute('width', '12');
    coil.setAttribute('height', '8');
    coil.setAttribute('rx', '2');
    coil.setAttribute('fill', 'none');
    coil.setAttribute('stroke', '#00d4ff');
    coil.setAttribute('stroke-width', '0.8');
    coil.setAttribute('opacity', '0.3');
    coil.setAttribute('class', 'detail-coil');
    g.appendChild(coil);
    detailStator.appendChild(g);
  }

  // 速度线
  const speedG = document.getElementById('speed-lines');
  for (let i = 0; i < 20; i++) {
    const line = document.createElementNS(SVG_NS, 'line');
    line.setAttribute('x1', '0');
    line.setAttribute('y1', String(350 + Math.random() * 280));
    line.setAttribute('x2', String(30 + Math.random() * 80));
    line.setAttribute('y2', String(350 + Math.random() * 280));
    line.setAttribute('stroke', '#00d4ff');
    line.setAttribute('stroke-width', '1');
    line.setAttribute('opacity', '0');
    line.setAttribute('class', 'speed-line');
    speedG.appendChild(line);
  }
}

// ===== 阶段切换 =====
function setPhase(newPhase) {
  state.phase = newPhase;
  state.phaseTime = 0;
  document.querySelectorAll('.phase-btn').forEach(btn => {
    btn.classList.toggle('active', btn.dataset.phase === newPhase);
  });
  const names = {standby:'STANDBY', accelerate:'ACCELERATE', cruise:'CRUISE', brake:'REGEN BRAKE', stop:'FULL STOP'};
  const colors = {standby:'#3e5278', accelerate:'#00d4ff', cruise:'#ffd600', brake:'#00ff88', stop:'#ff3d5a'};
  document.getElementById('phase-name').textContent = names[newPhase];
  document.getElementById('phase-name').setAttribute('fill', colors[newPhase]);
}

// ===== 货叉控制 =====
function extendFork() {
  state.forkTarget = FORK_MAX;
  state.forkDirection = 1;
  state.forkMoving = true;
  document.getElementById('fork-extend-btn').classList.add('extending');
  document.getElementById('fork-retract-btn').classList.remove('retracting');
}

function retractFork() {
  state.forkTarget = 0;
  state.forkDirection = -1;
  state.forkMoving = true;
  document.getElementById('fork-retract-btn').classList.add('retracting');
  document.getElementById('fork-extend-btn').classList.remove('extending');
}

function setForkTarget(val) {
  state.forkTarget = val;
  state.forkDirection = val > state.forkExtension ? 1 : (val < state.forkExtension ? -1 : 0);
  state.forkMoving = Math.abs(val - state.forkExtension) > 0.5;
}

// ===== 状态更新 =====
function updateState(dt) {
  state.time += dt;
  state.phaseTime += dt;

  // 驱动状态更新
  switch (state.phase) {
    case 'standby':
      state.speed = Math.max(0, state.speed - 3 * dt);
      state.torque = 0;
      state.acceleration = state.speed > 0.01 ? -3 : 0;
      state.regenPower = 0;
      break;
    case 'accelerate': {
      const maxA = 2.5 * state.friction;
      state.acceleration = maxA;
      state.speed = Math.min(state.targetSpeed, state.speed + maxA * dt);
      state.torque = 100 * (1 - state.speed / state.targetSpeed * 0.4) * state.friction;
      state.regenPower = 0;
      if (state.speed >= state.targetSpeed * 0.98) setPhase('cruise');
      break;
    }
    case 'cruise':
      state.speed = state.targetSpeed;
      state.acceleration = 0;
      state.torque = 15;
      state.regenPower = 0;
      break;
    case 'brake': {
      const brakeA = -4 * state.friction;
      state.acceleration = brakeA;
      state.speed = Math.max(0, state.speed + brakeA * dt);
      state.torque = -80 * state.friction;
      state.regenPower = Math.abs(state.speed * state.torque * 0.08);
      state.motorTemp = Math.min(135, state.motorTemp + 20 * dt);
      if (state.speed <= 0.05) setPhase('stop');
      break;
    }
    case 'stop':
      state.speed = 0;
      state.acceleration = 0;
      state.torque = 0;
      state.regenPower = 0;
      break;
  }

  if (state.phase !== 'brake') {
    state.motorTemp = Math.max(25, state.motorTemp - 3 * dt);
  }

  // 货叉伸缩更新
  if (state.forkMoving) {
    const diff = state.forkTarget - state.forkExtension;
    const step = FORK_SPEED * dt;
    if (Math.abs(diff) <= step) {
      state.forkExtension = state.forkTarget;
      state.forkMoving = false;
      state.forkDirection = 0;
      state.forkSpeed = 0;
      document.getElementById('fork-extend-btn').classList.remove('extending');
      document.getElementById('fork-retract-btn').classList.remove('retracting');
    } else {
      state.forkExtension += Math.sign(diff) * step;
      state.forkSpeed = Math.sign(diff) * FORK_SPEED;
    }
  } else {
    state.forkSpeed = 0;
  }

  // 轨道偏移
  state.trackOffset = (state.trackOffset + state.speed * 25 * dt) % 50;
  // 轮子旋转
  state.wheelAngle += state.speed * 3 * dt;
  // 电力流动偏移
  state.powerFlowOffset = (state.powerFlowOffset + state.speed * 80 * dt) % 40;
  // 电磁场旋转
  state.emFieldAngle += (state.speed * 2 + (state.phase === 'accelerate' ? 3 : 0)) * dt;
}

// ===== 渲染 =====
function render() {
  const isAccel = state.phase === 'accelerate';
  const isCruise = state.phase === 'cruise';
  const isBrake = state.phase === 'brake';
  const isStop = state.phase === 'stop';
  const isStandby = state.phase === 'standby';
  const isActive = isAccel || isCruise;
  const speedRatio = state.speed / 7;
  const ext = state.forkExtension;
  const isForkMoving = state.forkMoving;

  // ---- 轨道枕木滚动 ----
  const ties = document.querySelectorAll('.track-tie');
  ties.forEach((tie, i) => {
    const x = (i * 50 - state.trackOffset + 920) % (50 * 40) - 50;
    tie.setAttribute('x', String(x));
  });

  // ---- 轮子旋转 ----
  document.getElementById('spokes-rear').setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI}, 390, 590)`);
  document.getElementById('rotor-magnets').setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI * 0.95}, 390, 590)`);
  document.getElementById('spokes-front').setAttribute('transform', `rotate(${state.wheelAngle * 180 / Math.PI}, 670, 595)`);

  // ---- 定子线圈高亮 ----
  const coils = document.querySelectorAll('.stator-coil');
  coils.forEach((c, i) => {
    const phase = (state.emFieldAngle * 3 + i * 0.7) % (Math.PI * 2);
    const bright = isActive ? 0.3 + 0.7 * Math.max(0, Math.sin(phase)) : 0.15;
    c.setAttribute('opacity', String(bright));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });

  const detailCoils = document.querySelectorAll('.detail-coil');
  detailCoils.forEach((c, i) => {
    const phase = (state.emFieldAngle * 3 + i * 0.5) % (Math.PI * 2);
    const bright = isActive || isBrake ? 0.2 + 0.8 * Math.max(0, Math.sin(phase)) : 0.1;
    c.setAttribute('opacity', String(bright));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });

  // ---- 电力路径流动 ----
  ['power-path-cm1', 'power-path-cm2', 'power-path-bc'].forEach(id => {
    const el = document.getElementById(id);
    if (isActive) {
      el.setAttribute('stroke', '#00d4ff');
      el.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
      el.setAttribute('opacity', String(0.4 + speedRatio * 0.5));
    } else if (isBrake) {
      el.setAttribute('stroke', '#00ff88');
      el.setAttribute('stroke-dashoffset', String(state.powerFlowOffset));
      el.setAttribute('opacity', String(0.3 + speedRatio * 0.4));
    } else {
      el.setAttribute('stroke', '#2a4060');
      el.setAttribute('opacity', '0.25');
    }
  });

  // ---- 驱动力/再生力箭头 ----
  document.getElementById('drive-force').setAttribute('opacity', String(isActive ? Math.min(1, Math.abs(state.torque) / 60) : 0));
  document.getElementById('regen-force').setAttribute('opacity', String(isBrake ? Math.min(1, Math.abs(state.torque) / 60) : 0));

  // ---- 力矩弧线 ----
  document.getElementById('torque-arc').setAttribute('opacity', String(isActive ? 0.8 : 0));
  document.getElementById('regen-arc').setAttribute('opacity', String(isBrake ? 0.8 : 0));

  // ---- 控制器LED ----
  const led = document.getElementById('ctrl-led');
  if (isActive) {
    led.setAttribute('fill', '#00d4ff');
    led.setAttribute('filter', 'url(#softglow)');
  } else if (isBrake) {
    led.setAttribute('fill', '#00ff88');
    led.setAttribute('filter', 'url(#softglow)');
  } else if (isStop) {
    led.setAttribute('fill', '#ff3d5a');
    led.removeAttribute('filter');
  } else {
    led.setAttribute('fill', '#1a2a40');
    led.removeAttribute('filter');
  }

  // ---- 电池条 ----
  const batBar = document.getElementById('bat-bar');
  const batLevel = isBrake ? Math.min(1, 0.5 + state.regenPower / 80) : Math.max(0.2, 0.8 - speedRatio * 0.3);
  batBar.setAttribute('height', String(20 * batLevel));
  batBar.setAttribute('fill', isBrake ? '#00ff88' : '#1a4a2a');

  // ---- 俯视图差速线 ----
  const diffL = document.getElementById('diff-line-l');
  const diffR = document.getElementById('diff-line-r');
  if (isActive || isBrake) {
    const color = isBrake ? '#00ff88' : '#00d4ff';
    diffL.setAttribute('stroke', color); diffR.setAttribute('stroke', color);
    diffL.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    diffR.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    diffL.setAttribute('opacity', '0.8'); diffR.setAttribute('opacity', '0.8');
  } else {
    diffL.setAttribute('stroke', '#2a4060'); diffR.setAttribute('stroke', '#2a4060');
    diffL.setAttribute('opacity', '0.4'); diffR.setAttribute('opacity', '0.4');
  }

  document.getElementById('sync-indicator').setAttribute('opacity', String(isActive || isCruise ? 0.9 : 0));
  document.getElementById('direction-arrow').setAttribute('opacity', String(state.speed > 0.1 ? 0.8 : 0));

  // ---- 速度线 ----
  const speedLines = document.querySelectorAll('.speed-line');
  speedLines.forEach((line, i) => {
    if (state.speed > 1) {
      const alpha = Math.min(0.5, (state.speed - 1) / 6) * (0.3 + Math.random() * 0.7);
      line.setAttribute('opacity', String(alpha));
      line.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
      const y = 360 + ((i * 47 + state.time * 200) % 260);
      const len = 30 + state.speed * 15 + Math.random() * 40;
      const x = -len - Math.random() * 200;
      line.setAttribute('y1', String(y)); line.setAttribute('y2', String(y));
      line.setAttribute('x1', String(x)); line.setAttribute('x2', String(x + len));
    } else {
      line.setAttribute('opacity', '0');
    }
  });

  // ---- 轮毂电机发光 ----
  const hubGroup = document.getElementById('hub-motor-group');
  if (isActive) hubGroup.setAttribute('filter', 'url(#glow-cyan)');
  else if (isBrake) hubGroup.setAttribute('filter', 'url(#glow-green)');
  else hubGroup.removeAttribute('filter');

  // ---- 零传动链标注 ----
  document.getElementById('no-shaft-label').setAttribute('opacity', String(0.35 + speedRatio * 0.35));

  // ---- 俯视图电机高亮 ----
  ['top-left-motor', 'top-right-motor'].forEach(id => {
    const g = document.getElementById(id);
    const circle = g.querySelector('circle:nth-child(2)');
    if (isActive) { circle.setAttribute('stroke', '#00d4ff'); circle.setAttribute('stroke-width', '2'); }
    else if (isBrake) { circle.setAttribute('stroke', '#00ff88'); circle.setAttribute('stroke-width', '2'); }
    else { circle.setAttribute('stroke', '#1e3050'); circle.setAttribute('stroke-width', '1'); }
  });

  // ============================================================
  //  货叉伸缩动画渲染
  // ============================================================

  // 主视图货叉平移
  const forkUpper = document.getElementById('fork-upper');
  const forkLower = document.getElementById('fork-lower');
  const forkVerts = document.getElementById('fork-verticals');
  forkUpper.setAttribute('transform', `translate(${ext}, 0)`);
  forkLower.setAttribute('transform', `translate(${ext}, 0)`);
  // 竖向连接件跟随
  forkVerts.setAttribute('transform', `translate(${ext}, 0)`);

  // 俯视图货叉伸缩
  const topScale = ext / FORK_MAX;
  const topExt = ext * 0.6;  // 俯视图中的伸缩量(缩放比例)
  const forkTopUpper = document.getElementById('fork-top-upper');
  const forkTopLower = document.getElementById('fork-top-lower');
  const forkTopTipU = document.getElementById('fork-top-tip-u');
  const forkTopTipL = document.getElementById('fork-top-tip-l');
  forkTopUpper.setAttribute('x', String(310 + topExt));
  forkTopUpper.setAttribute('width', String(100 + topExt * 0.3));
  forkTopLower.setAttribute('x', String(310 + topExt));
  forkTopLower.setAttribute('width', String(100 + topExt * 0.3));
  // 叉尖跟随
  const tipUx = 310 + topExt + 100 + topExt * 0.3;
  forkTopTipU.setAttribute('d', `M${tipUx},80 L${tipUx + 15},83 L${tipUx + 15},91 L${tipUx},94Z`);
  forkTopTipL.setAttribute('d', `M${tipUx},186 L${tipUx + 15},189 L${tipUx + 15},197 L${tipUx},200Z`);

  // 导轨发光
  const railGlow = document.getElementById('rail-glow');
  const glowOpacity = isForkMoving ? (0.5 + 0.3 * Math.sin(state.time * 8)) : (ext > 0 ? 0.15 : 0);
  railGlow.setAttribute('opacity', String(glowOpacity));
  if (isForkMoving) {
    const color = state.forkDirection > 0 ? '#ff6b2b' : '#00ff88';
    railGlow.querySelectorAll('rect').forEach(r => {
      r.setAttribute('fill', `url(#rail-glow-grad)`);
    });
    // 更新渐变颜色
    const gradStops = document.getElementById('rail-glow-grad').querySelectorAll('stop');
    gradStops[1].setAttribute('stop-color', color);
    gradStops[2].setAttribute('stop-color', color);
  }

  // 推杆指示
  const actuatorRod = document.getElementById('fork-actuator-rod');
  const rodExt = Math.min(25, ext * 0.3);
  actuatorRod.setAttribute('x', String(740 + rodExt));
  actuatorRod.setAttribute('width', String(30 - rodExt * 0.5));
  const actuatorGroup = document.getElementById('fork-actuator');
  actuatorGroup.setAttribute('opacity', String(isForkMoving ? 0.9 : 0.4));

  // 伸缩位移标注
  const forkDim = document.getElementById('fork-dimension');
  const dimEnd = document.getElementById('fork-dim-end');
  const dimText = document.getElementById('fork-dim-text');
  const showDim = ext > 2 || isForkMoving;
  forkDim.setAttribute('opacity', String(showDim ? 0.9 : 0));
  if (showDim) {
    const startX = 690;
    const endX = 690 + ext;
    dimEnd.setAttribute('x1', String(endX));
    dimEnd.setAttribute('x2', String(endX));
    // 标注水平线
    const dimLine = forkDim.querySelector('line:nth-child(3)');
    if (dimLine) {
      dimLine.setAttribute('x1', String(startX));
      dimLine.setAttribute('x2', String(endX));
    }
    dimText.setAttribute('x', String((startX + endX) / 2));
    dimText.textContent = Math.round(ext * FORK_SCALE) + 'mm';
    // 颜色
    const dimColor = state.forkDirection > 0 ? '#ff6b2b' : (state.forkDirection < 0 ? '#00ff88' : '#ff6b2b');
    dimText.setAttribute('fill', dimColor);
  }

  // 货叉标签 - 随伸缩移动
  const forkLabel = document.getElementById('fork-label-text');
  forkLabel.setAttribute('x', String(790 + ext * 0.5));
  if (isForkMoving) {
    forkLabel.setAttribute('fill', state.forkDirection > 0 ? '#ff6b2b' : '#00ff88');
    forkLabel.textContent = state.forkDirection > 0 ? 'EXTENDING...' : 'RETRACTING...';
  } else if (ext > 0) {
    forkLabel.setAttribute('fill', '#2a4060');
    forkLabel.textContent = 'CARBON FORK';
  } else {
    forkLabel.setAttribute('fill', '#1e3050');
    forkLabel.textContent = 'CARBON FORK';
  }

  // 伸缩过程中叉尖闪烁
  if (isForkMoving) {
    const blink = 0.5 + 0.5 * Math.sin(state.time * 12);
    forkUpper.querySelector('path').setAttribute('fill', `rgba(255,107,43,${blink * 0.3})`);
    forkLower.querySelector('path').setAttribute('fill', `rgba(255,107,43,${blink * 0.3})`);
    forkUpper.querySelector('path').setAttribute('stroke', state.forkDirection > 0 ? '#ff6b2b' : '#00ff88');
    forkLower.querySelector('path').setAttribute('stroke', state.forkDirection > 0 ? '#ff6b2b' : '#00ff88');
  } else {
    forkUpper.querySelector('path').setAttribute('fill', '#14203a');
    forkLower.querySelector('path').setAttribute('fill', '#14203a');
    forkUpper.querySelector('path').setAttribute('stroke', '#1e3050');
    forkLower.querySelector('path').setAttribute('stroke', '#1e3050');
  }

  // ---- 参数更新 ----
  document.getElementById('svg-speed').textContent = state.speed.toFixed(1);
  document.getElementById('svg-accel').textContent = Math.abs(state.acceleration).toFixed(1);
  document.getElementById('svg-torque').textContent = Math.abs(Math.round(state.torque));
  document.getElementById('svg-regen').textContent = Math.round(state.regenPower);
  document.getElementById('svg-temp').textContent = Math.round(state.motorTemp);
  document.getElementById('svg-fork').textContent = Math.round(ext * FORK_SCALE);

  // 温度颜色
  const tempEl = document.getElementById('svg-temp');
  if (state.motorTemp > 100) tempEl.setAttribute('fill', '#ff3d5a');
  else if (state.motorTemp > 70) tempEl.setAttribute('fill', '#ff6b2b');
  else if (state.motorTemp > 45) tempEl.setAttribute('fill', '#ffd600');
  else tempEl.setAttribute('fill', '#ffd600');

  // 加速度颜色
  const accelEl = document.getElementById('svg-accel');
  accelEl.setAttribute('fill', state.acceleration >= 0 ? '#00d4ff' : '#ff6b2b');

  // 力矩颜色
  const torqueEl = document.getElementById('svg-torque');
  torqueEl.setAttribute('fill', state.torque >= 0 ? '#00d4ff' : '#00ff88');

  // 货叉状态值
  document.getElementById('fork-status-val').textContent = Math.round(ext * FORK_SCALE) + ' mm';
  const forkStatusColor = isForkMoving ? (state.forkDirection > 0 ? '#ff6b2b' : '#00ff88') : (ext > 0 ? '#ff6b2b' : '#3e5278');
  document.getElementById('fork-status-val').setAttribute('fill', forkStatusColor);
}

// ===== 动画循环 =====
let lastTime = 0;
function animate(timestamp) {
  const dt = Math.min(0.05, (timestamp - lastTime) / 1000);
  lastTime = timestamp;
  updateState(dt);
  render();
  requestAnimationFrame(animate);
}

// ===== 事件绑定 =====
document.querySelectorAll('.phase-btn').forEach(btn => {
  btn.addEventListener('click', () => setPhase(btn.dataset.phase));
});

document.getElementById('speed-slider').addEventListener('input', e => {
  state.targetSpeed = parseFloat(e.target.value);
  document.getElementById('speed-val').textContent = state.targetSpeed.toFixed(1) + ' m/s';
});

document.getElementById('friction-slider').addEventListener('input', e => {
  state.friction = parseFloat(e.target.value);
  document.getElementById('friction-val').textContent = state.friction.toFixed(1);
});

// 货叉伸出按钮
document.getElementById('fork-extend-btn').addEventListener('click', extendFork);
// 货叉缩回按钮
document.getElementById('fork-retract-btn').addEventListener('click', retractFork);
// 货叉滑块
document.getElementById('fork-slider').addEventListener('input', e => {
  const val = parseFloat(e.target.value);
  setForkTarget(val);
  document.getElementById('fork-val').textContent = Math.round(val * FORK_SCALE) + ' mm';
});

// ===== 启动 =====
initDynamicElements();
setPhase('standby');
requestAnimationFrame(animate);
</script>
</body>
</html>

新增货叉伸缩动画说明

在原有轮毂直驱系统动画基础上,完整实现了碳纤维层叠板货叉的伸缩动画系统:

  1. 主视图伸缩:货叉上下两层碳纤维板沿导轨平滑滑出/缩回,最大行程 150mm。导轨在伸缩过程中发出橙色(伸出)或绿色(缩回)脉冲辉光,叉尖在运动时闪烁提示方向。

  2. 位移标注:伸缩过程中自动显示实时位移尺寸线(如 "85mm"),颜色随伸缩方向切换——伸出为橙色、缩回为绿色。

  3. 推杆驱动可视化:微型电动推杆随伸缩量联动伸缩,运动时高亮显示。

  4. 俯视图联动:右侧俯视图中货叉同步伸缩,叉尖位置实时跟随。

  5. 三种控制方式

    • 按钮:一键伸出/缩回到极限位置(带匀速动画过渡)
    • 滑块:拖动精确控制任意伸缩量(0-150mm)
    • 状态面板:左上角实时显示当前伸缩量
  6. 底部参数栏:新增 "FORK" 参数位,以 Orbitron 字体实时显示伸缩毫米数。

轮子太大了 缩小直径为160mm
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮毂直驱系统 · IFR 最终理想解原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --bg:#050a14;--bg2:#0a1628;--cyan:#00d4ff;--cyan-dim:rgba(0,212,255,0.12);
  --orange:#ff6b2b;--green:#00ff88;--yellow:#ffd600;--red:#ff3d5a;
  --white:#dce4f0;--muted:#3e5278;--struct:#14203a;--carbon:#0e1830;
  --border:#1a2a48;
}
body{background:var(--bg);color:var(--white);font-family:'JetBrains Mono',monospace;overflow:hidden;height:100vh;display:flex;flex-direction:column;user-select:none}
header{padding:12px 28px;display:flex;align-items:baseline;gap:18px;border-bottom:1px solid var(--border);background:linear-gradient(180deg,rgba(10,22,40,0.95),transparent);position:relative;z-index:2}
header h1{font-family:'Orbitron',sans-serif;font-size:18px;font-weight:700;letter-spacing:2px;color:var(--cyan);text-shadow:0 0 20px rgba(0,212,255,0.3)}
header p{font-size:11px;color:var(--muted);letter-spacing:1px}
#svg-wrap{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden;position:relative}
#main-svg{width:100%;height:100%;max-height:calc(100vh - 120px)}
#controls{padding:10px 24px;display:flex;align-items:center;gap:14px;border-top:1px solid var(--border);background:linear-gradient(0deg,rgba(10,22,40,0.98),rgba(10,22,40,0.85));flex-wrap:wrap;justify-content:center}
.ctrl-section{display:flex;align-items:center;gap:10px}
.ctrl-label{font-size:9px;color:#2a4060;font-family:'Orbitron',sans-serif;letter-spacing:1px;text-transform:uppercase;writing-mode:vertical-lr;text-orientation:mixed}
.phase-btn{padding:7px 16px;border:1px solid var(--border);border-radius:6px;background:var(--carbon);color:var(--muted);font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer;transition:all .25s;letter-spacing:0.5px;display:flex;align-items:center;gap:6px}
.phase-btn:hover{border-color:var(--cyan);color:var(--white)}
.phase-btn.active{border-color:var(--cyan);color:var(--cyan);background:var(--cyan-dim);box-shadow:0 0 12px rgba(0,212,255,0.15)}
.phase-btn i{font-size:10px}
.sep{width:1px;height:28px;background:var(--border);margin:0 6px;flex-shrink:0}
.slider-group{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--muted)}
.slider-group label{white-space:nowrap}
.slider-group input[type=range]{-webkit-appearance:none;width:100px;height:4px;background:var(--border);border-radius:2px;outline:none}
.slider-group input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--cyan);border-radius:50%;cursor:pointer;box-shadow:0 0 6px rgba(0,212,255,0.4)}
.slider-val{color:var(--cyan);min-width:36px;text-align:right;font-weight:700;font-size:11px}
.fork-btn{padding:7px 18px;border:1px solid var(--border);border-radius:6px;background:var(--carbon);color:var(--muted);font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer;transition:all .25s;display:flex;align-items:center;gap:6px}
.fork-btn:hover{border-color:var(--orange);color:var(--white)}
.fork-btn.extending{border-color:var(--orange);color:var(--orange);background:rgba(255,107,43,0.1);box-shadow:0 0 12px rgba(255,107,43,0.15)}
.fork-btn.retracting{border-color:var(--green);color:var(--green);background:rgba(0,255,136,0.08)}
</style>
</head>
<body>
<header>
  <h1>HUB-DIRECT DRIVE</h1>
  <p>IFR 最终理想解 · 零传动链原理动画 · 轮径160mm</p>
</header>
<div id="svg-wrap">
<svg id="main-svg" viewBox="0 0 1400 850" preserveAspectRatio="xMidYMid meet">
<defs>
  <pattern id="carbon" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
    <rect width="8" height="8" fill="#0e1830"/><rect width="4" height="8" fill="#13203e"/>
  </pattern>
  <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
    <path d="M40 0L0 0 0 40" fill="none" stroke="#0c1828" stroke-width="0.5"/>
  </pattern>
  <filter id="glow-cyan" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="b"/>
    <feFlood flood-color="#00d4ff" flood-opacity="0.5"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="glow-green" x="-50%" y="-50%" width="200%" height="200%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5" result="b"/>
    <feFlood flood-color="#00ff88" flood-opacity="0.45"/><feComposite in2="b" operator="in" result="g"/>
    <feMerge><feMergeNode in="g"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <filter id="softglow" x="-30%" y="-30%" width="160%" height="160%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="3" result="b"/>
    <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
  </filter>
  <marker id="arrow-cyan" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00d4ff"/></marker>
  <marker id="arrow-orange" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#ff6b2b"/></marker>
  <marker id="arrow-green" viewBox="0 0 10 6" refX="10" refY="3" markerWidth="10" markerHeight="6" orient="auto"><path d="M0,0 L10,3 L0,6Z" fill="#00ff88"/></marker>
  <radialGradient id="tire-grad" cx="50%" cy="45%"><stop offset="0%" stop-color="#1a1a2a"/><stop offset="80%" stop-color="#0a0a14"/><stop offset="100%" stop-color="#050508"/></radialGradient>
  <linearGradient id="rail-grad" x1="0" y1="0" x2="1" y2="0">
    <stop offset="0%" stop-color="#1e3050"/><stop offset="50%" stop-color="#2a4568"/><stop offset="100%" stop-color="#1e3050"/>
  </linearGradient>
  <linearGradient id="rail-glow-grad" x1="0" y1="0" x2="1" y2="0">
    <stop offset="0%" stop-color="#ff6b2b" stop-opacity="0"/><stop offset="20%" stop-color="#ff6b2b" stop-opacity="0.6"/><stop offset="80%" stop-color="#ff6b2b" stop-opacity="0.6"/><stop offset="100%" stop-color="#ff6b2b" stop-opacity="0"/>
  </linearGradient>
</defs>

<rect width="1400" height="850" fill="url(#grid)"/>
<ellipse cx="500" cy="700" rx="500" ry="120" fill="rgba(0,212,255,0.02)"/>

<!-- ===== 轨道 ===== -->
<g id="track-group">
  <line x1="0" y1="670" x2="920" y2="670" stroke="#1a2a48" stroke-width="3"/>
  <line x1="0" y1="676" x2="920" y2="676" stroke="#1a2a48" stroke-width="1.5"/>
  <g id="track-ties"></g>
</g>

<!-- ===== 速度线 ===== -->
<g id="speed-lines"></g>

<!-- ===== 车辆主体 ===== -->
<!--
  轮径160mm → SVG半径32
  后轮中心: (390, 638)  底部y=670
  前轮中心: (670, 644)  底部y=670
  底盘: y=580~615
-->
<g id="vehicle-group">
  <!-- 碳纤维底盘桁架 -->
  <g id="chassis" stroke="#1e3050" stroke-width="2.5" fill="none">
    <line x1="310" y1="580" x2="690" y2="580" stroke="#2a4060" stroke-width="3.5"/>
    <line x1="290" y1="615" x2="710" y2="615" stroke="#2a4060" stroke-width="3.5"/>
    <line x1="350" y1="580" x2="345" y2="615"/>
    <line x1="430" y1="580" x2="425" y2="615"/>
    <line x1="510" y1="580" x2="510" y2="615"/>
    <line x1="590" y1="580" x2="595" y2="615"/>
    <line x1="670" y1="580" x2="675" y2="615"/>
    <line x1="345" y1="615" x2="430" y2="580" stroke="#1e3050" stroke-width="1.8"/>
    <line x1="425" y1="615" x2="510" y2="580" stroke="#1e3050" stroke-width="1.8"/>
    <line x1="510" y1="615" x2="590" y2="580" stroke="#1e3050" stroke-width="1.8"/>
    <line x1="595" y1="615" x2="670" y2="580" stroke="#1e3050" stroke-width="1.8"/>
    <line x1="350" y1="580" x2="425" y2="615" stroke="#1e3050" stroke-width="1.5" stroke-dasharray="4,4"/>
    <line x1="430" y1="580" x2="510" y2="615" stroke="#1e3050" stroke-width="1.5" stroke-dasharray="4,4"/>
    <line x1="510" y1="580" x2="595" y2="615" stroke="#1e3050" stroke-width="1.5" stroke-dasharray="4,4"/>
    <line x1="590" y1="580" x2="675" y2="615" stroke="#1e3050" stroke-width="1.5" stroke-dasharray="4,4"/>
    <g fill="#2a4a70">
      <circle cx="350" cy="580" r="3.5"/><circle cx="430" cy="580" r="3.5"/>
      <circle cx="510" cy="580" r="3.5"/><circle cx="590" cy="580" r="3.5"/>
      <circle cx="670" cy="580" r="3.5"/><circle cx="345" cy="615" r="3.5"/>
      <circle cx="425" cy="615" r="3.5"/><circle cx="510" cy="615" r="3.5"/>
      <circle cx="595" cy="615" r="3.5"/><circle cx="675" cy="615" r="3.5"/>
    </g>
  </g>
  <rect x="305" y="583" width="390" height="29" fill="url(#carbon)" opacity="0.4" rx="2"/>

  <!-- 控制器盒 -->
  <rect x="460" y="586" width="80" height="24" rx="3" fill="#0c1828" stroke="#2a4060" stroke-width="1.2"/>
  <text x="500" y="602" text-anchor="middle" fill="#3e5278" font-size="7" font-family="JetBrains Mono">CTRL</text>
  <rect id="ctrl-led" x="464" y="590" width="5" height="5" rx="2.5" fill="#1a2a40"/>

  <!-- 电池 -->
  <rect x="360" y="588" width="60" height="20" rx="2" fill="#0c1424" stroke="#1e3050" stroke-width="1"/>
  <text x="390" y="602" text-anchor="middle" fill="#2a4060" font-size="6" font-family="JetBrains Mono">BAT 48V</text>
  <rect id="bat-bar" x="365" y="591" width="3" height="14" rx="1" fill="#1a3a20"/>

  <!-- 悬挂连接:底盘→后轮轴 -->
  <g stroke="#1e3050" stroke-width="2" fill="none">
    <line x1="390" y1="615" x2="390" y2="628"/>
    <line x1="385" y1="615" x2="378" y2="630"/>
    <line x1="395" y1="615" x2="402" y2="630"/>
  </g>
  <!-- 悬挂连接:底盘→前轮轴 -->
  <g stroke="#141e30" stroke-width="1.5" fill="none">
    <line x1="670" y1="615" x2="670" y2="630"/>
    <line x1="665" y1="615" x2="660" y2="630"/>
    <line x1="675" y1="615" x2="680" y2="630"/>
  </g>

  <!-- ===== 货叉系统 ===== -->
  <g id="fork-system">
    <g id="fork-rails">
      <rect x="690" y="583" width="180" height="3" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="690" y="595" width="180" height="3" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="690" y="610" width="180" height="3" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="690" y="622" width="180" height="3" rx="1" fill="url(#rail-grad)" opacity="0.6"/>
      <rect x="866" y="580" width="5" height="20" rx="2" fill="#1a2a44"/>
      <rect x="866" y="607" width="5" height="20" rx="2" fill="#1a2a44"/>
    </g>
    <g id="rail-glow" opacity="0">
      <rect x="690" y="581" width="180" height="20" rx="1" fill="url(#rail-glow-grad)" opacity="0.15"/>
      <rect x="690" y="607" width="180" height="20" rx="1" fill="url(#rail-glow-grad)" opacity="0.15"/>
    </g>
    <!-- 伸缩货叉 - 上层 -->
    <g id="fork-upper">
      <rect x="690" y="586" width="160" height="8" rx="1" fill="url(#carbon)" stroke="#1e3050" stroke-width="1"/>
      <line x1="700" y1="588" x2="840" y2="588" stroke="#1a2a44" stroke-width="0.4"/>
      <line x1="700" y1="592" x2="840" y2="592" stroke="#1a2a44" stroke-width="0.4"/>
      <path d="M850,586 L865,588 L865,592 L850,594Z" fill="#14203a" stroke="#1e3050" stroke-width="0.7"/>
    </g>
    <!-- 伸缩货叉 - 下层 -->
    <g id="fork-lower">
      <rect x="690" y="613" width="160" height="8" rx="1" fill="url(#carbon)" stroke="#1e3050" stroke-width="1"/>
      <line x1="700" y1="615" x2="840" y2="615" stroke="#1a2a44" stroke-width="0.4"/>
      <line x1="700" y1="619" x2="840" y2="619" stroke="#1a2a44" stroke-width="0.4"/>
      <path d="M850,613 L865,615 L865,619 L850,621Z" fill="#14203a" stroke="#1e3050" stroke-width="0.7"/>
    </g>
    <!-- 竖向连接件 -->
    <g id="fork-verticals">
      <line x1="700" y1="594" x2="700" y2="613" stroke="#1e3050" stroke-width="2"/>
      <line x1="730" y1="594" x2="730" y2="613" stroke="#1e3050" stroke-width="1.2"/>
    </g>
    <!-- 伸缩位移标注 -->
    <g id="fork-dimension" opacity="0">
      <line id="fork-dim-start" x1="690" y1="575" x2="690" y2="570" stroke="#ff6b2b" stroke-width="0.7"/>
      <line id="fork-dim-end" x1="690" y1="575" x2="690" y2="570" stroke="#ff6b2b" stroke-width="0.7"/>
      <line id="fork-dim-line" x1="690" y1="572" x2="690" y2="572" stroke="#ff6b2b" stroke-width="0.7" marker-end="url(#arrow-orange)" marker-start="url(#arrow-orange)"/>
      <text id="fork-dim-text" x="690" y="568" text-anchor="middle" fill="#ff6b2b" font-size="8" font-family="Orbitron" font-weight="700">0mm</text>
    </g>
    <!-- 驱动推杆 -->
    <g id="fork-actuator" opacity="0.4">
      <rect x="692" y="600" width="40" height="4" rx="1.5" fill="#0e1830" stroke="#1e3050" stroke-width="0.7"/>
      <rect id="fork-actuator-rod" x="730" y="601" width="20" height="2" rx="1" fill="#2a4060"/>
    </g>
    <text id="fork-label-text" x="770" y="606" text-anchor="middle" fill="#1e3050" font-size="6" font-family="JetBrains Mono" letter-spacing="1">CARBON FORK</text>
  </g>

  <!-- ===== 后轮:轮毂电机 (r=32, φ160mm) ===== -->
  <g id="hub-motor-group">
    <circle cx="390" cy="638" r="32" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="1.5"/>
    <circle cx="390" cy="638" r="26" fill="none" stroke="#2a3a5a" stroke-width="2"/>
    <circle cx="390" cy="638" r="22" fill="none" stroke="#1e3050" stroke-width="0.8"/>
    <g id="rotor-magnets"></g>
    <circle cx="390" cy="638" r="17" fill="none" stroke="#0a1428" stroke-width="0.4" stroke-dasharray="1.5,1.5"/>
    <circle cx="390" cy="638" r="14" fill="#0c1424" stroke="#1a2a44" stroke-width="0.8"/>
    <g id="stator-coils"></g>
    <circle cx="390" cy="638" r="5" fill="#14203a" stroke="#2a4060" stroke-width="1"/>
    <circle cx="390" cy="638" r="2" fill="#2a4060"/>
    <g stroke="#1e3050" stroke-width="1.2" id="spokes-rear">
      <line x1="390" y1="623" x2="390" y2="612"/>
      <line x1="390" y1="653" x2="390" y2="664"/>
      <line x1="375" y1="638" x2="364" y2="638"/>
      <line x1="405" y1="638" x2="416" y2="638"/>
      <line x1="379" y1="627" x2="371" y2="619"/>
      <line x1="401" y1="649" x2="409" y2="657"/>
      <line x1="379" y1="649" x2="371" y2="657"/>
      <line x1="401" y1="627" x2="409" y2="619"/>
    </g>
    <text x="390" y="600" text-anchor="middle" fill="#2a4060" font-size="6" font-family="JetBrains Mono" letter-spacing="0.5">HUB MOTOR</text>
    <text x="390" y="682" text-anchor="middle" fill="#1e3050" font-size="6" font-family="JetBrains Mono">≤4kg · φ160</text>
  </g>

  <!-- ===== 前轮:从动轮 (r=26) ===== -->
  <g id="passive-wheel-group">
    <circle cx="670" cy="644" r="26" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="1.2"/>
    <circle cx="670" cy="644" r="21" fill="none" stroke="#1a2a40" stroke-width="1.2"/>
    <circle cx="670" cy="644" r="4" fill="#0e1830" stroke="#1e3050" stroke-width="0.8"/>
    <g stroke="#141e30" stroke-width="0.8" id="spokes-front">
      <line x1="670" y1="624" x2="670" y2="618"/>
      <line x1="670" y1="664" x2="670" y2="670"/>
      <line x1="650" y1="644" x2="644" y2="644"/>
      <line x1="690" y1="644" x2="696" y2="644"/>
    </g>
    <text x="670" y="682" text-anchor="middle" fill="#141e30" font-size="6" font-family="JetBrains Mono">PASSIVE</text>
  </g>

  <!-- "零传动链"标注 -->
  <g id="no-shaft-label" opacity="0.6">
    <line x1="420" y1="644" x2="640" y2="644" stroke="#1e3050" stroke-width="0.8" stroke-dasharray="5,3"/>
    <text x="530" y="640" text-anchor="middle" fill="#2a4060" font-size="7" font-family="Orbitron" letter-spacing="1">ZERO DRIVE SHAFT</text>
    <circle cx="530" cy="650" r="6" fill="none" stroke="#2a4060" stroke-width="0.8"/>
    <line x1="525" y1="655" x2="535" y2="645" stroke="#2a4060" stroke-width="0.8"/>
  </g>
</g>

<!-- ===== 电力流向线 ===== -->
<g id="power-flow-group">
  <path id="power-path-bc" d="M420,598 L460,598" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="4,4" opacity="0.5"/>
  <path id="power-path-cm1" d="M460,590 Q440,570 390,570 Q355,570 355,610 Q355,628 370,633" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="4,6" opacity="0.5"/>
  <path id="power-path-cm2" d="M460,605 Q430,625 405,633" fill="none" stroke="#2a4060" stroke-width="1" stroke-dasharray="3,5" opacity="0.3"/>
</g>

<!-- ===== 接触力箭头 ===== -->
<g id="force-arrows">
  <g id="drive-force" opacity="0">
    <line x1="352" y1="670" x2="310" y2="670" stroke="#00d4ff" stroke-width="2.5" marker-end="url(#arrow-cyan)"/>
    <text x="330" y="684" text-anchor="middle" fill="#00d4ff" font-size="8" font-family="Orbitron">F</text>
  </g>
  <g id="regen-force" opacity="0">
    <line x1="310" y1="670" x2="352" y2="670" stroke="#00ff88" stroke-width="2.5" marker-end="url(#arrow-green)"/>
    <text x="330" y="684" text-anchor="middle" fill="#00ff88" font-size="8" font-family="Orbitron">REGEN</text>
  </g>
</g>

<!-- ===== 阶段指示 ===== -->
<g id="phase-indicator" transform="translate(50,40)">
  <rect x="0" y="0" width="200" height="44" rx="6" fill="rgba(10,22,40,0.85)" stroke="#1a2a48" stroke-width="1"/>
  <text x="100" y="18" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono" letter-spacing="1">PHASE</text>
  <text id="phase-name" x="100" y="35" text-anchor="middle" fill="#00d4ff" font-size="14" font-family="Orbitron" font-weight="700">STANDBY</text>
</g>

<!-- ===== 货叉伸缩状态 ===== -->
<g id="fork-status" transform="translate(50,92)">
  <rect x="0" y="0" width="200" height="38" rx="6" fill="rgba(10,22,40,0.85)" stroke="#1a2a48" stroke-width="1"/>
  <text x="100" y="16" text-anchor="middle" fill="#3e5278" font-size="8" font-family="JetBrains Mono" letter-spacing="1">FORK EXTENSION</text>
  <text id="fork-status-val" x="100" y="32" text-anchor="middle" fill="#ff6b2b" font-size="13" font-family="Orbitron" font-weight="700">0 mm</text>
</g>

<!-- ===== 右侧面板:俯视图 ===== -->
<g transform="translate(940,20)">
  <rect x="0" y="0" width="440" height="260" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">TOP VIEW · ELECTRONIC DIFFERENTIAL</text>
  <rect x="130" y="50" width="180" height="180" rx="6" fill="url(#carbon)" stroke="#1e3050" stroke-width="1.5" opacity="0.6"/>
  <g id="fork-top-group">
    <rect id="fork-top-upper" x="310" y="80" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <rect id="fork-top-lower" x="310" y="186" width="100" height="14" rx="2" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <path id="fork-top-tip-u" d="M410,80 L425,83 L425,91 L410,94Z" fill="#14203a" stroke="#1e3050" stroke-width="0.6"/>
    <path id="fork-top-tip-l" d="M410,186 L425,189 L425,197 L410,200Z" fill="#14203a" stroke="#1e3050" stroke-width="0.6"/>
  </g>
  <rect x="190" y="120" width="60" height="40" rx="3" fill="#0c1828" stroke="#2a4060" stroke-width="1"/>
  <text x="220" y="144" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">ECU</text>
  <g id="top-left-motor">
    <circle cx="130" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="130" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="130" cy="140" r="5" fill="#14203a"/>
    <text x="100" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">L-HUB</text>
  </g>
  <g id="top-right-motor">
    <circle cx="310" cy="140" r="22" fill="#0a1428" stroke="#1a2a44" stroke-width="1.5"/>
    <circle cx="310" cy="140" r="14" fill="#0e1830" stroke="#1e3050" stroke-width="1"/>
    <circle cx="310" cy="140" r="5" fill="#14203a"/>
    <text x="340" y="175" text-anchor="middle" fill="#1e3050" font-size="7" font-family="JetBrains Mono">R-HUB</text>
  </g>
  <circle cx="170" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="58" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="170" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <circle cx="270" cy="222" r="12" fill="#0a0e18" stroke="#141e30" stroke-width="1"/>
  <path id="diff-line-l" d="M190,140 L155,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <path id="diff-line-r" d="M250,140 L285,140" fill="none" stroke="#2a4060" stroke-width="1.5" stroke-dasharray="3,3"/>
  <g id="sync-indicator" opacity="0">
    <text x="220" y="200" text-anchor="middle" fill="#00d4ff" font-size="8" font-family="Orbitron" letter-spacing="1">SYNC</text>
    <rect x="185" y="205" width="70" height="3" rx="1.5" fill="#0a1428"/>
    <rect id="sync-bar" x="185" y="205" width="70" height="3" rx="1.5" fill="#00d4ff" opacity="0.6"/>
  </g>
  <g id="direction-arrow" opacity="0">
    <line x1="220" y1="30" x2="220" y2="10" stroke="#00d4ff" stroke-width="2" marker-end="url(#arrow-cyan)"/>
  </g>
</g>

<!-- ===== 右侧面板:轮毂电机剖面 ===== -->
<g transform="translate(940,300)">
  <rect x="0" y="0" width="440" height="280" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">HUB MOTOR CROSS-SECTION · φ160mm</text>
  <g transform="translate(160,155)">
    <!-- 160mm直径 → 剖面半径80 -->
    <circle r="80" fill="url(#tire-grad)" stroke="#1a1a2a" stroke-width="1.5"/>
    <circle r="68" fill="none" stroke="#2a3a5a" stroke-width="1.5"/>
    <circle r="60" fill="none" stroke="#1e3050" stroke-width="4" id="rotor-ring"/>
    <g id="detail-magnets"></g>
    <circle r="48" fill="none" stroke="rgba(0,212,255,0.1)" stroke-width="1.5" stroke-dasharray="2,3"/>
    <circle r="42" fill="#0c1424" stroke="#1a2a44" stroke-width="1"/>
    <g id="detail-stator"></g>
    <circle r="11" fill="#14203a" stroke="#2a4060" stroke-width="1.5"/>
    <circle r="4" fill="#1e3050"/>
    <g id="torque-arc" opacity="0">
      <path d="M-32,-72 A78,78 0 0,1 32,-72" fill="none" stroke="#00d4ff" stroke-width="2" marker-end="url(#arrow-cyan)"/>
      <text x="0" y="-78" text-anchor="middle" fill="#00d4ff" font-size="9" font-family="Orbitron" font-weight="700">TORQUE</text>
    </g>
    <g id="regen-arc" opacity="0">
      <path d="M32,-72 A78,78 0 0,1 -32,-72" fill="none" stroke="#00ff88" stroke-width="2" marker-end="url(#arrow-green)"/>
      <text x="0" y="-78" text-anchor="middle" fill="#00ff88" font-size="9" font-family="Orbitron" font-weight="700">REGEN</text>
    </g>
    <!-- 直径标注 -->
    <g opacity="0.4">
      <line x1="-80" y1="0" x2="80" y2="0" stroke="#2a4060" stroke-width="0.5" stroke-dasharray="3,3"/>
      <text x="0" y="-4" text-anchor="middle" fill="#2a4060" font-size="7" font-family="JetBrains Mono">φ160mm</text>
    </g>
  </g>
  <g transform="translate(300,55)" fill="#3e5278" font-size="7" font-family="JetBrains Mono">
    <text y="0" fill="#2a4060" font-size="7">STRUCTURE</text>
    <circle cx="-7" cy="14" r="2.5" fill="#1a1a2a"/><text x="2" y="17">Tire</text>
    <circle cx="-7" cy="28" r="2.5" fill="#2a3a5a"/><text x="2" y="31">Rim</text>
    <circle cx="-7" cy="42" r="2.5" fill="#ff3d5a" opacity="0.6"/><text x="2" y="45">Rotor Mag</text>
    <circle cx="-7" cy="56" r="2.5" fill="#00d4ff" opacity="0.6"/><text x="2" y="59">Stator Coil</text>
    <circle cx="-7" cy="70" r="2.5" fill="#14203a"/><text x="2" y="73">Axle</text>
    <!-- 160mm参数 -->
    <text y="95" fill="#1e3050" font-size="6" letter-spacing="0.5">Wheel: φ160mm</text>
    <text y="108" fill="#1e3050" font-size="6" letter-spacing="0.5">Motor: ≤4kg</text>
  </g>
</g>

<!-- ===== 右侧面板:IFR 原则 ===== -->
<g transform="translate(940,600)">
  <rect x="0" y="0" width="440" height="230" rx="8" fill="rgba(8,16,32,0.9)" stroke="#1a2a48" stroke-width="1"/>
  <text x="220" y="22" text-anchor="middle" fill="#3e5278" font-size="9" font-family="Orbitron" letter-spacing="2">IFR · IDEAL FINAL RESULT</text>
  <g transform="translate(24,40)" font-family="JetBrains Mono" font-size="10">
    <text fill="#00d4ff" font-size="11" font-weight="700" font-family="Orbitron">Wheel = Motor</text>
    <text y="20" fill="#5a7aaa">轮即电机,动力直达轮缘</text>
    <text y="40" fill="#5a7aaa">零传动链 · 零机械间隙 · 零中间损耗</text>
    <line x1="0" y1="52" x2="392" y2="52" stroke="#1a2a48" stroke-width="0.5"/>
    <text y="70" fill="#2a4060" font-size="8" letter-spacing="1">WEIGHT REALLOCATION</text>
    <g transform="translate(0,82)">
      <rect width="120" height="24" rx="4" fill="rgba(255,107,43,0.1)" stroke="#ff6b2b" stroke-width="0.8"/>
      <text x="60" y="16" text-anchor="middle" fill="#ff6b2b" font-size="9">传动系统 15kg</text>
      <text x="145" y="16" fill="#3e5278" font-size="14">→</text>
      <rect x="170" width="120" height="24" rx="4" fill="rgba(0,255,136,0.08)" stroke="#00ff88" stroke-width="0.8"/>
      <text x="230" y="16" text-anchor="middle" fill="#00ff88" font-size="9">结构强度 +15kg</text>
    </g>
    <line x1="0" y1="116" x2="392" y2="116" stroke="#1a2a48" stroke-width="0.5"/>
    <text y="134" fill="#2a4060" font-size="8" letter-spacing="1">BOUNDARY / RISK</text>
    <text y="152" fill="#5a3a3a" font-size="9">⚠ 长时间极限制动 → 磁钢退磁风险</text>
    <text y="168" fill="#5a3a3a" font-size="9">⚠ 5m/s 轨道接缝冲击 → 轴承疲劳</text>
    <text y="184" fill="#5a3a3a" font-size="9">⚠ 粉尘/湿滑轨道 → 打滑失控</text>
  </g>
</g>

<!-- ===== 底部参数条 ===== -->
<g id="svg-params" transform="translate(50,790)" font-family="Orbitron" font-size="10">
  <g transform="translate(0,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">SPEED</text>
    <text id="svg-speed" y="18" fill="#00d4ff" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s</text>
  </g>
  <g transform="translate(120,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">ACCEL</text>
    <text id="svg-accel" y="18" fill="#ff6b2b" font-size="16" font-weight="700">0.0</text>
    <text x="52" y="18" fill="#3e5278" font-size="8">m/s²</text>
  </g>
  <g transform="translate(240,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">TORQUE</text>
    <text id="svg-torque" y="18" fill="#00d4ff" font-size="16" font-weight="700">0</text>
    <text x="38" y="18" fill="#3e5278" font-size="8">Nm</text>
  </g>
  <g transform="translate(350,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">REGEN</text>
    <text id="svg-regen" y="18" fill="#00ff88" font-size="16" font-weight="700">0</text>
    <text x="44" y="18" fill="#3e5278" font-size="8">W</text>
  </g>
  <g transform="translate(460,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">MOTOR TEMP</text>
    <text id="svg-temp" y="18" fill="#ffd600" font-size="16" font-weight="700">25</text>
    <text x="42" y="18" fill="#3e5278" font-size="8">°C</text>
  </g>
  <g transform="translate(590,0)">
    <text fill="#3e5278" font-size="8" letter-spacing="1">FORK</text>
    <text id="svg-fork" y="18" fill="#ff6b2b" font-size="16" font-weight="700">0</text>
    <text x="38" y="18" fill="#3e5278" font-size="8">mm</text>
  </g>
</g>

</svg>
</div>

<div id="controls">
  <div class="ctrl-section">
    <span class="ctrl-label">驱动</span>
    <button class="phase-btn active" data-phase="standby"><i class="fas fa-power-off"></i>待机</button>
    <button class="phase-btn" data-phase="accelerate"><i class="fas fa-bolt"></i>起步加速</button>
    <button class="phase-btn" data-phase="cruise"><i class="fas fa-gauge-high"></i>稳速行驶</button>
    <button class="phase-btn" data-phase="brake"><i class="fas fa-rotate-left"></i>再生制动</button>
    <button class="phase-btn" data-phase="stop"><i class="fas fa-stop"></i>抱刹停止</button>
  </div>
  <div class="sep"></div>
  <div class="ctrl-section">
    <span class="ctrl-label">货叉</span>
    <button class="fork-btn" id="fork-extend-btn"><i class="fas fa-arrows-left-right"></i>伸出货叉</button>
    <button class="fork-btn" id="fork-retract-btn"><i class="fas fa-compress"></i>缩回货叉</button>
    <div class="slider-group">
      <label>伸缩量</label>
      <input type="range" id="fork-slider" min="0" max="150" step="5" value="0"/>
      <span class="slider-val" id="fork-val">0 mm</span>
    </div>
  </div>
  <div class="sep"></div>
  <div class="ctrl-section">
    <span class="ctrl-label">参数</span>
    <div class="slider-group">
      <label>目标速度</label>
      <input type="range" id="speed-slider" min="1" max="7" step="0.5" value="5"/>
      <span class="slider-val" id="speed-val">5.0 m/s</span>
    </div>
    <div class="slider-group">
      <label>轨道摩擦</label>
      <input type="range" id="friction-slider" min="0.3" max="1" step="0.1" value="0.8"/>
      <span class="slider-val" id="friction-val">0.8</span>
    </div>
  </div>
</div>

<script>
const SVG_NS = 'http://www.w3.org/2000/svg';

// 轮毂电机参数(主视图后轮中心390,638 / 半径32 / 内部各层)
const HUB = { cx: 390, cy: 638, rTire: 32, rRim: 26, rRotor: 22, rGap: 17, rStator: 14, rShaft: 5 };

const state = {
  phase: 'standby', speed: 0, targetSpeed: 5, friction: 0.8,
  acceleration: 0, torque: 0, regenPower: 0, motorTemp: 25,
  trackOffset: 0, wheelAngle: 0, time: 0, phaseTime: 0,
  powerFlowOffset: 0, emFieldAngle: 0,
  forkExtension: 0, forkTarget: 0, forkSpeed: 0, forkMoving: false, forkDirection: 0,
};

const FORK_MAX = 150, FORK_SPEED = 80, FORK_SCALE = 1.0;

function initDynamicElements() {
  // 轨道枕木
  const tiesGroup = document.getElementById('track-ties');
  for (let i = 0; i < 40; i++) {
    const r = document.createElementNS(SVG_NS, 'rect');
    r.setAttribute('x', i * 50); r.setAttribute('y', '664');
    r.setAttribute('width', '20'); r.setAttribute('height', '12');
    r.setAttribute('rx', '1'); r.setAttribute('fill', '#0e1830');
    r.setAttribute('stroke', '#1a2a44'); r.setAttribute('stroke-width', '0.4');
    r.setAttribute('class', 'track-tie');
    tiesGroup.appendChild(r);
  }

  // 轮毂电机磁钢
  const rotorG = document.getElementById('rotor-magnets');
  for (let i = 0; i < 12; i++) {
    const a = (i * 30) * Math.PI / 180;
    const x = HUB.cx + Math.cos(a) * HUB.rRotor;
    const y = HUB.cy + Math.sin(a) * HUB.rRotor;
    const r = document.createElementNS(SVG_NS, 'rect');
    r.setAttribute('x', x - 3); r.setAttribute('y', y - 2.5);
    r.setAttribute('width', '6'); r.setAttribute('height', '5');
    r.setAttribute('rx', '0.8');
    r.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    r.setAttribute('opacity', '0.5');
    r.setAttribute('transform', `rotate(${i * 30}, ${x}, ${y})`);
    rotorG.appendChild(r);
  }

  // 定子线圈
  const statorG = document.getElementById('stator-coils');
  for (let i = 0; i < 9; i++) {
    const a = (i * 40) * Math.PI / 180;
    const x = HUB.cx + Math.cos(a) * (HUB.rStator - 2);
    const y = HUB.cy + Math.sin(a) * (HUB.rStator - 2);
    const c = document.createElementNS(SVG_NS, 'circle');
    c.setAttribute('cx', x); c.setAttribute('cy', y); c.setAttribute('r', '2.5');
    c.setAttribute('fill', '#0a1428'); c.setAttribute('stroke', '#00d4ff');
    c.setAttribute('stroke-width', '0.6'); c.setAttribute('opacity', '0.4');
    c.setAttribute('class', 'stator-coil');
    statorG.appendChild(c);
  }

  // 剖面图磁钢(φ160对应r=80,转子环r=60)
  const detailMag = document.getElementById('detail-magnets');
  for (let i = 0; i < 20; i++) {
    const a = (i * 18) * Math.PI / 180;
    const x = Math.cos(a) * 60; const y = Math.sin(a) * 60;
    const r = document.createElementNS(SVG_NS, 'rect');
    r.setAttribute('x', x - 4); r.setAttribute('y', y - 2.8);
    r.setAttribute('width', '8'); r.setAttribute('height', '5.5');
    r.setAttribute('rx', '0.8');
    r.setAttribute('fill', i % 2 === 0 ? '#ff3d5a' : '#3d5aff');
    r.setAttribute('opacity', '0.45');
    r.setAttribute('transform', `rotate(${i * 18}, ${x}, ${y})`);
    detailMag.appendChild(r);
  }

  // 剖面图定子
  const detailStator = document.getElementById('detail-stator');
  for (let i = 0; i < 12; i++) {
    const g = document.createElementNS(SVG_NS, 'g');
    g.setAttribute('transform', `rotate(${i * 30})`);
    const t = document.createElementNS(SVG_NS, 'rect');
    t.setAttribute('x', '-2.5'); t.setAttribute('y', '-42');
    t.setAttribute('width', '5'); t.setAttribute('height', '11');
    t.setAttribute('rx', '0.8'); t.setAttribute('fill', '#1a2a44');
    g.appendChild(t);
    const c = document.createElementNS(SVG_NS, 'rect');
    c.setAttribute('x', '-5'); c.setAttribute('y', '-39');
    c.setAttribute('width', '10'); c.setAttribute('height', '6');
    c.setAttribute('rx', '1.5'); c.setAttribute('fill', 'none');
    c.setAttribute('stroke', '#00d4ff'); c.setAttribute('stroke-width', '0.6');
    c.setAttribute('opacity', '0.3'); c.setAttribute('class', 'detail-coil');
    g.appendChild(c);
    detailStator.appendChild(g);
  }

  // 速度线
  const speedG = document.getElementById('speed-lines');
  for (let i = 0; i < 20; i++) {
    const l = document.createElementNS(SVG_NS, 'line');
    l.setAttribute('x1', '0'); l.setAttribute('y1', String(380 + Math.random() * 280));
    l.setAttribute('x2', String(30 + Math.random() * 80));
    l.setAttribute('y2', String(380 + Math.random() * 280));
    l.setAttribute('stroke', '#00d4ff'); l.setAttribute('stroke-width', '1');
    l.setAttribute('opacity', '0'); l.setAttribute('class', 'speed-line');
    speedG.appendChild(l);
  }
}

function setPhase(p) {
  state.phase = p; state.phaseTime = 0;
  document.querySelectorAll('.phase-btn').forEach(b => b.classList.toggle('active', b.dataset.phase === p));
  const n = {standby:'STANDBY',accelerate:'ACCELERATE',cruise:'CRUISE',brake:'REGEN BRAKE',stop:'FULL STOP'};
  const c = {standby:'#3e5278',accelerate:'#00d4ff',cruise:'#ffd600',brake:'#00ff88',stop:'#ff3d5a'};
  document.getElementById('phase-name').textContent = n[p];
  document.getElementById('phase-name').setAttribute('fill', c[p]);
}

function extendFork() {
  state.forkTarget = FORK_MAX; state.forkDirection = 1; state.forkMoving = true;
  document.getElementById('fork-extend-btn').classList.add('extending');
  document.getElementById('fork-retract-btn').classList.remove('retracting');
}
function retractFork() {
  state.forkTarget = 0; state.forkDirection = -1; state.forkMoving = true;
  document.getElementById('fork-retract-btn').classList.add('retracting');
  document.getElementById('fork-extend-btn').classList.remove('extending');
}
function setForkTarget(v) {
  state.forkTarget = v;
  state.forkDirection = v > state.forkExtension ? 1 : (v < state.forkExtension ? -1 : 0);
  state.forkMoving = Math.abs(v - state.forkExtension) > 0.5;
}

function updateState(dt) {
  state.time += dt; state.phaseTime += dt;
  switch (state.phase) {
    case 'standby':
      state.speed = Math.max(0, state.speed - 3 * dt);
      state.torque = 0; state.acceleration = state.speed > 0.01 ? -3 : 0; state.regenPower = 0;
      break;
    case 'accelerate': {
      const ma = 2.5 * state.friction;
      state.acceleration = ma;
      state.speed = Math.min(state.targetSpeed, state.speed + ma * dt);
      state.torque = 100 * (1 - state.speed / state.targetSpeed * 0.4) * state.friction;
      state.regenPower = 0;
      if (state.speed >= state.targetSpeed * 0.98) setPhase('cruise');
      break;
    }
    case 'cruise':
      state.speed = state.targetSpeed; state.acceleration = 0; state.torque = 15; state.regenPower = 0;
      break;
    case 'brake': {
      const ba = -4 * state.friction;
      state.acceleration = ba;
      state.speed = Math.max(0, state.speed + ba * dt);
      state.torque = -80 * state.friction;
      state.regenPower = Math.abs(state.speed * state.torque * 0.08);
      state.motorTemp = Math.min(135, state.motorTemp + 20 * dt);
      if (state.speed <= 0.05) setPhase('stop');
      break;
    }
    case 'stop':
      state.speed = 0; state.acceleration = 0; state.torque = 0; state.regenPower = 0;
      break;
  }
  if (state.phase !== 'brake') state.motorTemp = Math.max(25, state.motorTemp - 3 * dt);

  // 货叉伸缩
  if (state.forkMoving) {
    const diff = state.forkTarget - state.forkExtension;
    const step = FORK_SPEED * dt;
    if (Math.abs(diff) <= step) {
      state.forkExtension = state.forkTarget; state.forkMoving = false;
      state.forkDirection = 0; state.forkSpeed = 0;
      document.getElementById('fork-extend-btn').classList.remove('extending');
      document.getElementById('fork-retract-btn').classList.remove('retracting');
    } else {
      state.forkExtension += Math.sign(diff) * step;
      state.forkSpeed = Math.sign(diff) * FORK_SPEED;
    }
  } else { state.forkSpeed = 0; }

  state.trackOffset = (state.trackOffset + state.speed * 25 * dt) % 50;
  state.wheelAngle += state.speed * 3 * dt;
  state.powerFlowOffset = (state.powerFlowOffset + state.speed * 80 * dt) % 40;
  state.emFieldAngle += (state.speed * 2 + (state.phase === 'accelerate' ? 3 : 0)) * dt;
}

function render() {
  const isAccel = state.phase === 'accelerate';
  const isCruise = state.phase === 'cruise';
  const isBrake = state.phase === 'brake';
  const isStop = state.phase === 'stop';
  const isActive = isAccel || isCruise;
  const sr = state.speed / 7;
  const ext = state.forkExtension;
  const isFM = state.forkMoving;

  // 枕木
  document.querySelectorAll('.track-tie').forEach((t, i) => {
    t.setAttribute('x', String((i * 50 - state.trackOffset + 920) % 2000 - 50));
  });

  // 轮子旋转
  const wa = state.wheelAngle * 180 / Math.PI;
  document.getElementById('spokes-rear').setAttribute('transform', `rotate(${wa}, ${HUB.cx}, ${HUB.cy})`);
  document.getElementById('rotor-magnets').setAttribute('transform', `rotate(${wa * 0.95}, ${HUB.cx}, ${HUB.cy})`);
  document.getElementById('spokes-front').setAttribute('transform', `rotate(${wa}, 670, 644)`);

  // 定子线圈
  document.querySelectorAll('.stator-coil').forEach((c, i) => {
    const ph = (state.emFieldAngle * 3 + i * 0.7) % (Math.PI * 2);
    c.setAttribute('opacity', String(isActive ? 0.3 + 0.7 * Math.max(0, Math.sin(ph)) : 0.15));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });
  document.querySelectorAll('.detail-coil').forEach((c, i) => {
    const ph = (state.emFieldAngle * 3 + i * 0.5) % (Math.PI * 2);
    c.setAttribute('opacity', String(isActive || isBrake ? 0.2 + 0.8 * Math.max(0, Math.sin(ph)) : 0.1));
    c.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
  });

  // 电力路径
  ['power-path-cm1','power-path-cm2','power-path-bc'].forEach(id => {
    const el = document.getElementById(id);
    if (isActive) {
      el.setAttribute('stroke', '#00d4ff'); el.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
      el.setAttribute('opacity', String(0.4 + sr * 0.5));
    } else if (isBrake) {
      el.setAttribute('stroke', '#00ff88'); el.setAttribute('stroke-dashoffset', String(state.powerFlowOffset));
      el.setAttribute('opacity', String(0.3 + sr * 0.4));
    } else { el.setAttribute('stroke', '#2a4060'); el.setAttribute('opacity', '0.25'); }
  });

  // 力箭头
  document.getElementById('drive-force').setAttribute('opacity', String(isActive ? Math.min(1, Math.abs(state.torque) / 60) : 0));
  document.getElementById('regen-force').setAttribute('opacity', String(isBrake ? Math.min(1, Math.abs(state.torque) / 60) : 0));
  document.getElementById('torque-arc').setAttribute('opacity', String(isActive ? 0.8 : 0));
  document.getElementById('regen-arc').setAttribute('opacity', String(isBrake ? 0.8 : 0));

  // LED
  const led = document.getElementById('ctrl-led');
  if (isActive) { led.setAttribute('fill', '#00d4ff'); led.setAttribute('filter', 'url(#softglow)'); }
  else if (isBrake) { led.setAttribute('fill', '#00ff88'); led.setAttribute('filter', 'url(#softglow)'); }
  else if (isStop) { led.setAttribute('fill', '#ff3d5a'); led.removeAttribute('filter'); }
  else { led.setAttribute('fill', '#1a2a40'); led.removeAttribute('filter'); }

  // 电池
  const bl = isBrake ? Math.min(1, 0.5 + state.regenPower / 80) : Math.max(0.2, 0.8 - sr * 0.3);
  document.getElementById('bat-bar').setAttribute('height', String(14 * bl));
  document.getElementById('bat-bar').setAttribute('fill', isBrake ? '#00ff88' : '#1a4a2a');

  // 俯视图差速
  const dl = document.getElementById('diff-line-l'), dr = document.getElementById('diff-line-r');
  if (isActive || isBrake) {
    const col = isBrake ? '#00ff88' : '#00d4ff';
    dl.setAttribute('stroke', col); dr.setAttribute('stroke', col);
    dl.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    dr.setAttribute('stroke-dashoffset', String(-state.powerFlowOffset));
    dl.setAttribute('opacity', '0.8'); dr.setAttribute('opacity', '0.8');
  } else { dl.setAttribute('stroke', '#2a4060'); dr.setAttribute('stroke', '#2a4060'); dl.setAttribute('opacity', '0.4'); dr.setAttribute('opacity', '0.4'); }
  document.getElementById('sync-indicator').setAttribute('opacity', String(isActive || isCruise ? 0.9 : 0));
  document.getElementById('direction-arrow').setAttribute('opacity', String(state.speed > 0.1 ? 0.8 : 0));

  // 速度线
  document.querySelectorAll('.speed-line').forEach((l, i) => {
    if (state.speed > 1) {
      const al = Math.min(0.5, (state.speed - 1) / 6) * (0.3 + Math.random() * 0.7);
      l.setAttribute('opacity', String(al)); l.setAttribute('stroke', isBrake ? '#00ff88' : '#00d4ff');
      const y = 390 + ((i * 47 + state.time * 200) % 260);
      const len = 30 + state.speed * 15 + Math.random() * 40;
      l.setAttribute('y1', String(y)); l.setAttribute('y2', String(y));
      l.setAttribute('x1', String(-len - Math.random() * 200)); l.setAttribute('x2', String(-Math.random() * 200));
    } else { l.setAttribute('opacity', '0'); }
  });

  // 轮毂发光
  const hg = document.getElementById('hub-motor-group');
  if (isActive) hg.setAttribute('filter', 'url(#glow-cyan)');
  else if (isBrake) hg.setAttribute('filter', 'url(#glow-green)');
  else hg.removeAttribute('filter');

  document.getElementById('no-shaft-label').setAttribute('opacity', String(0.35 + sr * 0.35));

  ['top-left-motor','top-right-motor'].forEach(id => {
    const g = document.getElementById(id);
    const c = g.querySelector('circle:nth-child(2)');
    if (isActive) { c.setAttribute('stroke', '#00d4ff'); c.setAttribute('stroke-width', '2'); }
    else if (isBrake) { c.setAttribute('stroke', '#00ff88'); c.setAttribute('stroke-width', '2'); }
    else { c.setAttribute('stroke', '#1e3050'); c.setAttribute('stroke-width', '1'); }
  });

  // ===== 货叉伸缩渲染 =====
  document.getElementById('fork-upper').setAttribute('transform', `translate(${ext}, 0)`);
  document.getElementById('fork-lower').setAttribute('transform', `translate(${ext}, 0)`);
  document.getElementById('fork-verticals').setAttribute('transform', `translate(${ext}, 0)`);

  const te = ext * 0.6;
  const ftu = document.getElementById('fork-top-upper');
  const ftl = document.getElementById('fork-top-lower');
  ftu.setAttribute('x', String(310 + te)); ftu.setAttribute('width', String(100 + te * 0.3));
  ftl.setAttribute('x', String(310 + te)); ftl.setAttribute('width', String(100 + te * 0.3));
  const tipX = 310 + te + 100 + te * 0.3;
  document.getElementById('fork-top-tip-u').setAttribute('d', `M${tipX},80 L${tipX+15},83 L${tipX+15},91 L${tipX},94Z`);
  document.getElementById('fork-top-tip-l').setAttribute('d', `M${tipX},186 L${tipX+15},189 L${tipX+15},197 L${tipX},200Z`);

  // 导轨发光
  const rg = document.getElementById('rail-glow');
  rg.setAttribute('opacity', String(isFM ? (0.5 + 0.3 * Math.sin(state.time * 8)) : (ext > 0 ? 0.15 : 0)));
  if (isFM) {
    const gc = state.forkDirection > 0 ? '#ff6b2b' : '#00ff88';
    document.getElementById('rail-glow-grad').querySelectorAll('stop').forEach((s, i) => {
      if (i === 1 || i === 2) s.setAttribute('stop-color', gc);
    });
  }

  // 推杆
  const rod = document.getElementById('fork-actuator-rod');
  rod.setAttribute('x', String(730 + Math.min(18, ext * 0.2)));
  rod.setAttribute('width', String(Math.max(5, 20 - ext * 0.1)));
  document.getElementById('fork-actuator').setAttribute('opacity', String(isFM ? 0.9 : 0.4));

  // 位移标注
  const fd = document.getElementById('fork-dimension');
  const showD = ext > 2 || isFM;
  fd.setAttribute('opacity', String(showD ? 0.9 : 0));
  if (showD) {
    const sx = 690, ex = 690 + ext;
    document.getElementById('fork-dim-end').setAttribute('x1', String(ex));
    document.getElementById('fork-dim-end').setAttribute('x2', String(ex));
    document.getElementById('fork-dim-line').setAttribute('x1', String(sx));
    document.getElementById('fork-dim-line').setAttribute('x2', String(ex));
    document.getElementById('fork-dim-text').setAttribute('x', String((sx + ex) / 2));
    document.getElementById('fork-dim-text').textContent = Math.round(ext * FORK_SCALE) + 'mm';
    document.getElementById('fork-dim-text').setAttribute('fill', state.forkDirection > 0 ? '#ff6b2b' : (state.forkDirection < 0 ? '#00ff88' : '#ff6b2b'));
  }

  // 货叉标签
  const fl = document.getElementById('fork-label-text');
  fl.setAttribute('x', String(770 + ext * 0.5));
  if (isFM) { fl.setAttribute('fill', state.forkDirection > 0 ? '#ff6b2b' : '#00ff88'); fl.textContent = state.forkDirection > 0 ? 'EXTENDING...' : 'RETRACTING...'; }
  else { fl.setAttribute('fill', ext > 0 ? '#2a4060' : '#1e3050'); fl.textContent = 'CARBON FORK'; }

  // 叉尖闪烁
  if (isFM) {
    const bk = 0.5 + 0.5 * Math.sin(state.time * 12);
    const fc = state.forkDirection > 0 ? `rgba(255,107,43,${bk * 0.3})` : `rgba(0,255,136,${bk * 0.3})`;
    const sc = state.forkDirection > 0 ? '#ff6b2b' : '#00ff88';
    document.getElementById('fork-upper').querySelector('path').setAttribute('fill', fc);
    document.getElementById('fork-upper').querySelector('path').setAttribute('stroke', sc);
    document.getElementById('fork-lower').querySelector('path').setAttribute('fill', fc);
    document.getElementById('fork-lower').querySelector('path').setAttribute('stroke', sc);
  } else {
    document.getElementById('fork-upper').querySelector('path').setAttribute('fill', '#14203a');
    document.getElementById('fork-upper').querySelector('path').setAttribute('stroke', '#1e3050');
    document.getElementById('fork-lower').querySelector('path').setAttribute('fill', '#14203a');
    document.getElementById('fork-lower').querySelector('path').setAttribute('stroke', '#1e3050');
  }

  // 参数
  document.getElementById('svg-speed').textContent = state.speed.toFixed(1);
  document.getElementById('svg-accel').textContent = Math.abs(state.acceleration).toFixed(1);
  document.getElementById('svg-torque').textContent = Math.abs(Math.round(state.torque));
  document.getElementById('svg-regen').textContent = Math.round(state.regenPower);
  document.getElementById('svg-temp').textContent = Math.round(state.motorTemp);
  document.getElementById('svg-fork').textContent = Math.round(ext * FORK_SCALE);

  const tEl = document.getElementById('svg-temp');
  tEl.setAttribute('fill', state.motorTemp > 100 ? '#ff3d5a' : state.motorTemp > 70 ? '#ff6b2b' : '#ffd600');
  document.getElementById('svg-accel').setAttribute('fill', state.acceleration >= 0 ? '#00d4ff' : '#ff6b2b');
  document.getElementById('svg-torque').setAttribute('fill', state.torque >= 0 ? '#00d4ff' : '#00ff88');

  document.getElementById('fork-status-val').textContent = Math.round(ext * FORK_SCALE) + ' mm';
  document.getElementById('fork-status-val').setAttribute('fill', isFM ? (state.forkDirection > 0 ? '#ff6b2b' : '#00ff88') : (ext > 0 ? '#ff6b2b' : '#3e5278'));
}

let lastTime = 0;
function animate(ts) {
  const dt = Math.min(0.05, (ts - lastTime) / 1000);
  lastTime = ts;
  updateState(dt); render();
  requestAnimationFrame(animate);
}

document.querySelectorAll('.phase-btn').forEach(b => b.addEventListener('click', () => setPhase(b.dataset.phase)));
document.getElementById('speed-slider').addEventListener('input', e => {
  state.targetSpeed = parseFloat(e.target.value);
  document.getElementById('speed-val').textContent = state.targetSpeed.toFixed(1) + ' m/s';
});
document.getElementById('friction-slider').addEventListener('input', e => {
  state.friction = parseFloat(e.target.value);
  document.getElementById('friction-val').textContent = state.friction.toFixed(1);
});
document.getElementById('fork-extend-btn').addEventListener('click', extendFork);
document.getElementById('fork-retract-btn').addEventListener('click', retractFork);
document.getElementById('fork-slider').addEventListener('input', e => {
  const v = parseFloat(e.target.value);
  setForkTarget(v);
  document.getElementById('fork-val').textContent = Math.round(v * FORK_SCALE) + ' mm';
});

initDynamicElements(); setPhase('standby'); requestAnimationFrame(animate);
</script>
</body>
</html>

轮径调整说明

已将全部轮径缩至 φ160mm(SVG 半径 32px),并同步调整了所有关联元素:

调整项 旧值 新值
后轮(轮毂电机)半径 52px 32px
前轮(从动轮)半径 42px 26px(等比缩小)
后轮中心 Y 590 638(保持轮缘触轨 y=670)
前轮中心 Y 595 644
底盘桁架 y=465~540 y=580~615(下移贴合小轮)
轮毂内部分层(转子/定子/气隙/轴) 按原比例 按32半径等比缩放
剖面图 r=100 r=80(对应φ160mm)
磁钢/线圈/辐条尺寸 等比缩小
悬挂连接杆 新增(底盘→轮轴的 V 形连接)
轨道面 Y 638 670(随整车下移)

标签 "≤4kg · φ160" 标注在轮毂电机下方,剖面图标题也更新为 "φ160mm"。

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