分享图
动画工坊
引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>轴向自锁伸缩伞骨机构原理动画</title>
  <style>
    :root {
      --bg-color: #0c1017;
      --card-bg: rgba(18, 24, 38, 0.85);
      --card-border: rgba(56, 189, 248, 0.18);
      --accent-cyan: #38bdf8;
      --accent-amber: #fbbf24;
      --accent-emerald: #34d399;
      --accent-rose: #f43f5e;
      --tube-outer: #475569;
      --tube-mid: #64748b;
      --tube-inner: #94a3b8;
      --spring-color: #f59e0b;
      --text-main: #e2e8f0;
      --text-muted: #94a3b8;
      --font-mono: "JetBrains Mono", "Fira Code", "Courier New", monospace;
    }

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

    body {
      background-color: var(--bg-color);
      color: var(--text-main);
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: space-between;
      overflow: hidden;
      background-image: 
        radial-gradient(circle at 50% 20%, rgba(56, 189, 248, 0.08) 0%, transparent 60%),
        linear-gradient(to right, rgba(255, 255, 255, 0.02) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
      background-size: 100% 100%, 32px 32px, 32px 32px;
    }

    /* 顶部精简状态条 - 避免遮挡 */
    header {
      width: 100%;
      padding: 12px 24px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      border-bottom: 1px solid rgba(255, 255, 255, 0.06);
      backdrop-filter: blur(8px);
      z-index: 10;
    }

    .brand {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .brand-tag {
      font-size: 10px;
      font-family: var(--font-mono);
      color: var(--accent-cyan);
      background: rgba(56, 189, 248, 0.12);
      border: 1px solid rgba(56, 189, 248, 0.3);
      padding: 2px 6px;
      border-radius: 4px;
      letter-spacing: 0.5px;
    }

    .brand-title {
      font-size: 14px;
      font-weight: 600;
      letter-spacing: 0.3px;
      color: #f8fafc;
    }

    .specs-strip {
      display: flex;
      gap: 16px;
    }

    .spec-item {
      display: flex;
      align-items: baseline;
      gap: 4px;
      font-size: 11px;
    }

    .spec-label {
      color: var(--text-muted);
    }

    .spec-val {
      font-family: var(--font-mono);
      font-weight: 600;
      color: var(--accent-cyan);
    }

    /* 主可视化舞台 */
    main {
      flex: 1;
      width: 100%;
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 10px;
    }

    .stage-container {
      width: 100%;
      max-width: 1180px;
      height: 100%;
      max-height: 680px;
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    svg#mechanism-stage {
      width: 100%;
      height: 100%;
      overflow: visible;
    }

    /* 浮动边缘微型数据卡 (非侵入式布局,靠边置放) */
    .hud-overlay {
      position: absolute;
      top: 14px;
      left: 14px;
      display: flex;
      flex-direction: column;
      gap: 8px;
      pointer-events: none;
      z-index: 5;
    }

    .status-badge {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 5px 10px;
      background: var(--card-bg);
      border: 1px solid var(--card-border);
      border-radius: 6px;
      font-size: 11px;
      backdrop-filter: blur(10px);
    }

    .status-dot {
      width: 7px;
      height: 7px;
      border-radius: 50%;
      background: var(--accent-emerald);
      box-shadow: 0 0 8px var(--accent-emerald);
      transition: all 0.3s ease;
    }

    .status-dot.retracting {
      background: var(--accent-amber);
      box-shadow: 0 0 8px var(--accent-amber);
    }

    .status-dot.unlocking {
      background: var(--accent-rose);
      box-shadow: 0 0 8px var(--accent-rose);
    }

    .hud-metrics {
      display: grid;
      grid-template-columns: repeat(2, auto);
      gap: 6px;
    }

    .metric-pill {
      background: rgba(15, 23, 42, 0.75);
      border: 1px solid rgba(255, 255, 255, 0.07);
      padding: 4px 8px;
      border-radius: 4px;
      font-size: 10px;
      font-family: var(--font-mono);
      display: flex;
      justify-content: space-between;
      gap: 8px;
    }

    /* 右上角伞形联动形态监视小窗 */
    .umbrella-mini-view {
      position: absolute;
      top: 14px;
      right: 14px;
      width: 140px;
      height: 110px;
      background: var(--card-bg);
      border: 1px solid var(--card-border);
      border-radius: 8px;
      padding: 6px;
      display: flex;
      flex-direction: column;
      align-items: center;
      backdrop-filter: blur(8px);
      pointer-events: none;
      z-index: 5;
    }

    .mini-view-title {
      font-size: 9px;
      font-family: var(--font-mono);
      color: var(--text-muted);
      margin-bottom: 2px;
      width: 100%;
      text-align: left;
    }

    /* 底部控制中心 */
    footer {
      width: 100%;
      padding: 10px 24px 16px;
      background: rgba(12, 16, 23, 0.9);
      border-top: 1px solid rgba(255, 255, 255, 0.07);
      display: flex;
      flex-direction: column;
      gap: 8px;
      align-items: center;
      z-index: 10;
    }

    .timeline-container {
      width: 100%;
      max-width: 900px;
      display: flex;
      align-items: center;
      gap: 12px;
    }

    .time-slider {
      flex: 1;
      -webkit-appearance: none;
      height: 5px;
      border-radius: 3px;
      background: #1e293b;
      outline: none;
      cursor: pointer;
      position: relative;
    }

    .time-slider::-webkit-slider-thumb {
      -webkit-appearance: none;
      width: 14px;
      height: 14px;
      border-radius: 50%;
      background: var(--accent-cyan);
      box-shadow: 0 0 10px var(--accent-cyan);
      cursor: pointer;
      border: 2px solid #0f172a;
    }

    .controls-row {
      display: flex;
      align-items: center;
      gap: 16px;
      font-size: 11px;
    }

    .btn {
      background: #1e293b;
      color: #e2e8f0;
      border: 1px solid rgba(255, 255, 255, 0.12);
      padding: 5px 12px;
      border-radius: 5px;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-size: 11px;
      transition: all 0.2s;
    }

    .btn:hover {
      background: #334155;
      border-color: var(--accent-cyan);
    }

    .btn.active {
      background: rgba(56, 189, 248, 0.15);
      border-color: var(--accent-cyan);
      color: var(--accent-cyan);
    }

    .step-pill-group {
      display: flex;
      background: #0f172a;
      padding: 2px;
      border-radius: 6px;
      border: 1px solid rgba(255, 255, 255, 0.08);
      gap: 2px;
    }

    .step-pill {
      background: transparent;
      border: none;
      color: var(--text-muted);
      padding: 3px 8px;
      font-size: 10px;
      border-radius: 4px;
      cursor: pointer;
      transition: 0.2s;
    }

    .step-pill.active {
      background: #1e293b;
      color: var(--accent-cyan);
      font-weight: 600;
    }

    /* SVG 内部微动画样式 */
    .glow-cyan { filter: drop-shadow(0 0 4px rgba(56, 189, 248, 0.8)); }
    .glow-amber { filter: drop-shadow(0 0 4px rgba(251, 191, 36, 0.8)); }
    .glow-emerald { filter: drop-shadow(0 0 5px rgba(52, 211, 153, 0.9)); }
    .glow-rose { filter: drop-shadow(0 0 5px rgba(244, 63, 94, 0.9)); }
    
    .vector-arrow {
      stroke-dasharray: 4, 3;
      animation: dashMove 1s linear infinite;
    }

    @keyframes dashMove {
      from { stroke-dashoffset: 14; }
      to { stroke-dashoffset: 0; }
    }

    .spring-coils {
      stroke-dasharray: 3, 1.5;
    }
  </style>
</head>
<body>

  <!-- 顶部精简抬头条 -->
  <header>
    <div class="brand">
      <span class="brand-tag">IFR-DESIGN</span>
      <span class="brand-title">轴向自锁套接伞骨原理动画 (Axial Telescopic Rib)</span>
    </div>
    <div class="specs-strip">
      <div class="spec-item"><span class="spec-label">套管节数:</span><span class="spec-val">3节 (304薄壁管)</span></div>
      <div class="spec-item"><span class="spec-label">行程压缩:</span><span class="spec-val">550mm → 200mm (350mm)</span></div>
      <div class="spec-item"><span class="spec-label">卷簧恒力:</span><span class="spec-val">6.0 N</span></div>
      <div class="spec-item"><span class="spec-label">重叠自锁:</span><span class="spec-val">40 mm</span></div>
    </div>
  </header>

  <!-- 主动画展示舞台 -->
  <main>
    <div class="stage-container">
      
      <!-- 边缘非遮挡 HUD 读数 -->
      <div class="hud-overlay">
        <div class="status-badge">
          <div class="status-dot" id="statusDot"></div>
          <span id="stateName" style="font-weight: 600; font-size: 11px;">状态:连续循环演示中</span>
        </div>
        <div class="hud-metrics">
          <div class="metric-pill"><span>骨架总长:</span><span id="hudLength" class="spec-val">200 mm</span></div>
          <div class="metric-pill"><span>自锁爪状态:</span><span id="hudLock" class="spec-val" style="color:var(--accent-amber)">就绪/待锁</span></div>
          <div class="metric-pill"><span>卷簧张力:</span><span id="hudSpring" class="spec-val">6.0 N 蓄能</span></div>
          <div class="metric-pill"><span>释放推杆:</span><span id="hudPusher" class="spec-val">原位复位</span></div>
        </div>
      </div>

      <!-- 右上角整伞联动小窗 -->
      <div class="umbrella-mini-view">
        <div class="mini-view-title">整伞形态联动投影</div>
        <svg id="miniUmbrella" viewBox="0 0 120 80" width="100%" height="100%">
          <defs>
            <linearGradient id="canopyGrad" x1="0%" y1="0%" x2="0%" y2="100%">
              <stop offset="0%" stop-color="#0284c7" stop-opacity="0.75"/>
              <stop offset="100%" stop-color="#0369a1" stop-opacity="0.25"/>
            </linearGradient>
          </defs>
          <!-- 伞中棒 -->
          <line x1="60" y1="12" x2="60" y2="72" stroke="#64748b" stroke-width="2.5" stroke-linecap="round"/>
          <circle cx="60" cy="12" r="3" fill="#38bdf8"/>
          <rect x="56" y="66" width="8" height="9" rx="2" fill="#334155"/>
          <!-- 下巢滑块 -->
          <rect id="miniRunner" x="57" y="52" width="6" height="5" rx="1" fill="#38bdf8"/>
          <!-- 动态伞面 -->
          <path id="miniCanopy" d="M 15 48 Q 60 10 105 48" fill="url(#canopyGrad)" stroke="#38bdf8" stroke-width="1.5"/>
          <!-- 左右支撑副骨 -->
          <line id="miniStrutL" x1="57" y1="52" x2="32" y2="38" stroke="#94a3b8" stroke-width="1.2"/>
          <line id="miniStrutR" x1="63" y1="52" x2="88" y2="38" stroke="#94a3b8" stroke-width="1.2"/>
          <!-- 左右伸缩主骨 -->
          <line id="miniRibL" x1="60" y1="12" x2="15" y2="48" stroke="#f8fafc" stroke-width="1.6"/>
          <line id="miniRibR" x1="60" y1="12" x2="105" y2="48" stroke="#f8fafc" stroke-width="1.6"/>
        </svg>
      </div>

      <!-- 核心原理剖面 SVG -->
      <svg id="mechanism-stage" viewBox="0 0 1000 520">
        <defs>
          <!-- 滤镜与渐变定义 -->
          <linearGradient id="gradOuterTube" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stop-color="#64748b"/>
            <stop offset="30%" stop-color="#475569"/>
            <stop offset="70%" stop-color="#334155"/>
            <stop offset="100%" stop-color="#1e293b"/>
          </linearGradient>

          <linearGradient id="gradMidTube" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stop-color="#94a3b8"/>
            <stop offset="30%" stop-color="#64748b"/>
            <stop offset="70%" stop-color="#475569"/>
            <stop offset="100%" stop-color="#334155"/>
          </linearGradient>

          <linearGradient id="gradInnerTube" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" stop-color="#cbd5e1"/>
            <stop offset="30%" stop-color="#94a3b8"/>
            <stop offset="70%" stop-color="#64748b"/>
            <stop offset="100%" stop-color="#475569"/>
          </linearGradient>

          <linearGradient id="gradSpring" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stop-color="#f59e0b"/>
            <stop offset="50%" stop-color="#fbbf24"/>
            <stop offset="100%" stop-color="#d97706"/>
          </linearGradient>

          <filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
            <feGaussianBlur stdDeviation="3" result="blur"/>
            <feComposite in="SourceGraphic" in2="blur" operator="over"/>
          </filter>

          <filter id="glow-gold" x="-20%" y="-20%" width="140%" height="140%">
            <feGaussianBlur stdDeviation="3" result="blur"/>
            <feComposite in="SourceGraphic" in2="blur" operator="over"/>
          </filter>

          <marker id="arrowhead" markerWidth="6" markerHeight="4" refX="5" refY="2" orient="auto">
            <polygon points="0 0, 6 2, 0 4" fill="#38bdf8"/>
          </marker>

          <marker id="arrowhead-amber" markerWidth="6" markerHeight="4" refX="5" refY="2" orient="auto">
            <polygon points="0 0, 6 2, 0 4" fill="#fbbf24"/>
          </marker>
        </defs>

        <!-- 背景工程基准线网格 -->
        <g opacity="0.18">
          <line x1="80" y1="260" x2="940" y2="260" stroke="#38bdf8" stroke-dasharray="8 4" stroke-width="1"/>
          <line x1="120" y1="120" x2="120" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
          <line x1="380" y1="120" x2="380" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
          <line x1="640" y1="120" x2="640" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
          <line x1="900" y1="120" x2="900" y2="400" stroke="#94a3b8" stroke-dasharray="2 4" stroke-width="1"/>
        </g>

        <!-- 顶部动态总行程标尺 -->
        <g id="dimensionLineGroup" transform="translate(0, -30)">
          <line id="dimLine" x1="130" y1="145" x2="390" y2="145" stroke="#38bdf8" stroke-width="1.5"/>
          <line x1="130" y1="138" x2="130" y2="152" stroke="#38bdf8" stroke-width="1.5"/>
          <line id="dimTickEnd" x1="390" y1="138" x2="390" y2="152" stroke="#38bdf8" stroke-width="1.5"/>
          <rect id="dimBadge" x="220" y="132" width="80" height="18" rx="3" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>
          <text id="dimText" x="260" y="145" fill="#38bdf8" font-size="11" font-family="monospace" text-anchor="middle" dominant-baseline="central">200 mm</text>
        </g>

        <!-- 主机构装配体 (居中基准 Y=260) -->
        <g id="mainAssembly" transform="translate(0, 0)">

          <!-- 1. 中央伞盘与释放驱动模块 (Base Mount & Release Collar) -->
          <g id="baseCollarGroup">
            <!-- 伞顶固定座 -->
            <path d="M 80,210 L 130,210 L 130,310 L 80,310 Z" fill="#1e293b" stroke="#475569" stroke-width="2"/>
            <circle cx="105" cy="260" r="14" fill="#0f172a" stroke="#38bdf8" stroke-width="2"/>
            <circle cx="105" cy="260" r="4" fill="#38bdf8"/>
            <text x="105" y="332" fill="#94a3b8" font-size="10" text-anchor="middle">伞头铰接座</text>

            <!-- 恒力簧卷盘 (固定在基座内部) -->
            <circle cx="148" cy="260" r="16" fill="#1e293b" stroke="#d97706" stroke-width="2" class="glow-gold"/>
            <circle cx="148" cy="260" r="7" fill="#d97706"/>
            <!-- 卷簧发条涡卷纹 -->
            <path d="M 148,248 A 12 12 0 1 1 138,265 A 7 7 0 1 1 148,255" fill="none" stroke="#fbbf24" stroke-width="1.8"/>

            <!-- 中央环形释放推压板 (Release Collar Actuator) -->
            <g id="releaseCollar" transform="translate(0, 0)">
              <rect x="70" y="234" width="14" height="52" rx="3" fill="#e11d48" stroke="#fda4af" stroke-width="1.5" class="glow-rose"/>
              <polygon points="62,260 68,254 68,266" fill="#f43f5e"/>
              <text id="releaseText" x="52" y="264" fill="#f43f5e" font-size="9" font-weight="bold" text-anchor="end">释放环</text>
            </g>

            <!-- 解锁细推杆 (穿过管壁内部) -->
            <line id="pushRod" x1="84" y1="240" x2="370" y2="240" stroke="#f43f5e" stroke-width="2" stroke-dasharray="6 2" opacity="0.9"/>
          </g>

          <!-- 2. 第一节:外节薄壁管 (Base Tube, 固定在伞座) -->
          <g id="outerTubeGroup">
            <!-- 外管剖面主体 (外径 14mm,壁厚 0.3mm 示意) -->
            <path d="M 130,224 L 390,224 L 390,234 L 130,234 Z" fill="url(#gradOuterTube)" stroke="#64748b" stroke-width="1"/>
            <path d="M 130,286 L 390,286 L 390,296 L 130,296 Z" fill="url(#gradOuterTube)" stroke="#64748b" stroke-width="1"/>
            
            <!-- 外管右端锁定凹槽 (Locking Notch 1) -->
            <rect x="366" y="220" width="12" height="5" fill="#0f172a" stroke="#38bdf8" stroke-width="1.2"/>
            <rect x="366" y="295" width="12" height="5" fill="#0f172a" stroke="#38bdf8" stroke-width="1.2"/>

            <!-- O形防尘密封阻尼圈 (40mm 重叠端部) -->
            <ellipse cx="386" cy="229" rx="3" ry="4" fill="#0284c7" stroke="#38bdf8"/>
            <ellipse cx="386" cy="291" rx="3" ry="4" fill="#0284c7" stroke="#38bdf8"/>
            <text x="365" y="208" fill="#94a3b8" font-size="10" text-anchor="middle">外节管 (节1) / 定位槽</text>
          </g>

          <!-- 3. 第二节:中节套管 (Mid Tube, 可轴向伸缩) -->
          <g id="midTubeGroup" transform="translate(0, 0)">
            <!-- 中节管剖面 (略小一圈,嵌套在外管中) -->
            <path d="M 150,235 L 410,235 L 410,243 L 150,243 Z" fill="url(#gradMidTube)" stroke="#94a3b8" stroke-width="1"/>
            <path d="M 150,277 L 410,277 L 410,285 L 150,285 Z" fill="url(#gradMidTube)" stroke="#94a3b8" stroke-width="1"/>
            
            <!-- 中节管左端弹性卡爪 1 (Pawl 1) -->
            <g id="pawl1Group" transform="translate(160, 0)">
              <!-- 上弹片 -->
              <path id="pawl1Upper" d="M -10,243 Q 5,243 14,228 L 22,228 L 22,243 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
              <!-- 下弹片 -->
              <path id="pawl1Lower" d="M -10,277 Q 5,277 14,292 L 22,292 L 22,277 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
              <circle cx="16" cy="228" r="2" fill="#ffffff" class="glow-cyan"/>
            </g>

            <!-- 中节管右端锁定凹槽 (Locking Notch 2) -->
            <rect x="388" y="232" width="10" height="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>
            <rect x="388" y="284" width="10" height="4" fill="#0f172a" stroke="#38bdf8" stroke-width="1"/>

            <!-- 中节管防泥沙O圈 -->
            <ellipse cx="406" cy="239" rx="2.5" ry="3.5" fill="#0284c7"/>
            <ellipse cx="406" cy="281" rx="2.5" ry="3.5" fill="#0284c7"/>
          </g>

          <!-- 4. 第三节:内节末端管 (Inner Tip Tube, 伸至伞骨末端) -->
          <g id="innerTubeGroup" transform="translate(0, 0)">
            <!-- 内节管剖面 -->
            <path d="M 170,244 L 430,244 L 430,250 L 170,250 Z" fill="url(#gradInnerTube)" stroke="#cbd5e1" stroke-width="1"/>
            <path d="M 170,270 L 430,270 L 430,276 L 170,276 Z" fill="url(#gradInnerTube)" stroke="#cbd5e1" stroke-width="1"/>
            
            <!-- 伞骨末梢珠尾 (Tip Cap) -->
            <path d="M 430,240 L 444,244 L 448,260 L 444,276 L 430,280 Z" fill="#38bdf8" stroke="#e0f2fe" stroke-width="1.5" class="glow-cyan"/>
            <circle cx="442" cy="260" r="3" fill="#ffffff"/>
            
            <!-- 内节管左端弹性卡爪 2 (Pawl 2) -->
            <g id="pawl2Group" transform="translate(180, 0)">
              <!-- 上弹片 -->
              <path id="pawl2Upper" d="M -10,250 Q 5,250 12,238 L 18,238 L 18,250 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
              <!-- 下弹片 -->
              <path id="pawl2Lower" d="M -10,270 Q 5,270 12,282 L 18,282 L 18,270 Z" fill="#38bdf8" stroke="#7dd3fc" stroke-width="1"/>
              <circle cx="14" cy="238" r="2" fill="#ffffff" class="glow-cyan"/>
            </g>

            <!-- 恒力簧与末端管的锚定点固定块 -->
            <circle cx="426" cy="260" r="4" fill="#fbbf24" stroke="#d97706" stroke-width="1.5"/>
          </g>

          <!-- 5. 核心机构:0.1mm 恒力卷簧拉伸带 (Constant Force Spring Strip) -->
          <g id="springBeltGroup">
            <!-- 卷簧钢带 (从卷轴 148,260 连至内节锚定点) -->
            <line id="springBelt" x1="164" y1="260" x2="426" y2="260" stroke="url(#gradSpring)" stroke-width="3" stroke-linecap="round" class="glow-gold"/>
            <!-- 恒力张力微波纹/刻度 -->
            <line id="springTexture" x1="164" y1="260" x2="426" y2="260" stroke="#ffffff" stroke-width="1" stroke-dasharray="5 3" opacity="0.6"/>
          </g>

          <!-- 6. 动态受力与自锁微观状态高亮层 (Visual FX) -->
          <!-- 自锁入槽光晕与提示 -->
          <g id="lockHighlight1" opacity="0" transform="translate(372, 222)">
            <circle cx="0" cy="0" r="10" fill="none" stroke="#34d399" stroke-width="2" class="glow-emerald"/>
            <polygon points="-4,-7 0,-14 4,-7" fill="#34d399"/>
            <text x="0" y="-18" fill="#34d399" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">自锁锁定 40mm</text>
          </g>

          <g id="lockHighlight2" opacity="0" transform="translate(632, 234)">
            <circle cx="0" cy="0" r="10" fill="none" stroke="#34d399" stroke-width="2" class="glow-emerald"/>
            <polygon points="-4,-7 0,-14 4,-7" fill="#34d399"/>
            <text x="0" y="-18" fill="#34d399" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">末节自锁到位</text>
          </g>

          <!-- 恒力卷簧 6N 恒定收缩力矢量箭头 -->
          <g id="forceVectorGroup" opacity="0.8">
            <line id="vectorLine" x1="420" y1="260" x2="340" y2="260" stroke="#fbbf24" stroke-width="2.5" marker-end="url(#arrowhead-amber)" class="vector-arrow"/>
            <text id="vectorText" x="380" y="278" fill="#fbbf24" font-size="10" font-family="monospace" font-weight="bold" text-anchor="middle">F_spring = 6.0 N (恒力回缩)</text>
          </g>

        </g>

        <!-- 底部精简图例与结构导引 (不遮挡主体) -->
        <g transform="translate(100, 440)">
          <!-- 导引 1 -->
          <g transform="translate(0, 0)">
            <rect x="0" y="0" width="12" height="12" rx="2" fill="#475569" stroke="#64748b"/>
            <text x="18" y="10" fill="#94a3b8" font-size="11">3节薄壁套管 (0.3mm 304不锈钢/碳纤)</text>
          </g>
          <!-- 导引 2 -->
          <g transform="translate(260, 0)">
            <rect x="0" y="0" width="12" height="12" rx="2" fill="#fbbf24"/>
            <text x="18" y="10" fill="#94a3b8" font-size="11">0.1mm 内置恒力卷簧 (提供全行程 6N 恒拉力)</text>
          </g>
          <!-- 导引 3 -->
          <g transform="translate(540, 0)">
            <polygon points="0,12 6,0 12,12" fill="#38bdf8"/>
            <text x="18" y="10" fill="#94a3b8" font-size="11">双侧弹性自锁卡爪 (抗伞面张力与暴风压)</text>
          </g>
          <!-- 导引 4 -->
          <g transform="translate(790, 0)">
            <rect x="0" y="0" width="12" height="12" rx="2" fill="#f43f5e"/>
            <text x="18" y="10" fill="#94a3b8" font-size="11">中央推杆同步解锁</text>
          </g>
        </g>
      </svg>
    </div>
  </main>

  <!-- 底部操作与时序控制条 -->
  <footer>
    <div class="timeline-container">
      <span style="font-size: 11px; font-family: var(--font-mono); color: var(--text-muted);">进度</span>
      <input type="range" id="progressSlider" class="time-slider" min="0" max="1000" value="0">
      <span id="progressTime" style="font-size: 11px; font-family: var(--font-mono); color: var(--accent-cyan); min-width: 45px;">0.0s</span>
    </div>

    <div class="controls-row">
      <button id="btnPlayPause" class="btn active">
        <span id="playIcon">⏸</span>
        <span id="playText">自动演示中</span>
      </button>

      <div class="step-pill-group">
        <button class="step-pill active" onclick="seekToPhase(0)">1. 极限收拢 (20cm)</button>
        <button class="step-pill" onclick="seekToPhase(0.35)">2. 轴向抽出</button>
        <button class="step-pill" onclick="seekToPhase(0.55)">3. 卡爪自锁 (55cm)</button>
        <button class="step-pill" onclick="seekToPhase(0.72)">4. 触发展开/释放</button>
        <button class="step-pill" onclick="seekToPhase(0.88)">5. 卷簧自缩回</button>
      </div>

      <div style="display: flex; align-items: center; gap: 6px; margin-left: 8px;">
        <span style="color: var(--text-muted); font-size: 10px;">速度:</span>
        <button class="btn" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(0.5)">0.5x</button>
        <button class="btn active" id="spd1" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(1)">1.0x</button>
        <button class="btn" style="padding: 2px 7px; font-size: 10px;" onclick="setSpeed(1.8)">1.8x</button>
      </div>
    </div>
  </footer>

  <script>
    // --- 机械运动核心变量与时序参数 ---
    const TOTAL_DURATION = 9000; // 一个完整循环 9 秒
    let isPlaying = true;
    let animSpeed = 1.0;
    let startTime = performance.now();
    let currentProgress = 0; // 0.0 ~ 1.0

    // DOM 元素引用
    const midTube = document.getElementById('midTubeGroup');
    const innerTube = document.getElementById('innerTubeGroup');
    const springBelt = document.getElementById('springBelt');
    const springTexture = document.getElementById('springTexture');
    const pushRod = document.getElementById('pushRod');
    const releaseCollar = document.getElementById('releaseCollar');
    const dimLine = document.getElementById('dimLine');
    const dimTickEnd = document.getElementById('dimTickEnd');
    const dimBadge = document.getElementById('dimBadge');
    const dimText = document.getElementById('dimText');
    const lockH1 = document.getElementById('lockHighlight1');
    const lockH2 = document.getElementById('lockHighlight2');
    const forceVec = document.getElementById('forceVectorGroup');
    const vectorLine = document.getElementById('vectorLine');
    const vectorText = document.getElementById('vectorText');
    const pawl1U = document.getElementById('pawl1Upper');
    const pawl1L = document.getElementById('pawl1Lower');
    const pawl2U = document.getElementById('pawl2Upper');
    const pawl2L = document.getElementById('pawl2Lower');

    // HUD 读数
    const statusDot = document.getElementById('statusDot');
    const stateName = document.getElementById('stateName');
    const hudLength = document.getElementById('hudLength');
    const hudLock = document.getElementById('hudLock');
    const hudSpring = document.getElementById('hudSpring');
    const hudPusher = document.getElementById('hudPusher');

    // 联动小窗
    const miniCanopy = document.getElementById('miniCanopy');
    const miniRunner = document.getElementById('miniRunner');
    const miniStrutL = document.getElementById('miniStrutL');
    const miniStrutR = document.getElementById('miniStrutR');
    const miniRibL = document.getElementById('miniRibL');
    const miniRibR = document.getElementById('miniRibR');

    // 控制栏
    const slider = document.getElementById('progressSlider');
    const timeDisplay = document.getElementById('progressTime');
    const btnPlayPause = document.getElementById('btnPlayPause');
    const playIcon = document.getElementById('playIcon');
    const playText = document.getElementById('playText');
    const stepPills = document.querySelectorAll('.step-pill');

    // 最大物理像素位移 (对应 350mm 真实行程)
    const MAX_DISP_MID = 240;   // 中节滑出 240px (~175mm)
    const MAX_DISP_INNER = 480; // 内节总滑出 480px (~350mm)

    // 缓动函数
    function easeInOutQuad(t) {
      return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
    }
    function easeOutBack(t) {
      const c1 = 1.70158;
      const c3 = c1 + 1;
      return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
    }
    function easeInQuad(t) {
      return t * t;
    }

    // --- 主帧更新循环 ---
    function updatePhysics(progress) {
      currentProgress = progress;
      slider.value = Math.floor(progress * 1000);
      timeDisplay.textContent = ((progress * TOTAL_DURATION) / 1000).toFixed(1) + 's';

      // 阶段时序划分:
      // 0.00 - 0.15: 紧凑收纳状态展示 (总长 200mm)
      // 0.15 - 0.48: 上推展开,各节套管向右平滑抽出,恒力簧被拉开
      // 0.48 - 0.68: 卡爪弹入凹槽完全自锁,抵抗风压稳态 (总长 550mm)
      // 0.68 - 0.78: 按压中央释放环,推杆顶开卡爪解锁
      // 0.78 - 0.95: 恒力卷簧 6N 恒定自回缩,秒级缩回最短
      // 0.95 - 1.00: 循环缓冲复位

      let midX = 0;
      let innerX = 0;
      let collarX = 0;
      let rodStroke = 0;
      let isLocked = false;
      let isUnlocking = false;
      let isRetracting = false;

      if (progress <= 0.15) {
        // [阶段 1] 极致紧凑收拢
        midX = 0;
        innerX = 0;
        collarX = 0;
        stateName.textContent = "1. 极致紧凑收拢态 (骨长20cm/无冗余折段)";
        statusDot.className = "status-dot";
        hudLock.textContent = "解除锁定 / 自由";
        hudLock.style.color = "var(--text-muted)";
        hudPusher.textContent = "原位复位";
        updateActivePill(0);
      } 
      else if (progress > 0.15 && progress <= 0.48) {
        // [阶段 2] 轴向平稳抽出展开
        const p = (progress - 0.15) / 0.33;
        const eased = easeInOutQuad(p);
        midX = eased * MAX_DISP_MID;
        innerX = eased * MAX_DISP_INNER;
        stateName.textContent = "2. 上推轴向抽出 (套管逐节延伸/卷簧匀速储能)";
        statusDot.className = "status-dot";
        hudLock.textContent = "滑动到位中...";
        hudLock.style.color = "var(--accent-cyan)";
        hudPusher.textContent = "待命";
        updateActivePill(1);
      } 
      else if (progress > 0.48 && progress <= 0.68) {
        // [阶段 3] 自锁锁定,伞面饱满撑开
        midX = MAX_DISP_MID;
        innerX = MAX_DISP_INNER;
        isLocked = true;
        stateName.textContent = "3. 弹性卡爪弹入槽口自锁 (刚性抵抗风压与张力)";
        statusDot.className = "status-dot";
        hudLock.textContent = "双节全刚性自锁 ✓";
        hudLock.style.color = "var(--accent-emerald)";
        hudPusher.textContent = "锁定保持";
        updateActivePill(2);
      } 
      else if (progress > 0.68 && progress <= 0.78) {
        // [阶段 4] 释放环动作,推杆顶出解锁
        midX = MAX_DISP_MID;
        innerX = MAX_DISP_INNER;
        const p = (progress - 0.68) / 0.10;
        collarX = Math.sin(p * Math.PI) * 12; // 释放环按压行程 12px
        rodStroke = collarX;
        isUnlocking = true;
        stateName.textContent = "4. 伞柄释放环同步顶开卡爪 (释放自锁)";
        statusDot.className = "status-dot unlocking";
        hudLock.textContent = "卡爪脱出凹槽 ⚡";
        hudLock.style.color = "var(--accent-rose)";
        hudPusher.textContent = `行程 ${Math.round(collarX * 0.25 + 1)}mm (驱动中)`;
        updateActivePill(3);
      } 
      else if (progress > 0.78 && progress <= 0.95) {
        // [阶段 5] 卷簧 6N 恒定自动缩回
        const p = (progress - 0.78) / 0.17;
        const eased = 1 - easeInOutQuad(p);
        midX = eased * MAX_DISP_MID;
        innerX = eased * MAX_DISP_INNER;
        isRetracting = true;
        stateName.textContent = "5. 恒力卷簧 6N 恒定拉力瞬间自回缩";
        statusDot.className = "status-dot retracting";
        hudLock.textContent = "自动滑移归位";
        hudLock.style.color = "var(--accent-amber)";
        hudPusher.textContent = "自动复位";
        updateActivePill(4);
      } 
      else {
        // 缓冲复位
        midX = 0;
        innerX = 0;
        stateName.textContent = "1. 极致紧凑收拢态 (准备就绪)";
        statusDot.className = "status-dot";
        updateActivePill(0);
      }

      // --- SVG 主管段位移应用 ---
      midTube.setAttribute('transform', `translate(${midX}, 0)`);
      innerTube.setAttribute('transform', `translate(${innerX}, 0)`);
      releaseCollar.setAttribute('transform', `translate(${collarX}, 0)`);

      // 推杆联动
      pushRod.setAttribute('x1', 84 + collarX);
      pushRod.setAttribute('x2', 370 + (isUnlocking ? 20 : 0));

      // 恒力弹簧带长度更新 (卷筒中心固定在 148,锚定点随 innerX 移动)
      const springTipX = 426 + innerX;
      springBelt.setAttribute('x2', springTipX);
      springTexture.setAttribute('x2', springTipX);

      // 卡爪弹片微观开合动画
      if (isLocked) {
        // 弹入凹槽 (深扣)
        pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,222 L 24,222 L 24,243 Z');
        pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,298 L 24,298 L 24,277 Z');
        pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,233 L 20,233 L 20,250 Z');
        pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,287 L 20,287 L 20,270 Z');
        lockH1.setAttribute('opacity', '1');
        lockH2.setAttribute('opacity', '1');
      } else if (isUnlocking) {
        // 被推杆压平 (脱出槽口)
        pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,236 L 22,236 L 22,243 Z');
        pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,284 L 22,284 L 22,277 Z');
        pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,245 L 18,245 L 18,250 Z');
        pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,275 L 18,275 L 18,270 Z');
        lockH1.setAttribute('opacity', '0');
        lockH2.setAttribute('opacity', '0');
      } else {
        // 管内滑动平伏态
        pawl1U.setAttribute('d', 'M -10,243 Q 5,243 14,233 L 22,233 L 22,243 Z');
        pawl1L.setAttribute('d', 'M -10,277 Q 5,277 14,287 L 22,287 L 22,277 Z');
        pawl2U.setAttribute('d', 'M -10,250 Q 5,250 12,242 L 18,242 L 18,250 Z');
        pawl2L.setAttribute('d', 'M -10,270 Q 5,270 12,278 L 18,278 L 18,270 Z');
        lockH1.setAttribute('opacity', '0');
        lockH2.setAttribute('opacity', '0');
      }

      // 实时尺寸标尺更新 (从 200mm 到 550mm)
      const currentLengthMm = Math.round(200 + (innerX / MAX_DISP_INNER) * 350);
      const endPixelX = 390 + innerX;
      dimLine.setAttribute('x2', endPixelX);
      dimTickEnd.setAttribute('x1', endPixelX);
      dimTickEnd.setAttribute('x2', endPixelX);
      const badgeX = (130 + endPixelX) / 2 - 40;
      dimBadge.setAttribute('x', badgeX);
      dimText.setAttribute('x', badgeX + 40);
      dimText.textContent = `${currentLengthMm} mm`;
      hudLength.textContent = `${currentLengthMm} mm`;

      // 6N 恒力回缩矢量动态跟随末端
      forceVec.setAttribute('transform', `translate(${innerX}, 0)`);
      if (isRetracting) {
        forceVec.setAttribute('opacity', '1');
        vectorText.textContent = "F_spring = 6.0 N (正在高速回缩)";
      } else {
        forceVec.setAttribute('opacity', '0.7');
        vectorText.textContent = "F_spring = 6.0 N (恒力待命)";
      }

      // --- 右上角小伞联动形态更新 ---
      const expandRatio = innerX / MAX_DISP_INNER; // 0.0 ~ 1.0
      // 伞面展开几何计算
      const runnerY = 66 - expandRatio * 28; // 下巢向上滑动
      const canopyTipY = 48 + expandRatio * 6;
      const canopySpan = 15 + (1 - expandRatio) * 35; // 伞边宽度展开
      const ribTipLX = 60 - (45 * (0.35 + expandRatio * 0.65));
      const ribTipRX = 60 + (45 * (0.35 + expandRatio * 0.65));

      miniRunner.setAttribute('y', runnerY);
      miniRibL.setAttribute('x2', ribTipLX);
      miniRibL.setAttribute('y2', canopyTipY);
      miniRibR.setAttribute('x2', ribTipRX);
      miniRibR.setAttribute('y2', canopyTipY);

      miniStrutL.setAttribute('y1', runnerY + 2);
      miniStrutL.setAttribute('x2', 60 - 28 * expandRatio);
      miniStrutL.setAttribute('y2', 20 + 18 * expandRatio);

      miniStrutR.setAttribute('y1', runnerY + 2);
      miniStrutR.setAttribute('x2', 60 + 28 * expandRatio);
      miniStrutR.setAttribute('y2', 20 + 18 * expandRatio);

      const curveControlY = 10 - expandRatio * 4;
      miniCanopy.setAttribute('d', `M ${ribTipLX} ${canopyTipY} Q 60 ${curveControlY} ${ribTipRX} ${canopyTipY}`);
    }

    // 更新分相按钮高亮
    function updateActivePill(index) {
      stepPills.forEach((pill, idx) => {
        if (idx === index) pill.classList.add('active');
        else pill.classList.remove('active');
      });
    }

    // --- 动画主循环引擎 (自动播放 & 随时重开) ---
    function animationLoop(timestamp) {
      if (isPlaying) {
        const elapsed = (timestamp - startTime) * animSpeed;
        const progress = (elapsed % TOTAL_DURATION) / TOTAL_DURATION;
        updatePhysics(progress);
      }
      requestAnimationFrame(animationLoop);
    }

    // 交互控制:播放/暂停
    btnPlayPause.addEventListener('click', () => {
      isPlaying = !isPlaying;
      if (isPlaying) {
        startTime = performance.now() - (currentProgress * TOTAL_DURATION) / animSpeed;
        btnPlayPause.classList.add('active');
        playIcon.textContent = "⏸";
        playText.textContent = "自动演示中";
      } else {
        btnPlayPause.classList.remove('active');
        playIcon.textContent = "▶";
        playText.textContent = "已暂停";
      }
    });

    // 进度条手动拖动
    slider.addEventListener('input', (e) => {
      isPlaying = false;
      btnPlayPause.classList.remove('active');
      playIcon.textContent = "▶";
      playText.textContent = "手动单步";
      const progress = parseFloat(e.target.value) / 1000;
      updatePhysics(progress);
    });

    // 分相跳转
    window.seekToPhase = function(targetProgress) {
      isPlaying = false;
      btnPlayPause.classList.remove('active');
      playIcon.textContent = "▶";
      playText.textContent = "单步驻留";
      updatePhysics(targetProgress);
    };

    // 速度调节
    window.setSpeed = function(spd) {
      const now = performance.now();
      const currentElapsed = (now - startTime) * animSpeed;
      animSpeed = spd;
      startTime = now - (currentElapsed / animSpeed);
      document.querySelectorAll('.controls-row .btn').forEach(b => {
        if (b.textContent.includes(spd + 'x')) b.classList.add('active');
        else if (b.textContent.includes('x')) b.classList.remove('active');
      });
    };

    // 页面完全就绪与 iframe 重载时自动自启播放
    document.addEventListener('DOMContentLoaded', () => {
      startTime = performance.now();
      requestAnimationFrame(animationLoop);
    });

    window.addEventListener('pageshow', () => {
      startTime = performance.now();
      isPlaying = true;
    });
  </script>
</body>
</html>
积分规则:每轮对话扣10分