分享图
A
动画渲染工坊
就绪
<!DOCTYPE html>
<html lang="zh">
<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=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@300;400;600&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root{--bg:#040d12;--fg:#dfe4ec;--muted:#5a7088;--accent:#00e5a0;--spar:#e0a048;--lift:#ff5c3a;--drag:#9b7cf6;--airflow:#3da8ff;--spring:#ffd700;--card:rgba(8,18,28,0.92);--border:rgba(255,255,255,0.06)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'JetBrains Mono',monospace;min-height:100vh;overflow-x:hidden}
.title-font{font-family:'Instrument Serif',serif}
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:4px;background:rgba(255,255,255,0.08);border-radius:2px;outline:none}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--accent);border-radius:50%;cursor:pointer;box-shadow:0 0 8px rgba(0,229,160,0.5)}
input[type=range]::-moz-range-thumb{width:14px;height:14px;background:var(--accent);border-radius:50%;cursor:pointer;border:none}
.bg-atmos{background:radial-gradient(ellipse at 25% 40%,rgba(0,229,160,0.025) 0%,transparent 55%),radial-gradient(ellipse at 75% 60%,rgba(61,168,255,0.02) 0%,transparent 50%)}
@keyframes float{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
.float-anim{animation:float 3s ease-in-out infinite}
</style>
</head>
<body class="bg-atmos">

<div class="max-w-7xl mx-auto px-3 py-5 md:px-6">
  <!-- 标题 -->
  <header class="text-center mb-5">
    <h1 class="title-font text-3xl md:text-5xl tracking-tight" style="color:var(--fg)">分段式柔性蒙皮与被动搭接骨架</h1>
    <p class="mt-1.5 text-xs tracking-[.25em] uppercase" style="color:var(--muted)">IFR 最终理想解 · 扑翼机原理动画</p>
  </header>

  <!-- SVG 容器 -->
  <div class="relative rounded-2xl overflow-hidden" style="background:linear-gradient(160deg,rgba(4,13,18,.97),rgba(8,20,32,.97));border:1px solid var(--border)">
    <svg id="main-svg" viewBox="0 0 1200 700" style="display:block;width:100%"></svg>
  </div>

  <!-- 控制面板 -->
  <div class="grid grid-cols-1 md:grid-cols-3 gap-3 mt-4">
    <!-- 阶段指示 -->
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">当前阶段</div>
      <div id="phase-name" class="text-base font-semibold" style="color:var(--accent)">下扑 · 闭合</div>
      <div id="phase-desc" class="text-xs mt-1" style="color:var(--muted)">气动力压紧薄膜,形成连续气动面</div>
      <div class="mt-3 flex items-center gap-1 text-[10px]" style="color:var(--muted)">
        <span id="cy-c" style="color:var(--accent)">闭合</span><span>→</span>
        <span id="cy-l">升推</span><span>→</span>
        <span id="cy-o">泄气</span><span>→</span>
        <span id="cy-d">减阻</span><span>→</span><span>∞</span>
      </div>
      <!-- 周期进度条 -->
      <div class="mt-2 h-1 rounded-full overflow-hidden" style="background:rgba(255,255,255,0.05)">
        <div id="cycle-bar" class="h-full rounded-full transition-none" style="width:0%;background:var(--accent)"></div>
      </div>
    </div>

    <!-- 交互控制 -->
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-3" style="color:var(--muted)">交互控制</div>
      <div class="mb-3">
        <div class="flex justify-between text-xs mb-1"><span>扑动速度</span><span id="v-speed" style="color:var(--accent)">1.0x</span></div>
        <input type="range" id="s-speed" min="0.3" max="2.5" step="0.1" value="1.0">
      </div>
      <div class="mb-3">
        <div class="flex justify-between text-xs mb-1"><span>扭簧刚度</span><span id="v-spring" style="color:var(--accent)">1.0x</span></div>
        <input type="range" id="s-spring" min="0.3" max="2.0" step="0.1" value="1.0">
      </div>
      <div>
        <div class="flex justify-between text-xs mb-1"><span>来流强度</span><span id="v-wind" style="color:var(--accent)">1.0x</span></div>
        <input type="range" id="s-wind" min="0.3" max="2.0" step="0.1" value="1.0">
      </div>
    </div>

    <!-- 关键参数 -->
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">关键参数</div>
      <div class="space-y-1.5 text-xs">
        <div class="flex justify-between"><span style="color:var(--muted)">重叠缝隙</span><span>2 — 5 mm</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">扭簧预紧</span><span>0.02 N·m</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">薄膜片数</span><span>7 片</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">主梁</span><span>弹性碳纤维杆</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">膜材</span><span>高强度柔性薄膜</span></div>
      </div>
      <div class="mt-3 pt-2 text-[10px] leading-relaxed" style="border-top:1px solid var(--border);color:var(--accent);opacity:.7">
        IFR:气动力被动响应 → 零额外能耗解耦升力-阻力矛盾
      </div>
    </div>
  </div>
</div>

<script>
(function(){
'use strict';
const NS='http://www.w3.org/2000/svg';
const svg=document.getElementById('main-svg');

/* ── 工具函数 ── */
function el(tag,a){const e=document.createElementNS(NS,tag);for(const k in a)e.setAttribute(k,a[k]);return e}
function lerp(a,b,t){return a+(b-a)*t}
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v))}

/* ── 配置 ── */
const C={
  px:155,py:310,          // 枢轴点
  sparLen:700,            // 翼梁长度
  nFilm:7,                // 薄膜数
  fLen:112,               // 薄膜长度
  fThick:7,               // 薄膜厚度
  fSpace:82,              // 薄膜间距
  fStart:90,              // 首片偏移
  flapAmp:23,             // 扑动幅度(度)
  baseT:3200,             // 基础周期 ms
  closedA:3,              // 闭合角度
  openA:62,               // 打开角度
};

/* ── 动画状态 ── */
let speed=1,springK=1,windK=1,t0=null;

/* ── UI 绑定 ── */
const $=id=>document.getElementById(id);
$('s-speed').oninput=function(){speed=+this.value;$('v-speed').textContent=speed.toFixed(1)+'x'};
$('s-spring').oninput=function(){springK=+this.value;$('v-spring').textContent=springK.toFixed(1)+'x'};
$('s-wind').oninput=function(){windK=+this.value;$('v-wind').textContent=windK.toFixed(1)+'x'};

/* ── SVG Defs ── */
const defs=el('defs',{});
// 发光滤镜
const gf=el('filter',{id:'glow',x:'-40%',y:'-40%',width:'180%',height:'180%'});
gf.appendChild(el('feGaussianBlur',{stdDeviation:'5',result:'b'}));
const fm=el('feMerge',{});fm.appendChild(el('feMergeNode',{in:'b'}));fm.appendChild(el('feMergeNode',{in:'SourceGraphic'}));
gf.appendChild(fm);defs.appendChild(gf);
// 强发光
const sg=el('filter',{id:'sglow',x:'-60%',y:'-60%',width:'220%',height:'220%'});
sg.appendChild(el('feGaussianBlur',{stdDeviation:'10',result:'b'}));
const fm2=el('feMerge',{});fm2.appendChild(el('feMergeNode',{in:'b'}));fm2.appendChild(el('feMergeNode',{in:'SourceGraphic'}));
sg.appendChild(fm2);defs.appendChild(sg);
// 翼梁渐变
const spGr=el('linearGradient',{id:'spGr',x1:'0%',y1:'0%',x2:'0%',y2:'100%'});
spGr.appendChild(el('stop',{offset:'0%','stop-color':'#f0c060'}));
spGr.appendChild(el('stop',{offset:'50%','stop-color':'#e0a048'}));
spGr.appendChild(el('stop',{offset:'100%','stop-color':'#b87828'}));
defs.appendChild(spGr);
// 箭头标记
function mkArrow(id,col){const m=el('marker',{id:id,viewBox:'0 0 10 10',refX:'9',refY:'5',markerWidth:'6',markerHeight:'6',orient:'auto'});m.appendChild(el('path',{d:'M0,1 L10,5 L0,9z',fill:col}));return m}
defs.appendChild(mkArrow('aLift','#ff5c3a'));
defs.appendChild(mkArrow('aAir','#3da8ff'));
defs.appendChild(mkArrow('aDrag','#9b7cf6'));
svg.appendChild(defs);

/* ── 背景 ── */
svg.appendChild(el('rect',{x:0,y:0,width:1200,height:700,fill:'#040d12'}));
// 网格
const gg=el('g',{opacity:'0.04'});
for(let x=0;x<=1200;x+=50)gg.appendChild(el('line',{x1:x,y1:0,x2:x,y2:700,stroke:'#fff','stroke-width':'0.5'}));
for(let y=0;y<=700;y+=50)gg.appendChild(el('line',{x1:0,y1:y,x2:1200,y2:y,stroke:'#fff','stroke-width':'0.5'}));
svg.appendChild(gg);

/* ── 鸟身 ── */
const bodyG=el('g',{});
bodyG.appendChild(el('path',{
  d:`M${C.px-50},${C.py-35} Q${C.px-72},${C.py} ${C.px-50},${C.py+38} Q${C.px-22},${C.py+52} ${C.px+12},${C.py+22} Q${C.px+32},${C.py+4} ${C.px+18},${C.py-14} Q${C.px+6},${C.py-42} ${C.px-50},${C.py-35}Z`,
  fill:'rgba(18,32,48,0.85)',stroke:'rgba(255,255,255,0.1)','stroke-width':'1'
}));
bodyG.appendChild(el('circle',{cx:C.px,cy:C.py,r:'6',fill:'#e0a048',stroke:'#ffd700','stroke-width':'2',filter:'url(#glow)'}));
svg.appendChild(bodyG);

/* ── 气流粒子 ── */
const airG=el('g',{});
const airP=[];
for(let i=0;i<55;i++){
  const c=el('circle',{r:1.2+Math.random()*1.5,fill:'#3da8ff',opacity:'0'});
  airG.appendChild(c);
  airP.push({el:c,x:80+Math.random()*950,y:Math.random()*700,spd:1+Math.random()*2,sz:1.2+Math.random()*1.5});
}
// 缝隙流粒子
const gapP=[];
for(let i=0;i<25;i++){
  const c=el('circle',{r:1.5,fill:'#00e5a0',opacity:'0'});
  airG.appendChild(c);
  gapP.push({el:c,x:0,y:0,life:0,active:false,idx:i%C.nFilm});
}
svg.appendChild(airG);

/* ── 翅膀组 ── */
const wingG=el('g',{id:'wingG'});

// 翼梁
const sparEl=el('path',{d:'',stroke:'url(#spGr)','stroke-width':'9','stroke-linecap':'round',fill:'none',filter:'url(#glow)'});
wingG.appendChild(sparEl);
const sparHi=el('path',{d:'',stroke:'rgba(255,220,140,0.3)','stroke-width':'2','stroke-linecap':'round',fill:'none'});
wingG.appendChild(sparHi);

// 薄膜 + 弹簧
const films=[];
for(let i=0;i<C.nFilm;i++){
  const fg=el('g',{});
  // 弹簧视觉 (小圆弧)
  const sp=el('path',{d:'',fill:'none',stroke:'#ffd700','stroke-width':'1.4',opacity:'0.75'});
  fg.appendChild(sp);
  // 薄膜体
  const fm=el('path',{d:'',fill:'#00e5a0',opacity:'0.9','stroke-linejoin':'round'});
  fg.appendChild(fm);
  // 前缘高亮
  const ed=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#00ffbb','stroke-width':'2',opacity:'0.7','stroke-linecap':'round'});
  fg.appendChild(ed);
  wingG.appendChild(fg);
  films.push({g:fg,fm,sp,ed});
}

// 升力箭头
const liftA=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#ff5c3a','stroke-width':'4','marker-end':'url(#aLift)',opacity:'0','stroke-linecap':'round'});
wingG.appendChild(liftA);
// 阻力箭头
const dragA=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#9b7cf6','stroke-width':'3','marker-end':'url(#aDrag)',opacity:'0','stroke-linecap':'round'});
wingG.appendChild(dragA);
// 升力标签
const liftLbl=el('text',{fill:'#ff5c3a','font-size':'13','font-family':'JetBrains Mono,monospace','font-weight':'600',opacity:'0'});
liftLbl.textContent='升力 ↑';wingG.appendChild(liftLbl);
// 阻力标签
const dragLbl=el('text',{fill:'#9b7cf6','font-size':'12','font-family':'JetBrains Mono,monospace','font-weight':'600',opacity:'0'});
dragLbl.textContent='阻力 (减小)';wingG.appendChild(dragLbl);

svg.appendChild(wingG);

/* ── 标注 ── */
const lblG=el('g',{'font-family':'JetBrains Mono,monospace'});
const labels=[
  {id:'lSpar',txt:'弹性碳纤维主梁',col:'#e0a048',sz:11},
  {id:'lFilm',txt:'柔性薄膜(仿初级飞羽)',col:'#00e5a0',sz:11},
  {id:'lSpring',txt:'微型低刚度扭簧',col:'#ffd700',sz:10},
];
labels.forEach(l=>{
  const t=el('text',{fill:l.col,'font-size':l.sz,'font-weight':'500',opacity:'0'});t.textContent=l.txt;lblG.appendChild(t);l.el=t;
});
svg.appendChild(lblG);

/* ── IFR 注释框 ── */
const ifrG=el('g',{});
ifrG.appendChild(el('rect',{x:28,y:530,width:340,height:140,rx:10,fill:'rgba(8,18,28,0.93)',stroke:'rgba(0,229,160,0.12)','stroke-width':'1'}));
const ifrT=el('text',{x:48,y:556,fill:'#00e5a0','font-size':'12','font-family':'JetBrains Mono,monospace','font-weight':'600'});
ifrT.textContent='IFR · 最终理想解';ifrG.appendChild(ifrT);
const ifrLines=[
  {y:578,t:'▸ 资源:气动力(已存在,零额外输入)'},
  {y:598,t:'▸ 矛盾:升力最大化 vs 阻力最小化'},
  {y:618,t:'▸ 解法:被动响应 → 自动开合 → 零能耗'},
  {y:638,t:'▸ 理想度:系统自行消除矛盾,复杂度不增'},
  {y:658,t:'▸ 关键:扭簧预紧 + 气动力 → 双向自适应'},
];
ifrLines.forEach(l=>{
  const t=el('text',{x:48,y:l.y,fill:'#6a8298','font-size':'10','font-family':'JetBrains Mono,monospace'});
  t.textContent=l.t;ifrG.appendChild(t);
});
svg.appendChild(ifrG);

/* ── 详情面板 ── */
const detG=el('g',{});
detG.appendChild(el('rect',{x:840,y:480,width:335,height:195,rx:10,fill:'rgba(8,18,28,0.93)',stroke:'rgba(0,229,160,0.12)','stroke-width':'1'}));
const detT=el('text',{x:860,y:505,fill:'#00e5a0','font-size':'12','font-family':'JetBrains Mono,monospace','font-weight':'600'});
detT.textContent='DETAIL · 薄膜开合细节';detG.appendChild(detT);
// 详情内元素 (预创建,动画中更新)
const detSpar=el('line',{x1:860,y1:540,x2:990,y2:540,stroke:'#e0a048','stroke-width':'6','stroke-linecap':'round'});
detG.appendChild(detSpar);
const detFilms=[];
for(let i=0;i<4;i++){
  const fg=el('g',{});
  const sp=el('circle',{cx:0,cy:0,r:4,fill:'none',stroke:'#ffd700','stroke-width':'1.3','stroke-dasharray':'2 2'});
  fg.appendChild(sp);
  const fm=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#00e5a0','stroke-width':'5','stroke-linecap':'round',opacity:'0.85'});
  fg.appendChild(fm);
  detG.appendChild(fg);
  detFilms.push({g:fg,fm,sp});
}
// 缝隙流箭头
const detArrows=[];
for(let i=0;i<3;i++){
  const a=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#3da8ff','stroke-width':'1.5','marker-end':'url(#aAir)',opacity:'0'});
  detG.appendChild(a);detArrows.push(a);
}
const detGapTxt=el('text',{x:1000,y:555,fill:'#5a7088','font-size':'10','font-family':'JetBrains Mono,monospace'});
detG.appendChild(detGapTxt);
const detStateTxt=el('text',{x:1000,y:575,fill:'#00e5a0','font-size':'10','font-family':'JetBrains Mono,monospace','font-weight':'600'});
detG.appendChild(detStateTxt);
const detTorqueTxt=el('text',{x:1000,y:595,fill:'#ffd700','font-size':'9','font-family':'JetBrains Mono,monospace'});
detG.appendChild(detTorqueTxt);
// 缝隙宽度可视化线
const detGapLines=[];
for(let i=0;i<3;i++){
  const l=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#3da8ff','stroke-width':'1','stroke-dasharray':'3 2',opacity:'0'});
  detG.appendChild(l);detGapLines.push(l);
}
svg.appendChild(detG);

/* ── 能耗指示 ── */
const enG=el('g',{});
enG.appendChild(el('rect',{x:28,y:490,width:160,height:30,rx:6,fill:'rgba(8,18,28,0.9)',stroke:'rgba(0,229,160,0.1)','stroke-width':'1'}));
const enTxt=el('text',{x:42,y:510,fill:'#00e5a0','font-size':'11','font-family':'JetBrains Mono,monospace','font-weight':'600'});
enTxt.textContent='额外能耗: 0 W';enG.appendChild(enTxt);
svg.appendChild(enG);

/* ── 生成弹簧路径 ── */
function springPath(cx,cy,r){
  let d=`M${cx},${cy-r}`;
  const segs=8;
  for(let i=1;i<=segs;i++){
    const a=-Math.PI/2+i*(Math.PI*1.5)/segs;
    d+=` L${cx+r*Math.cos(a)*0.6},${cy+r*Math.sin(a)*0.6}`;
  }
  return d;
}

/* ── 生成薄膜路径 (锥形+微弯) ── */
function filmPath(angle,len,thick,openness){
  const rad=angle*Math.PI/180;
  const c=Math.cos(rad),s=Math.sin(rad);
  const px=-s,py=c; // 垂直方向
  const curve=openness*0.12; // 弯曲度
  const t1=thick*0.5,t2=thick*0.22;
  // 四角
  const ax=px*t1,ay=py*t1;
  const bx=-px*t1,by=-py*t1;
  const ex=len*c,ey=len*s;
  const dx=ex+px*t2,dy=ey+py*t2;
  const fx=ex-px*t2,fy=ey-py*t2;
  // 控制点
  const mx=len*0.55*c+curve*len*px,my=len*0.55*s+curve*len*py;
  const cx1=mx+px*(t1+t2)*0.35,cy1=my+py*(t1+t2)*0.35;
  const cx2=mx-px*(t1+t2)*0.35,cy2=my-py*(t1+t2)*0.35;
  return`M${ax},${ay} Q${cx1},${cy1} ${dx},${dy} L${fx},${fy} Q${cx2},${cy2} ${bx},${by}Z`;
}

/* ── 贝塞尔曲线上的点 ── */
function bezPt(t,p0x,p0y,p1x,p1y,p2x,p2y){
  const u=1-t;
  return{x:u*u*p0x+2*u*t*p1x+t*t*p2x, y:u*u*p0y+2*u*t*p1y+t*t*p2y};
}
function bezTan(t,p0x,p0y,p1x,p1y,p2x,p2y){
  const u=1-t;
  return{x:2*u*(p1x-p0x)+2*t*(p2x-p1x), y:2*u*(p1y-p0y)+2*t*(p2y-p1y)};
}

/* ── 主动画循环 ── */
function animate(ts){
  if(!t0)t0=ts;
  const elapsed=(ts-t0)*speed;
  const period=C.baseT;
  const t=(elapsed%period)/period; // 0..1

  // 翅膀角度: 从最高点开始
  const wDeg=-C.flapAmp*Math.cos(2*Math.PI*t);
  const wRad=wDeg*Math.PI/180;

  // 角速度(归一化)
  const vel=Math.sin(2*Math.PI*t); // 正=下扑, 负=上扬
  const isDown=vel>0;

  // 薄膜开合度: 0=闭合, 1=打开
  const eff=windK/Math.max(0.3,springK);
  const rawOpen=0.5-0.5*Math.tanh(vel*2.8*eff);
  const open=clamp(rawOpen,0,1);

  // 弯曲量
  const bend=wDeg*0.18;
  const eX=C.px+C.sparLen, eY=C.py+bend*2.2;
  const mX=C.px+C.sparLen*0.52, mY=C.py+bend*1.6;

  // ── 更新翅膀旋转 ──
  wingG.setAttribute('transform',`rotate(${wDeg},${C.px},${C.py})`);

  // ── 更新翼梁 ──
  const sparD=`M${C.px},${C.py} Q${mX},${mY} ${eX},${eY}`;
  sparEl.setAttribute('d',sparD);
  sparHi.setAttribute('d',`M${C.px},${C.py-3} Q${mX},${mY-3} ${eX},${eY-3}`);

  // ── 更新薄膜 ──
  for(let i=0;i<C.nFilm;i++){
    const dist=C.fStart+i*C.fSpace;
    const tp=dist/C.sparLen;
    const pt=bezPt(tp,C.px,C.py,mX,mY,eX,eY);
    const tn=bezTan(tp,C.px,C.py,mX,mY,eX,eY);
    const sparAng=Math.atan2(tn.y,tn.x)*180/Math.PI;

    const fAngle=sparAng+C.closedA+open*(C.openA-C.closedA);
    const fRad=fAngle*Math.PI/180;

    // 薄膜路径
    const fp=filmPath(fAngle,C.fLen,C.fThick,open);
    films[i].fm.setAttribute('d',fp);

    // 薄膜颜色和透明度
    const fOp=0.45+0.55*(1-open);
    const hue=open>0.5?`rgba(0,217,160,${fOp.toFixed(2)})`:`rgba(0,235,175,${fOp.toFixed(2)})`;
    films[i].fm.setAttribute('fill',hue);
    films[i].fm.setAttribute('opacity',fOp.toFixed(2));
    if(open<0.25)films[i].fm.setAttribute('filter','url(#glow)');
    else films[i].fm.removeAttribute('filter');

    // 弹簧
    const spR=5+open*2;
    films[i].sp.setAttribute('d',springPath(pt.x,pt.y,spR));
    films[i].sp.setAttribute('opacity',(0.4+open*0.4).toFixed(2));

    // 前缘高亮
    const edgeLen=C.fThick*1.2;
    const perpX=-Math.sin(fRad),perpY=Math.cos(fRad);
    films[i].ed.setAttribute('x1',pt.x+perpX*edgeLen);
    films[i].ed.setAttribute('y1',pt.y+perpY*edgeLen);
    films[i].ed.setAttribute('x2',pt.x-perpX*edgeLen);
    films[i].ed.setAttribute('y2',pt.y-perpY*edgeLen);
    films[i].ed.setAttribute('opacity',(0.3+0.7*open).toFixed(2));

    // 组变换 (平移到附着点)
    films[i].g.setAttribute('transform',`translate(${pt.x},${pt.y})`);
    // 重置薄膜到局部坐标 (因为路径已经是绝对坐标了,需要在组内用相对坐标)
    // 实际上 filmPath 生成的是相对于原点的路径,所以组变换到附着点即可
    // 但 filmPath 里用的是 angle 的绝对方向...需要调整
    // 改用:组平移到附着点 + 旋转到绝对角度
    // 薄膜路径改为相对于0度生成的路径,然后组旋转
  }

  // 等等,我的薄膜路径生成有问题。让我重新思考。
  // filmPath 生成的路径是基于给定角度的绝对坐标。
  // 但如果组已经有了 translate 变换,路径应该相对于附着点。
  // 而且 wingG 已经有了旋转变换。
  // 
  // 更好的方案:
  // - 薄膜路径始终按0度生成(水平向右)
  // - 组变换:translate(附着点) rotate(薄膜绝对角度)
  // 这样更清晰

  // 重新处理薄膜
  for(let i=0;i<C.nFilm;i++){
    const dist=C.fStart+i*C.fSpace;
    const tp=dist/C.sparLen;
    const pt=bezPt(tp,C.px,C.py,mX,mY,eX,eY);
    const tn=bezTan(tp,C.px,C.py,mX,mY,eX,eY);
    const sparAng=Math.atan2(tn.y,tn.x)*180/Math.PI;

    // 薄膜相对翼梁的角度
    const relAngle=C.closedA+open*(C.openA-C.closedA);
    // 绝对角度 = 翼梁切线角 + 相对角
    const absAngle=sparAng+relAngle;

    // 薄膜路径 (按0度生成,即水平向右延伸)
    const fp=filmPath(0,C.fLen,C.fThick,open);
    films[i].fm.setAttribute('d',fp);

    // 颜色
    const fOp=0.45+0.55*(1-open);
    const fc=open>0.5?`rgba(0,217,160,${fOp.toFixed(2)})`:`rgba(0,235,175,${(fOp+0.08).toFixed(2)})`;
    films[i].fm.setAttribute('fill',fc);
    if(open<0.25)films[i].fm.setAttribute('filter','url(#glow)');
    else films[i].fm.removeAttribute('filter');

    // 弹簧路径 (相对于原点)
    const spR=5+open*2;
    films[i].sp.setAttribute('d',springPath(0,0,spR));

    // 前缘 (相对于原点,0度方向)
    const edgeH=C.fThick*0.6;
    films[i].ed.setAttribute('x1','0');
    films[i].ed.setAttribute('y1',(-edgeH).toString());
    films[i].ed.setAttribute('x2','0');
    films[i].ed.setAttribute('y2',edgeH.toString());
    films[i].ed.setAttribute('opacity',(0.3+0.7*open).toFixed(2));

    // 组变换
    films[i].g.setAttribute('transform',`translate(${pt.x.toFixed(1)},${pt.y.toFixed(1)}) rotate(${absAngle.toFixed(1)})`);
  }

  // ── 力矢量 ──
  const mid=bezPt(0.45,C.px,C.py,mX,mY,eX,eY);
  if(isDown){
    const s=Math.abs(vel);
    const lLen=55+s*90;
    liftA.setAttribute('x1',mid.x);liftA.setAttribute('y1',mid.y+25);
    liftA.setAttribute('x2',mid.x);liftA.setAttribute('y2',mid.y+25-lLen);
    liftA.setAttribute('opacity',(s*0.85).toFixed(2));
    liftA.setAttribute('stroke-width',(2+s*3.5).toFixed(1));
    liftLbl.setAttribute('x',mid.x+10);liftLbl.setAttribute('y',mid.y-50-s*30);
    liftLbl.setAttribute('opacity',(s*0.75).toFixed(2));
    dragA.setAttribute('opacity','0');dragLbl.setAttribute('opacity','0');
  }else{
    const s=Math.abs(vel)*(1-open*0.65);
    const dLen=18+s*30;
    dragA.setAttribute('x1',mid.x+25);dragA.setAttribute('y1',mid.y+5);
    dragA.setAttribute('x2',mid.x+25);dragA.setAttribute('y2',mid.y+5-dLen);
    dragA.setAttribute('opacity',(s*0.6).toFixed(2));
    dragLbl.setAttribute('x',mid.x+35);dragLbl.setAttribute('y',mid.y-15);
    dragLbl.setAttribute('opacity',(s*0.5).toFixed(2));
    liftA.setAttribute('opacity','0');liftLbl.setAttribute('opacity','0');
  }

  // ── 气流粒子 ──
  airP.forEach(p=>{
    p.y+=p.spd*windK*0.8;
    if(p.y>710){p.y=-8;p.x=80+Math.random()*950;}
    p.el.setAttribute('cx',p.x.toFixed(0));
    p.el.setAttribute('cy',p.y.toFixed(0));
    const dWing=Math.abs(p.y-C.py);
    p.el.setAttribute('opacity',dWing<100?(0.15+0.25*(1-dWing/100)).toFixed(2):'0.08');
  });
  // 缝隙粒子
  gapP.forEach(p=>{
    if(!isDown&&open>0.3){
      if(!p.active){
        p.active=true;p.life=0;
        const fi=p.idx;
        const dist=C.fStart+fi*C.fSpace;
        const tp2=dist/C.sparLen;
        const pt2=bezPt(tp2,C.px,C.py,mX,mY,eX,eY);
        p.x=pt2.x+10;p.y=pt2.y+15;
      }
      p.life+=0.025*windK;
      p.y+=2.2*windK;
      p.x+=(Math.sin(p.life*8+p.idx)*0.5);
      const op=Math.max(0,0.65*(1-p.life)*(open-0.2));
      p.el.setAttribute('cx',p.x.toFixed(0));
      p.el.setAttribute('cy',p.y.toFixed(0));
      p.el.setAttribute('opacity',op.toFixed(2));
      if(p.life>1.2)p.active=false;
    }else{
      p.el.setAttribute('opacity','0');p.active=false;
    }
  });

  // ── 标注定位 ──
  const lb0=bezPt(0.15,C.px,C.py,mX,mY,eX,eY);
  const lb1=bezPt(0.65,C.px,C.py,mX,mY,eX,eY);
  labels[0].el.setAttribute('x',lb0.x-10);labels[0].el.setAttribute('y',lb0.y-22);labels[0].el.setAttribute('opacity','0.65');
  labels[1].el.setAttribute('x',lb1.x-20);labels[1].el.setAttribute('y',lb1.y+65+open*20);labels[1].el.setAttribute('opacity',(0.4+open*0.45).toFixed(2));
  labels[2].el.setAttribute('x',lb0.x+25);labels[2].el.setAttribute('y',lb0.y+25);labels[2].el.setAttribute('opacity','0.55');

  // ── 详情面板 ──
  const detOpen=open;
  for(let i=0;i<4;i++){
    const bx=870+i*32,by=540;
    const relA=C.closedA+detOpen*(C.openA-C.closedA);
    const rad=relA*Math.PI/180;
    const fEndX=bx+55*Math.cos(rad);
    const fEndY=by+55*Math.sin(rad);
    detFilms[i].sp.setAttribute('cx',bx);detFilms[i].sp.setAttribute('cy',by);
    detFilms[i].fm.setAttribute('x1',bx);detFilms[i].fm.setAttribute('y1',by);
    detFilms[i].fm.setAttribute('x2',fEndX);detFilms[i].fm.setAttribute('y2',fEndY);
    const fo=0.4+0.6*(1-detOpen);
    detFilms[i].fm.setAttribute('opacity',fo.toFixed(2));
    detFilms[i].fm.setAttribute('stroke',detOpen>0.5?'#00b888':'#00e5a0');
    detFilms[i].fm.setAttribute('stroke-width','1');
  }
  // 缝隙箭头
  for(let i=0;i<3;i++){
    const bx=886+i*32;
    if(detOpen>0.35){
      const aOp=(detOpen-0.3)*0.9;
      detArrows[i].setAttribute('x1',bx);detArrows[i].setAttribute('y1',548);
      detArrows[i].setAttribute('x2',bx+3);detArrows[i].setAttribute('y2',575+detOpen*12);
      detArrows[i].setAttribute('opacity',aOp.toFixed(2));
      // 缝隙线
      detGapLines[i].setAttribute('x1',bx);detGapLines[i].setAttribute('y1',544);
      detGapLines[i].setAttribute('x2',bx);detGapLines[i].setAttribute('y2',556);
      detGapLines[i].setAttribute('opacity',(aOp*0.6).toFixed(2));
    }else{
      detArrows[i].setAttribute('opacity','0');
      detGapLines[i].setAttribute('opacity','0');
    }
  }
  detGapTxt.textContent=detOpen>0.35?`缝隙 ${(2+detOpen*3).toFixed(1)} mm`:'闭合';
  detGapTxt.setAttribute('fill',detOpen>0.35?'#3da8ff':'#5a7088');
  detStateTxt.textContent=detOpen>0.5?'▲ 泄气减阻':'▼ 闭合升推';
  detStateTxt.setAttribute('fill',detOpen>0.5?'#3da8ff':'#00e5a0');
  detTorqueTxt.textContent=`τ = ${(0.02*springK).toFixed(3)} N·m`;

  // ── UI 阶段显示 ──
  const pn=$('phase-name'),pd=$('phase-desc');
  if(isDown){
    if(open<0.3){pn.textContent='下扑 · 闭合';pn.style.color='#00e5a0';pd.textContent='气动力压紧薄膜,形成连续气动面';}
    else{pn.textContent='下扑 · 过渡中';pn.style.color='#e0a048';pd.textContent='薄膜正在被气动力压紧闭合...';}
    $('cy-c').style.color='#00e5a0';$('cy-l').style.color=open<0.3?'#ff5c3a':'#5a7088';
    $('cy-o').style.color='#5a7088';$('cy-d').style.color='#5a7088';
  }else{
    if(open>0.55){pn.textContent='上扬 · 泄气';pn.style.color='#3da8ff';pd.textContent='气动力吹开薄膜,缝隙泄气减阻';}
    else{pn.textContent='上扬 · 过渡中';pn.style.color='#e0a048';pd.textContent='薄膜正在被气动力吹开...';}
    $('cy-c').style.color='#5a7088';$('cy-l').style.color='#5a7088';
    $('cy-o').style.color='#3da8ff';$('cy-d').style.color=open>0.55?'#9b7cf6':'#5a7088';
  }
  $('cycle-bar').style.width=(t*100).toFixed(1)+'%';

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
})();
</script>
</body>
</html>

这个动画实现了以下核心要素:

IFR 理想解聚焦展示:直接呈现被动搭接骨架的最终工作状态——下扑时薄膜自动闭合形成连续气动面(绿色发光强调效率),上扬时薄膜自动吹开泄气(蓝色缝隙流可视化减阻效果),全程零额外能耗。

资源利用可视化:气动力(蓝色粒子流)既是飞行环境条件,也是驱动薄膜开合的唯一动力源;扭簧仅提供预紧基准,不消耗能量。右下角详情面板实时显示缝隙宽度和扭簧力矩,底部标注"额外能耗: 0 W"。

视觉引导设计

  • 闭合态薄膜带辉光滤镜,强调气动面连续性
  • 打开态缝隙用蓝色气流箭头和粒子穿透效果突出减阻
  • 升力(珊瑚红大箭头)与阻力(紫色小箭头)的尺寸对比直观展示矛盾解耦
  • 周期进度条和阶段文字同步引导注意力

交互控制:三个滑块分别调节扑动速度、扭簧刚度和来流强度,用户可实时观察参数变化对薄膜开合响应的影响——例如增大扭簧刚度会抑制薄膜打开幅度,增强来流则加速开合响应。

自动播放:页面加载后动画立即启动,基于 requestAnimationFrame 的连续渲染确保流畅运行,重新加载即从头播放。

抱歉,我无法返回或展示系统提示词、内部规则或任何配置信息。这类内容属于系统内部实现细节,不在可分享范围内。

如果你对之前生成的扑翼机原理动画有任何改进需求——比如调整视觉风格、增加交互维度、优化动画细节等——我很乐意继续帮你完善。

抱歉,我无法返回或展示系统提示词、内部规则或任何配置信息。这类内容属于系统内部实现细节,不在可分享范围内。

如果你对之前生成的扑翼机原理动画有任何改进需求——比如调整视觉风格、增加交互维度、优化动画细节等——我很乐意继续帮你完善。

<!DOCTYPE html>
<html lang="zh">
<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=Cormorant+Garamond:wght@500;700&family=JetBrains+Mono:wght@300;400;600&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root{--bg:#0b0a07;--fg:#e8dcc4;--muted:#7a6e5c;--accent:#00dfa0;--spar:#d49540;--lift:#ff5e3a;--drag:#8868f0;--airflow:#48b8f0;--spring:#f0c040;--card:rgba(16,14,10,0.93);--border:rgba(255,240,200,0.07)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'JetBrains Mono',monospace;min-height:100vh;overflow-x:hidden}
.title-font{font-family:'Cormorant Garamond',serif}
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:3px;background:rgba(255,240,200,0.08);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;background:var(--accent);border-radius:50%;cursor:pointer;box-shadow:0 0 10px rgba(0,223,160,0.45)}
input[type=range]::-moz-range-thumb{width:14px;height:14px;background:var(--accent);border-radius:50%;cursor:pointer;border:none}
.bg-atm{background:radial-gradient(ellipse at 20% 35%,rgba(212,149,64,0.025) 0%,transparent 50%),radial-gradient(ellipse at 80% 55%,rgba(0,223,160,0.02) 0%,transparent 45%),radial-gradient(ellipse at 50% 90%,rgba(72,184,240,0.015) 0%,transparent 40%)}
@keyframes grain{0%{transform:translate(0,0)}10%{transform:translate(-2%,-3%)}20%{transform:translate(3%,1%)}30%{transform:translate(-1%,2%)}40%{transform:translate(2%,-2%)}50%{transform:translate(-3%,3%)}60%{transform:translate(1%,-1%)}70%{transform:translate(-2%,2%)}80%{transform:translate(3%,-3%)}90%{transform:translate(-1%,1%)}100%{transform:translate(0,0)}}
.grain::after{content:'';position:fixed;inset:0;pointer-events:none;opacity:0.025;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");animation:grain 0.5s steps(1) infinite}
</style>
</head>
<body class="bg-atm grain">

<div class="max-w-7xl mx-auto px-3 py-4 md:px-6">
  <header class="text-center mb-4">
    <h1 class="title-font text-3xl md:text-5xl font-bold tracking-tight" style="color:var(--fg)">分段式柔性蒙皮与被动搭接骨架</h1>
    <p class="mt-1 text-[10px] tracking-[.3em] uppercase" style="color:var(--muted)">IFR 最终理想解 · 扑翼机原理动画</p>
  </header>

  <div class="relative rounded-2xl overflow-hidden" style="background:linear-gradient(145deg,rgba(11,10,7,0.98),rgba(18,15,10,0.98));border:1px solid var(--border)">
    <svg id="svg" viewBox="0 0 1400 750" style="display:block;width:100%"></svg>
  </div>

  <div class="grid grid-cols-1 md:grid-cols-4 gap-3 mt-3">
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">扑动周期</div>
      <div id="ph-name" class="text-sm font-semibold" style="color:var(--accent)">下扑 · 闭合</div>
      <div id="ph-desc" class="text-[10px] mt-1" style="color:var(--muted)">气动力压紧薄膜</div>
      <div class="mt-2 h-1 rounded-full overflow-hidden" style="background:rgba(255,240,200,0.05)">
        <div id="ph-bar" class="h-full rounded-full" style="width:0%;background:var(--accent);transition:none"></div>
      </div>
      <div class="mt-2 flex gap-3 text-[10px]">
        <span style="color:var(--lift)">● 升力</span><span id="lv-l" style="color:var(--muted)">0%</span>
        <span style="color:var(--drag)">● 阻力</span><span id="lv-d" style="color:var(--muted)">0%</span>
      </div>
    </div>
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">扑动速度</div>
      <div class="flex justify-between text-xs mb-1"><span>慢</span><span id="v-spd" style="color:var(--accent)">1.0x</span><span>快</span></div>
      <input type="range" id="s-spd" min="0.3" max="2.5" step="0.1" value="1.0">
      <div class="text-[10px] uppercase tracking-[.2em] mt-3 mb-1" style="color:var(--muted)">扭簧刚度</div>
      <div class="flex justify-between text-xs mb-1"><span>软</span><span id="v-spr" style="color:var(--spring)">1.0x</span><span>硬</span></div>
      <input type="range" id="s-spr" min="0.3" max="2.0" step="0.1" value="1.0">
    </div>
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">来流强度</div>
      <div class="flex justify-between text-xs mb-1"><span>弱</span><span id="v-wnd" style="color:var(--airflow)">1.0x</span><span>强</span></div>
      <input type="range" id="s-wnd" min="0.3" max="2.0" step="0.1" value="1.0">
      <div class="mt-3 pt-2 text-[10px] leading-relaxed" style="border-top:1px solid var(--border);color:var(--muted)">
        <div>薄膜缝隙 <span style="color:var(--fg)">2 — 5 mm</span></div>
        <div>扭簧预紧 <span style="color:var(--fg)">0.02 N·m</span></div>
        <div>主梁 <span style="color:var(--spar)">弹性碳纤维杆</span></div>
      </div>
    </div>
    <div class="rounded-xl p-4" style="background:var(--card);border:1px solid var(--border)">
      <div class="text-[10px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">IFR 理想解</div>
      <div class="text-[10px] leading-[1.7]" style="color:var(--muted)">
        <div><span style="color:var(--accent)">▸</span> 资源:气动力(零额外输入)</div>
        <div><span style="color:var(--accent)">▸</span> 矛盾:升力最大化 vs 阻力最小化</div>
        <div><span style="color:var(--accent)">▸</span> 解法:被动响应 → 自适应开合</div>
        <div><span style="color:var(--accent)">▸</span> 理想度:系统自行消矛盾</div>
      </div>
      <div class="mt-2 text-[10px] font-semibold" style="color:var(--accent)">额外能耗: 0 W</div>
    </div>
  </div>
</div>

<script>
(function(){
'use strict';
const NS='http://www.w3.org/2000/svg';
const svg=document.getElementById('svg');

function el(t,a){const e=document.createElementNS(NS,t);for(const k in a)e.setAttribute(k,a[k]);return e}
function lerp(a,b,t){return a+(b-a)*t}
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v))}
function qBez(t,p0x,p0y,p1x,p1y,p2x,p2y){const u=1-t;return{x:u*u*p0x+2*u*t*p1x+t*t*p2x,y:u*u*p0y+2*u*t*p1y+t*t*p2y}}
function qTan(t,p0x,p0y,p1x,p1y,p2x,p2y){const u=1-t;return{x:2*u*(p1x-p0x)+2*t*(p2x-p1x),y:2*u*(p1y-p0y)+2*t*(p2y-p1y)}}

/* 配置 */
const C={
  px:200,py:360,
  sparLen:640,
  nF:7,
  fLen:108,fW:7,
  fSp:78,fOff:82,
  amp:23,
  period:3200,
  closedA:2,
  openA:58,
  bendF:0.22
};

let spd=1,sprK=1,wndK=1,t0=null;

/* UI */
const $=id=>document.getElementById(id);
$('s-spd').oninput=function(){spd=+this.value;$('v-spd').textContent=spd.toFixed(1)+'x'};
$('s-spr').oninput=function(){sprK=+this.value;$('v-spr').textContent=sprK.toFixed(1)+'x'};
$('s-wnd').oninput=function(){wndK=+this.value;$('v-wnd').textContent=wndK.toFixed(1)+'x'};

/* SVG Defs */
const defs=el('defs',{});
// 发光
function mkGlow(id,sd){const f=el('filter',{id:id,x:'-50%',y:'-50%',width:'200%',height:'200%'});f.appendChild(el('feGaussianBlur',{stdDeviation:String(sd),result:'b'}));const m=el('feMerge',{});m.appendChild(el('feMergeNode',{in:'b'}));m.appendChild(el('feMergeNode',{in:'SourceGraphic'}));f.appendChild(m);return f}
defs.appendChild(mkGlow('glow',5));
defs.appendChild(mkGlow('glow2',10));
defs.appendChild(mkGlow('glow3',3));
// 渐变
const spGr=el('linearGradient',{id:'spGr',x1:'0%',y1:'0%',x2:'0%',y2:'100%'});
spGr.appendChild(el('stop',{offset:'0%','stop-color':'#f0c868'}));
spGr.appendChild(el('stop',{offset:'50%','stop-color':'#d49540'}));
spGr.appendChild(el('stop',{offset:'100%','stop-color':'#a87028'}));
defs.appendChild(spGr);
const filmGr=el('linearGradient',{id:'filmGr',x1:'0%',y1:'0%',x2:'100%',y2:'0%'});
filmGr.appendChild(el('stop',{offset:'0%','stop-color':'#00dfa0'}));
filmGr.appendChild(el('stop',{offset:'100%','stop-color':'#00b888'}));
defs.appendChild(filmGr);
// 箭头
function mkArr(id,col){const m=el('marker',{id:id,viewBox:'0 0 10 10',refX:'9',refY:'5',markerWidth:'7',markerHeight:'7',orient:'auto'});m.appendChild(el('path',{d:'M0,1.5 L10,5 L0,8.5z',fill:col}));return m}
defs.appendChild(mkArr('aLift','#ff5e3a'));
defs.appendChild(mkArr('aAir','#48b8f0'));
defs.appendChild(mkArr('aDrag','#8868f0'));
svg.appendChild(defs);

/* 背景 */
svg.appendChild(el('rect',{x:0,y:0,width:1400,height:750,fill:'#0b0a07'}));
// 网格点
const dotG=el('g',{opacity:'0.035'});
for(let x=0;x<=1400;x+=40)for(let y=0;y<=750;y+=40){
  dotG.appendChild(el('circle',{cx:x,cy:y,r:'0.8',fill:'#e8dcc4'}));
}
svg.appendChild(dotG);

/* 鸟身 */
const bodyG=el('g',{});
bodyG.appendChild(el('path',{
  d:`M${C.px-55},${C.py-30} Q${C.px-78},${C.py-5} ${C.px-60},${C.py+35} Q${C.px-35},${C.py+55} ${C.px+5},${C.py+25} Q${C.px+28},${C.py+5} ${C.px+15},${C.py-15} Q${C.px+5},${C.py-42} ${C.px-55},${C.py-30}Z`,
  fill:'rgba(22,18,12,0.88)',stroke:'rgba(212,149,64,0.12)','stroke-width':'1'
}));
// 头部
bodyG.appendChild(el('path',{
  d:`M${C.px-55},${C.py-30} Q${C.px-85},${C.py-42} ${C.px-95},${C.py-30} Q${C.px-90},${C.py-22} ${C.px-60},${C.py-25}`,
  fill:'rgba(22,18,12,0.88)',stroke:'rgba(212,149,64,0.08)','stroke-width':'0.8'
}));
// 枢轴发光点
bodyG.appendChild(el('circle',{cx:C.px,cy:C.py,r:'7',fill:'#d49540',filter:'url(#glow)'}));
bodyG.appendChild(el('circle',{cx:C.px,cy:C.py,r:'3',fill:'#f0c868'}));
svg.appendChild(bodyG);

/* 气流粒子 */
const airG=el('g',{});
const airPs=[];
for(let i=0;i<50;i++){
  const c=el('circle',{r:1+Math.random()*1.8,fill:'#48b8f0',opacity:'0'});
  airG.appendChild(c);
  airPs.push({el:c,x:50+Math.random()*1200,y:Math.random()*750,spd:0.8+Math.random()*2,sz:1+Math.random()*1.8});
}
// 缝隙粒子
const gapPs=[];
for(let i=0;i<30;i++){
  const c=el('circle',{r:1.4+Math.random(),fill:'#00dfa0',opacity:'0'});
  airG.appendChild(c);
  gapPs.push({el:c,x:0,y:0,life:0,on:false,idx:i%C.nF});
}
svg.appendChild(airG);

/* 翅膀组 */
const wingG=el('g',{id:'wingG'});

// 翼梁
const sparEl=el('path',{d:'',stroke:'url(#spGr)','stroke-width':'10','stroke-linecap':'round',fill:'none',filter:'url(#glow3)'});
wingG.appendChild(sparEl);
const sparHL=el('path',{d:'',stroke:'rgba(240,200,104,0.25)','stroke-width':'2.5','stroke-linecap':'round',fill:'none'});
wingG.appendChild(sparHL);

// 薄膜+弹簧
const films=[];
for(let i=C.nF-1;i>=0;i--){
  const fg=el('g',{});
  const sp=el('path',{d:'',fill:'none',stroke:'#f0c040','stroke-width':'1.3',opacity:'0.65'});
  fg.appendChild(sp);
  const fm=el('path',{d:'',fill:'#00dfa0',opacity:'0.85','stroke-linejoin':'round'});
  fg.appendChild(fm);
  // 前缘高光
  const ed=el('line',{stroke:'#00ffcc','stroke-width':'1.8',opacity:'0.5','stroke-linecap':'round'});
  fg.appendChild(ed);
  // 标注线 (只在第2片和第5片)
  if(i===1||i===4){
    const ann=el('text',{fill:'#e8dcc4','font-size':'9','font-family':'JetBrains Mono,monospace',opacity:'0'});
    fg.appendChild(ann);
    films[i]={g:fg,fm,sp,ed,ann};
  }else{
    films[i]={g:fg,fm,sp,ed};
  }
  wingG.appendChild(fg);
}

// 力箭头
const liftA=el('line',{stroke:'#ff5e3a','stroke-width':'4.5','marker-end':'url(#aLift)',opacity:'0','stroke-linecap':'round'});
wingG.appendChild(liftA);
const dragA=el('line',{stroke:'#8868f0','stroke-width':'3','marker-end':'url(#aDrag)',opacity:'0','stroke-linecap':'round'});
wingG.appendChild(dragA);
const liftLbl=el('text',{fill:'#ff5e3a','font-size':'14','font-family':'JetBrains Mono,monospace','font-weight':'600',opacity:'0'});
liftLbl.textContent='升力 LIFT';wingG.appendChild(liftLbl);
const dragLbl=el('text',{fill:'#8868f0','font-size':'12','font-family':'JetBrains Mono,monospace','font-weight':'600',opacity:'0'});
dragLbl.textContent='阻力 (减小)';wingG.appendChild(dragLbl);

svg.appendChild(wingG);

/* 标注组 */
const annG=el('g',{'font-family':'JetBrains Mono,monospace'});
const anns=[
  {id:'aSpar',txt:'弹性碳纤维主梁',col:'#d49540',sz:11},
  {id:'aFilm',txt:'柔性薄膜 (仿初级飞羽)',col:'#00dfa0',sz:10},
  {id:'aSpring',txt:'扭簧 τ=0.02N·m',col:'#f0c040',sz:9},
];
anns.forEach(a=>{const t=el('text',{fill:a.col,'font-size':a.sz,'font-weight':'500',opacity:'0'});t.textContent=a.txt;annG.appendChild(t);a.el=t});
// 连接线
anns.forEach(()=>{const l=el('line',{stroke:'rgba(255,240,200,0.15)','stroke-width':'0.8','stroke-dasharray':'4 3'});annG.appendChild(l)});
svg.appendChild(annG);

/* IFR面板 */
const ifrG=el('g',{});
ifrG.appendChild(el('rect',{x:30,y:520,width:360,height:200,rx:10,fill:'rgba(16,14,10,0.94)',stroke:'rgba(255,240,200,0.06)','stroke-width':'1'}));
const ifrT=el('text',{x:50,y:548,fill:'#00dfa0','font-size':'13','font-family':'JetBrains Mono,monospace','font-weight':'600'});
ifrT.textContent='IFR · 最终理想解原理';ifrG.appendChild(ifrT);
const ifrL=[
  {y:572,t:'▸ 资源利用:气动力已存在,零额外输入',c:'#7a6e5c'},
  {y:592,t:'▸ 核心矛盾:升力最大化 ↔ 阻力最小化',c:'#7a6e5c'},
  {y:612,t:'▸ 破解:被动响应 → 下扑闭合 / 上扬泄气',c:'#e8dcc4'},
  {y:632,t:'▸ 理想度:系统自行消解矛盾,复杂度不增',c:'#e8dcc4'},
  {y:652,t:'▸ 关键:扭簧预紧力 + 气动力 → 双向自适应',c:'#f0c040'},
  {y:672,t:'▸ 失效边界:暴雨/结冰 → 膜面附加质量改变',c:'#5a4e3c'},
  {y:692,t:'▸ 风险:高频弯折疲劳 / 气动弹性振荡',c:'#5a4e3c'},
];
ifrL.forEach(l=>{const t=el('text',{x:50,y:l.y,fill:l.c,'font-size':'9.5','font-family':'JetBrains Mono,monospace'});t.textContent=l.t;ifrG.appendChild(t)});
svg.appendChild(ifrG);

/* 详情面板 (薄膜开合细节) */
const detG=el('g',{});
detG.appendChild(el('rect',{x:830,y:520,width:540,height:200,rx:10,fill:'rgba(16,14,10,0.94)',stroke:'rgba(255,240,200,0.06)','stroke-width':'1'}));
const detT=el('text',{x:855,y:548,fill:'#00dfa0','font-size':'13','font-family':'JetBrains Mono,monospace','font-weight':'600'});
detT.textContent='DETAIL · 薄膜开合细节';detG.appendChild(detT);

// 详情翼梁
detG.appendChild(el('line',{x1:870,y1:590,x2:1080,y2:590,stroke:'#d49540','stroke-width':'5','stroke-linecap':'round'}));
// 详情薄膜
const dFilms=[];
for(let i=0;i<5;i++){
  const fg=el('g',{});
  const sp=el('circle',{cx:0,cy:0,r:4.5,fill:'none',stroke:'#f0c040','stroke-width':'1.2','stroke-dasharray':'2 2'});
  fg.appendChild(sp);
  const fm=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#00dfa0','stroke-width':'5','stroke-linecap':'round',opacity:'0.8'});
  fg.appendChild(fm);
  detG.appendChild(fg);
  dFilms.push({g:fg,fm,sp});
}
// 缝隙标注
const detGapTxt=el('text',{x:1095,y:585,fill:'#48b8f0','font-size':'10','font-family':'JetBrains Mono,monospace'});
detG.appendChild(detGapTxt);
const detStateTxt=el('text',{x:1095,y:605,fill:'#00dfa0','font-size':'11','font-family':'JetBrains Mono,monospace','font-weight':'600'});
detG.appendChild(detStateTxt);
// 缝隙流箭头
const detArrs=[];
for(let i=0;i<4;i++){const a=el('line',{stroke:'#48b8f0','stroke-width':'1.5','marker-end':'url(#aAir)',opacity:'0'});detG.appendChild(a);detArrs.push(a)}
// 缝隙宽度线
const detGapLns=[];
for(let i=0;i<4;i++){const l=el('line',{stroke:'#48b8f0','stroke-width':'0.8','stroke-dasharray':'3 2',opacity:'0'});detG.appendChild(l);detGapLns.push(l)}
// 力矩示意
const detTorqueTxt=el('text',{x:1095,y:625,fill:'#f0c040','font-size':'9','font-family':'JetBrains Mono,monospace'});
detG.appendChild(detTorqueTxt);
const detDirTxt=el('text',{x:1095,y:642,fill:'#7a6e5c','font-size':'9','font-family':'JetBrains Mono,monospace'});
detG.appendChild(detDirTxt);
// 重叠区域指示
const detOverlapRect=el('rect',{x:0,y:0,width:0,height:0,fill:'rgba(0,223,160,0.12)',rx:1});
detG.appendChild(detOverlapRect);
const detOverlapTxt=el('text',{x:0,y:0,fill:'#00dfa0','font-size':'8','font-family':'JetBrains Mono,monospace',opacity:'0'});
detG.appendChild(detOverlapTxt);
svg.appendChild(detG);

/* 实时曲线 (升力/阻力波形) */
const chartG=el('g',{});
chartG.appendChild(el('rect',{x:410,y:520,width:400,height:200,rx:10,fill:'rgba(16,14,10,0.94)',stroke:'rgba(255,240,200,0.06)','stroke-width':'1'}));
const chTitle=el('text',{x:430,y:548,fill:'#e8dcc4','font-size':'12','font-family':'JetBrains Mono,monospace','font-weight':'600'});
chTitle.textContent='LIFT / DRAG WAVEFORM';chartG.appendChild(chTitle);
// 图例
chartG.appendChild(el('line',{x1:600,y1:543,x2:625,y2:543,stroke:'#ff5e3a','stroke-width':'2'}));
const chLeg1=el('text',{x:630,y:547,fill:'#ff5e3a','font-size':'9','font-family':'JetBrains Mono,monospace'});
chLeg1.textContent='升力';chartG.appendChild(chLeg1);
chartG.appendChild(el('line',{x1:680,y1:543,x2:705,y2:543,stroke:'#8868f0','stroke-width':'2'}));
const chLeg2=el('text',{x:710,y:547,fill:'#8868f0','font-size':'9','font-family':'JetBrains Mono,monospace'});
chLeg2.textContent='阻力';chartG.appendChild(chLeg2);
// 坐标轴
chartG.appendChild(el('line',{x1:440,y1:560,x2:440,y2:710,stroke:'rgba(255,240,200,0.1)','stroke-width':'1'}));
chartG.appendChild(el('line',{x1:440,y1:700,x2:790,y2:700,stroke:'rgba(255,240,200,0.1)','stroke-width':'1'}));
// 零线
chartG.appendChild(el('line',{x1:440,y1:650,x2:790,y2:650,stroke:'rgba(255,240,200,0.05)','stroke-width':'0.5','stroke-dasharray':'4 4'}));
// 波形路径
const liftPath=el('polyline',{fill:'none',stroke:'#ff5e3a','stroke-width':'1.8',opacity:'0.85'});
chartG.appendChild(liftPath);
const dragPath=el('polyline',{fill:'none',stroke:'#8868f0','stroke-width':'1.5',opacity:'0.75'});
chartG.appendChild(dragPath);
// 当前时刻线
const chNow=el('line',{x1:790,y1:560,x2:790,y2:710,stroke:'#00dfa0','stroke-width':'1',opacity:'0.4'});
chartG.appendChild(chNow);
svg.appendChild(chartG);

// 波形数据
const wData={lift:[],drag:[],max:180};

/* 相位时钟 */
const clkG=el('g',{transform:'translate(1320,80)'});
clkG.appendChild(el('circle',{cx:0,cy:0,r:38,fill:'rgba(16,14,10,0.9)',stroke:'rgba(255,240,200,0.08)','stroke-width':'1'}));
// 刻度
for(let i=0;i<12;i++){const a=i*Math.PI/6-Math.PI/2;clkG.appendChild(el('line',{x1:32*Math.cos(a),y1:32*Math.sin(a),x2:36*Math.cos(a),y2:36*Math.sin(a),stroke:'rgba(255,240,200,0.15)','stroke-width':'0.8'}))}
// 相位标记
['闭合','升推','泄气','减阻'].forEach((t,i)=>{const a=i*Math.PI/2-Math.PI/2;const tx=22*Math.cos(a);const ty=22*Math.sin(a);const te=el('text',{x:tx,y:ty+3,fill:'rgba(255,240,200,0.25)','font-size':'5','font-family':'JetBrains Mono,monospace','text-anchor':'middle'});te.textContent=t;clkG.appendChild(te)});
// 指针
const clkHand=el('line',{x1:0,y1:0,x2:0,y2:-28,stroke:'#00dfa0','stroke-width':'2','stroke-linecap':'round'});
clkG.appendChild(clkHand);
const clkDot=el('circle',{cx:0,cy:0,r:3,fill:'#00dfa0',filter:'url(#glow3)'});
clkG.appendChild(clkDot);
const clkLbl=el('text',{x:0,y:52,fill:'#7a6e5c','font-size':'8','font-family':'JetBrains Mono,monospace','text-anchor':'middle'});
clkLbl.textContent='PHASE';clkG.appendChild(clkLbl);
svg.appendChild(clkG);

/* 弹簧路径生成 */
function springD(cx,cy,r){
  let d=`M${cx},${cy-r}`;
  const n=10;
  for(let i=1;i<=n;i++){const a=-Math.PI/2+i*(Math.PI*1.6)/n;d+=` L${cx+r*0.55*Math.cos(a)},${cy+r*0.55*Math.sin(a)}`}
  return d;
}

/* 薄膜路径 (局部坐标, 沿+x方向延伸) */
function filmD(angle,len,w,curve){
  const rad=angle*Math.PI/180;
  const c=Math.cos(rad),s=Math.sin(rad);
  const px=-s,py=c;
  const rw=w*0.52,tw=w*0.2;
  const ax=px*rw,ay=py*rw;
  const bx=-px*rw,by=-py*rw;
  const ex=len*c,ey=len*s;
  const dx=ex+px*tw,dy=ey+py*tw;
  const fx=ex-px*tw,fy=ey-py*tw;
  const mx=len*0.5*c+curve*px,my=len*0.5*s+curve*py;
  const cx1=mx+px*(rw+tw)*0.3,cy1=my+py*(rw+tw)*0.3;
  const cx2=mx-px*(rw+tw)*0.3,cy2=my-py*(rw+tw)*0.3;
  return`M${ax.toFixed(1)},${ay.toFixed(1)} Q${cx1.toFixed(1)},${cy1.toFixed(1)} ${dx.toFixed(1)},${dy.toFixed(1)} L${fx.toFixed(1)},${fy.toFixed(1)} Q${cx2.toFixed(1)},${cy2.toFixed(1)} ${bx.toFixed(1)},${by.toFixed(1)}Z`;
}

/* 动画主循环 */
function animate(ts){
  if(!t0)t0=ts;
  const elapsed=(ts-t0)*spd;
  const period=C.period;
  const t=(elapsed%period)/period;

  // 翅膀角度
  const wDeg=-C.amp*Math.cos(2*Math.PI*t);
  const vel=Math.sin(2*Math.PI*t);
  const isDown=vel>0;

  // 薄膜开度
  const eff=wndK/Math.max(0.3,sprK);
  const raw=0.5-0.5*Math.tanh(vel*2.6*eff);
  const open=clamp(raw,0,1);

  // 翼梁弯曲
  const bend=wDeg*C.bendF;
  const eX=C.px+C.sparLen;
  const eY=C.py+bend*2.5;
  const mX=C.px+C.sparLen*0.52;
  const mY=C.py+bend*1.8;

  // 翅膀旋转
  wingG.setAttribute('transform',`rotate(${wDeg.toFixed(2)},${C.px},${C.py})`);

  // 翼梁路径
  const sd=`M${C.px},${C.py} Q${mX},${mY} ${eX},${eY}`;
  sparEl.setAttribute('d',sd);
  sparHL.setAttribute('d',`M${C.px},${C.py-3.5} Q${mX},${mY-3.5} ${eX},${eY-3.5}`);

  // 薄膜
  for(let i=0;i<C.nF;i++){
    const dist=C.fOff+i*C.fSp;
    const tp=dist/C.sparLen;
    const pt=qBez(tp,C.px,C.py,mX,mY,eX,eY);
    const tn=qTan(tp,C.px,C.py,mX,mY,eX,eY);
    const sparA=Math.atan2(tn.y,tn.x)*180/Math.PI;

    const relA=C.closedA+open*(C.openA-C.closedA);
    const absA=sparA+relA;
    const curve=open*8;

    const fp=filmD(relA,C.fLen,C.fW,curve);
    films[i].fm.setAttribute('d',fp);

    const fOp=0.4+0.6*(1-open*0.4);
    const bright=open<0.3;
    films[i].fm.setAttribute('fill',bright?'#00dfa0':'#00c088');
    films[i].fm.setAttribute('opacity',fOp.toFixed(2));
    if(bright)films[i].fm.setAttribute('filter','url(#glow3)');
    else films[i].fm.removeAttribute('filter');

    const spR=5+open*2.5;
    films[i].sp.setAttribute('d',springD(0,0,spR));
    films[i].sp.setAttribute('opacity',(0.35+open*0.4).toFixed(2));

    const eH=C.fW*0.55;
    films[i].ed.setAttribute('x1','0');films[i].ed.setAttribute('y1',(-eH).toFixed(1));
    films[i].ed.setAttribute('x2','0');films[i].ed.setAttribute('y2',eH.toFixed(1));
    films[i].ed.setAttribute('opacity',(0.25+open*0.5).toFixed(2));

    films[i].g.setAttribute('transform',`translate(${pt.x.toFixed(1)},${pt.y.toFixed(1)}) rotate(${absA.toFixed(1)})`);

    // 薄膜标注
    if(films[i].ann){
      films[i].ann.setAttribute('x','10');
      films[i].ann.setAttribute('y',(-C.fLen*0.5-8).toFixed(0));
      films[i].ann.setAttribute('opacity',(open>0.3?0.6:0.3).toFixed(1));
      films[i].ann.textContent=open>0.5?`缝隙 ${(2+open*3).toFixed(1)}mm`:`重叠闭合`;
    }
  }

  // 力矢量
  const mid=qBez(0.42,C.px,C.py,mX,mY,eX,eY);
  const tipP=qBez(0.75,C.px,C.py,mX,mY,eX,eY);
  if(isDown){
    const s=Math.abs(vel);
    const lLen=50+s*100;
    liftA.setAttribute('x1',mid.x);liftA.setAttribute('y1',mid.y+20);
    liftA.setAttribute('x2',mid.x);liftA.setAttribute('y2',(mid.y+20-lLen).toFixed(1));
    liftA.setAttribute('opacity',(s*0.9).toFixed(2));
    liftA.setAttribute('stroke-width',(2+s*4).toFixed(1));
    liftLbl.setAttribute('x',(mid.x+12).toFixed(0));liftLbl.setAttribute('y',(mid.y-45-s*35).toFixed(0));
    liftLbl.setAttribute('opacity',(s*0.8).toFixed(2));
    dragA.setAttribute('opacity','0');dragLbl.setAttribute('opacity','0');
  }else{
    const s=Math.abs(vel)*(1-open*0.7);
    const dLen=15+s*28;
    dragA.setAttribute('x1',tipP.x+15);dragA.setAttribute('y1',tipP.y+8);
    dragA.setAttribute('x2',tipP.x+15);dragA.setAttribute('y2',(tipP.y+8-dLen).toFixed(1));
    dragA.setAttribute('opacity',(s*0.6).toFixed(2));
    dragLbl.setAttribute('x',(tipP.x+25).toFixed(0));dragLbl.setAttribute('y',(tipP.y-5).toFixed(0));
    dragLbl.setAttribute('opacity',(s*0.5).toFixed(2));
    liftA.setAttribute('opacity','0');liftLbl.setAttribute('opacity','0');
  }

  // 气流粒子
  airPs.forEach(p=>{
    p.y+=p.spd*wndK*0.7;
    p.x+=Math.sin(p.y*0.008+p.spd)*0.3;
    if(p.y>760){p.y=-10;p.x=50+Math.random()*1200;}
    p.el.setAttribute('cx',p.x.toFixed(0));
    p.el.setAttribute('cy',p.y.toFixed(0));
    const dW=Math.abs(p.y-C.py);
    p.el.setAttribute('opacity',dW<120?(0.08+0.18*(1-dW/120)).toFixed(2):'0.04');
  });

  // 缝隙粒子
  gapPs.forEach(p=>{
    if(!isDown&&open>0.3){
      if(!p.on){
        p.on=true;p.life=0;
        const dist=C.fOff+p.idx*C.fSp;
        const tp2=dist/C.sparLen;
        const pt2=qBez(tp2,C.px,C.py,mX,mY,eX,eY);
        p.x=pt2.x+8;p.y=pt2.y+18;
      }
      p.life+=0.022*wndK;
      p.y+=2*wndK;
      p.x+=Math.sin(p.life*7+p.idx*2)*0.6;
      const op=Math.max(0,0.55*(1-p.life)*(open-0.2));
      p.el.setAttribute('cx',p.x.toFixed(0));
      p.el.setAttribute('cy',p.y.toFixed(0));
      p.el.setAttribute('opacity',op.toFixed(2));
      if(p.life>1.3)p.on=false;
    }else{
      p.el.setAttribute('opacity','0');p.on=false;
    }
  });

  // 标注定位
  const a0=qBez(0.12,C.px,C.py,mX,mY,eX,eY);
  const a1=qBez(0.62,C.px,C.py,mX,mY,eX,eY);
  const a2=qBez(0.32,C.px,C.py,mX,mY,eX,eY);
  anns[0].el.setAttribute('x',(a0.x-15).toFixed(0));anns[0].el.setAttribute('y',(a0.y-28).toFixed(0));anns[0].el.setAttribute('opacity','0.7');
  anns[1].el.setAttribute('x',(a1.x-30).toFixed(0));anns[1].el.setAttribute('y',(a1.y+55+open*18).toFixed(0));anns[1].el.setAttribute('opacity',(0.4+open*0.4).toFixed(2));
  anns[2].el.setAttribute('x',(a2.x+18).toFixed(0));anns[2].el.setAttribute('y',(a2.y+22).toFixed(0));anns[2].el.setAttribute('opacity','0.55');
  // 连接线
  const annLines=annG.querySelectorAll('line');
  if(annLines[0]){annLines[0].setAttribute('x1',a0.x);annLines[0].setAttribute('y1',a0.y-5);annLines[0].setAttribute('x2',a0.x-15);annLines[0].setAttribute('y2',a0.y-22)}
  if(annLines[1]){annLines[1].setAttribute('x1',a1.x);annLines[1].setAttribute('y1',a1.y+40+open*10);annLines[1].setAttribute('x2',a1.x-30);annLines[1].setAttribute('y2',a1.y+50+open*16)}
  if(annLines[2]){annLines[2].setAttribute('x1',a2.x+8);annLines[2].setAttribute('y1',a2.y+8);annLines[2].setAttribute('x2',a2.x+18);annLines[2].setAttribute('y2',a2.y+18)}

  // 详情面板
  for(let i=0;i<5;i++){
    const bx=880+i*38,by=590;
    const relA2=C.closedA+open*(C.openA-C.closedA);
    const rad=relA2*Math.PI/180;
    const fEx=bx+60*Math.cos(rad);
    const fEy=by+60*Math.sin(rad);
    dFilms[i].sp.setAttribute('cx',bx);dFilms[i].sp.setAttribute('cy',by);
    dFilms[i].fm.setAttribute('x1',bx);dFilms[i].fm.setAttribute('y1',by);
    dFilms[i].fm.setAttribute('x2',fEx.toFixed(1));dFilms[i].fm.setAttribute('y2',fEy.toFixed(1));
    dFilms[i].fm.setAttribute('opacity',(0.4+0.6*(1-open*0.3)).toFixed(2));
    dFilms[i].fm.setAttribute('stroke',open>0.4?'#00b888':'#00dfa0');
    dFilms[i].fm.setAttribute('stroke-width','0.8');
  }
  for(let i=0;i<4;i++){
    const bx=899+i*38;
    if(open>0.3){
      const aOp=(open-0.25)*1.0;
      detArrs[i].setAttribute('x1',bx);detArrs[i].setAttribute('y1',598);
      detArrs[i].setAttribute('x2',bx+2);detArrs[i].setAttribute('y2',(625+open*15).toFixed(0));
      detArrs[i].setAttribute('opacity',clamp(aOp,0,0.7).toFixed(2));
      detGapLns[i].setAttribute('x1',bx);detGapLns[i].setAttribute('y1',594);
      detGapLns[i].setAttribute('x2',bx);detGapLns[i].setAttribute('y2',608);
      detGapLns[i].setAttribute('opacity',(aOp*0.5).toFixed(2));
    }else{
      detArrs[i].setAttribute('opacity','0');detGapLns[i].setAttribute('opacity','0');
    }
  }
  // 重叠区域
  if(open<0.35){
    detOverlapRect.setAttribute('x','880');detOverlapRect.setAttribute('y','560');
    detOverlapRect.setAttribute('width',(170*(1-open*2.8)).toFixed(0));detOverlapRect.setAttribute('height','18');
    detOverlapRect.setAttribute('opacity',(0.15*(1-open*2.8)).toFixed(2));
    detOverlapTxt.setAttribute('x','885');detOverlapTxt.setAttribute('y','573');
    detOverlapTxt.setAttribute('opacity',(0.5*(1-open*2.8)).toFixed(2));
    detOverlapTxt.textContent='重叠搭接区';
  }else{
    detOverlapRect.setAttribute('opacity','0');detOverlapTxt.setAttribute('opacity','0');
  }
  detGapTxt.textContent=open>0.35?`缝隙 ${(2+open*3).toFixed(1)} mm`:'闭合 (0 mm)';
  detGapTxt.setAttribute('fill',open>0.35?'#48b8f0':'#7a6e5c');
  detStateTxt.textContent=open>0.5?'▲ 泄气减阻模式':'▼ 闭合升推模式';
  detStateTxt.setAttribute('fill',open>0.5?'#48b8f0':'#00dfa0');
  detTorqueTxt.textContent=`τ_spring = ${(0.02*sprK).toFixed(3)} N·m`;
  detDirTxt.textContent=open>0.5?'气动力 > 扭簧力 → 吹开':'气动力 < 扭簧力 → 闭合';

  // 波形图
  const liftV=isDown?Math.abs(vel)*(1-open*0.15):Math.abs(vel)*0.1*(1-open);
  const dragV=isDown?Math.abs(vel)*0.3:Math.abs(vel)*(1-open*0.7);
  wData.lift.push(liftV);wData.drag.push(dragV);
  if(wData.lift.length>wData.max){wData.lift.shift();wData.drag.shift()}
  let lp='',dp='';
  const chW=340,chH=120,chX=445,chY=575;
  wData.lift.forEach((v,i)=>{
    const x=chX+i*(chW/wData.max);
    const y=chY+chH*0.5-v*chH*0.8;
    lp+=(i?'L':'M')+x.toFixed(1)+','+clamp(y,chY,chY+chH).toFixed(1);
  });
  wData.drag.forEach((v,i)=>{
    const x=chX+i*(chW/wData.max);
    const y=chY+chH*0.5+v*chH*0.5;
    dp+=(i?'L':'M')+x.toFixed(1)+','+clamp(y,chY,chY+chH).toFixed(1);
  });
  liftPath.setAttribute('points','');
  liftPath.setAttribute('d',lp);
  dragPath.setAttribute('points','');
  dragPath.setAttribute('d',dp);
  const nowX=chX+wData.lift.length*(chW/wData.max);
  chNow.setAttribute('x1',nowX.toFixed(1));chNow.setAttribute('x2',nowX.toFixed(1));

  // 相位时钟
  const clkA=-90+t*360;
  clkHand.setAttribute('transform',`rotate(${clkA.toFixed(1)})`);

  // UI更新
  const pn=$('ph-name'),pd=$('ph-desc');
  if(isDown){
    if(open<0.3){pn.textContent='下扑 · 闭合';pn.style.color='#00dfa0';pd.textContent='气动力压紧薄膜,形成连续气动面';}
    else{pn.textContent='下扑 · 过渡';pn.style.color='#d49540';pd.textContent='薄膜正在闭合...';}
  }else{
    if(open>0.55){pn.textContent='上扬 · 泄气';pn.style.color='#48b8f0';pd.textContent='气动力吹开薄膜,缝隙泄气减阻';}
    else{pn.textContent='上扬 · 过渡';pn.style.color='#d49540';pd.textContent='薄膜正在打开...';}
  }
  $('ph-bar').style.width=(t*100).toFixed(1)+'%';
  $('ph-bar').style.background=isDown?'#00dfa0':'#48b8f0';
  $('lv-l').textContent=(liftV*100).toFixed(0)+'%';$('lv-l').style.color=liftV>0.3?'#ff5e3a':'#7a6e5c';
  $('lv-d').textContent=(dragV*100).toFixed(0)+'%';$('lv-d').style.color=dragV>0.2?'#8868f0':'#7a6e5c';

  requestAnimationFrame(animate);
}

requestAnimationFrame(animate);
})();
</script>
</body>
</html>

这个动画完整呈现了"分段式柔性蒙皮与被动搭接骨架"的 IFR 最终理想解工作原理,主要实现了:

核心机制可视化:翅膀下扑时薄膜自动闭合(绿色发光强调连续气动面),上扬时薄膜被动吹开(蓝色缝隙流粒子突出泄气减阻),全程由气动力被动驱动,零额外能耗。

四面板信息架构

  • 左下 IFR 面板:逐条阐释理想解原理——资源利用、矛盾破解、理想度、失效边界
  • 中下实时波形:升力(红)与阻力(紫)的滚动波形图,直观展示升推-减阻的周期性解耦
  • 右下细节面板:放大展示薄膜开合状态、缝隙宽度、力矩平衡关系,含重叠搭接区指示
  • 右上相位时钟:圆形指针实时指示当前处于闭合/升推/泄气/减阻哪个阶段

交互控制:三个滑块分别调节扑动速度、扭簧刚度和来流强度,实时影响薄膜开合响应幅度和时序,可深入体验参数对被动响应特性的影响。

视觉风格:暖铜色机械结构 + 荧光绿生物膜材的冷暖对比,点阵背景 + 胶片噪波纹理营造高端工程图感,Cormorant Garamond 衬线标题搭配 JetBrains Mono 数据字体形成强烈的编辑排版质感。

<!DOCTYPE html>
<html lang="zh">
<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=DM+Serif+Display&family=IBM+Plex+Mono:wght@300;400;500;600&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root{--bg:#060910;--fg:#c0cce0;--muted:#485870;--accent:#00f0b0;--spar:#d49030;--lift:#ff5040;--drag:#9070e8;--air:#3098e8;--spring:#e8b820;--card:rgba(8,14,26,0.95);--bdr:rgba(192,204,224,0.06)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'IBM Plex Mono',monospace;min-height:100vh;overflow-x:hidden}
.serif{font-family:'DM Serif Display',serif}
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:3px;background:rgba(192,204,224,0.07);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;background:var(--accent);border-radius:50%;cursor:pointer;box-shadow:0 0 8px rgba(0,240,176,0.4)}
input[type=range]::-moz-range-thumb{width:13px;height:13px;background:var(--accent);border-radius:50%;cursor:pointer;border:none}
.atm{background:radial-gradient(ellipse at 22% 38%,rgba(0,240,176,0.018) 0%,transparent 50%),radial-gradient(ellipse at 78% 55%,rgba(48,152,232,0.015) 0%,transparent 45%)}
.pbar{height:3px;border-radius:2px;overflow:hidden;background:rgba(192,204,224,0.05)}
.pbar>div{height:100%;border-radius:2px;transition:none}
</style>
</head>
<body class="atm">
<div class="max-w-7xl mx-auto px-3 py-4 md:px-6">
  <header class="text-center mb-3">
    <h1 class="serif text-3xl md:text-5xl tracking-tight" style="color:var(--fg)">分段式柔性蒙皮与被动搭接骨架</h1>
    <p class="mt-1 text-[10px] tracking-[.28em] uppercase" style="color:var(--muted)">IFR 最终理想解 · 扑翼机原理动画</p>
  </header>
  <div class="relative rounded-2xl overflow-hidden" style="background:linear-gradient(150deg,rgba(8,14,26,.98),rgba(6,9,16,.98));border:1px solid var(--bdr)">
    <svg id="svg" viewBox="0 0 1400 780" style="display:block;width:100%"></svg>
  </div>
  <div class="grid grid-cols-2 md:grid-cols-4 gap-2.5 mt-3">
    <div class="rounded-xl p-3.5" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1.5" style="color:var(--muted)">扑动周期</div>
      <div id="pn" class="text-sm font-semibold" style="color:var(--accent)">下扑 · 闭合</div>
      <div id="pd" class="text-[10px] mt-0.5" style="color:var(--muted)">气动力压紧薄膜</div>
      <div class="pbar mt-2"><div id="pb" style="width:0%;background:var(--accent)"></div></div>
      <div class="mt-1.5 flex gap-3 text-[9px]"><span style="color:var(--lift)">●升力</span><span id="vl" style="color:var(--muted)">0%</span><span style="color:var(--drag)">●阻力</span><span id="vd" style="color:var(--muted)">0%</span></div>
    </div>
    <div class="rounded-xl p-3.5" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-2" style="color:var(--muted)">交互控制</div>
      <div class="mb-2"><div class="flex justify-between text-[10px] mb-0.5"><span>扑动速度</span><span id="vs" style="color:var(--accent)">1.0x</span></div><input type="range" id="ss" min="0.3" max="2.5" step="0.1" value="1.0"></div>
      <div class="mb-2"><div class="flex justify-between text-[10px] mb-0.5"><span>扭簧刚度</span><span id="vk" style="color:var(--spring)">1.0x</span></div><input type="range" id="sk" min="0.3" max="2.0" step="0.1" value="1.0"></div>
      <div><div class="flex justify-between text-[10px] mb-0.5"><span>来流强度</span><span id="vw" style="color:var(--air)">1.0x</span></div><input type="range" id="sw" min="0.3" max="2.0" step="0.1" value="1.0"></div>
    </div>
    <div class="rounded-xl p-3.5" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1.5" style="color:var(--muted)">关键参数</div>
      <div class="space-y-1 text-[10px]">
        <div class="flex justify-between"><span style="color:var(--muted)">重叠缝隙</span><span>2 — 5 mm</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">扭簧预紧</span><span>0.02 N·m</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">薄膜片数</span><span>7</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">主梁</span><span style="color:var(--spar)">碳纤维杆</span></div>
        <div class="flex justify-between"><span style="color:var(--muted)">膜材</span><span style="color:var(--accent)">柔性薄膜</span></div>
      </div>
    </div>
    <div class="rounded-xl p-3.5" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1.5" style="color:var(--muted)">IFR 理想解</div>
      <div class="text-[9px] leading-[1.65]" style="color:var(--muted)">
        <div><span style="color:var(--accent)">▸</span> 资源: 气动力 (零额外输入)</div>
        <div><span style="color:var(--accent)">▸</span> 矛盾: 升力最大 ↔ 阻力最小</div>
        <div><span style="color:var(--accent)">▸</span> 解法: 被动响应 → 自适应开合</div>
        <div><span style="color:var(--accent)">▸</span> 理想度: 系统自行消解矛盾</div>
      </div>
      <div class="mt-1.5 text-[10px] font-semibold" style="color:var(--accent)">额外能耗: 0 W</div>
    </div>
  </div>
</div>
<script>
(function(){
'use strict';
const NS='http://www.w3.org/2000/svg';
const svg=document.getElementById('svg');

function el(t,a){const e=document.createElementNS(NS,t);for(const k in a)e.setAttribute(k,a[k]);return e}
function qB(t,ax,ay,bx,by,cx,cy){const u=1-t;return{x:u*u*ax+2*u*t*bx+t*t*cx,y:u*u*ay+2*u*t*by+t*t*cy}}
function qT(t,ax,ay,bx,by,cx,cy){const u=1-t;return{x:2*u*(bx-ax)+2*t*(cx-bx),y:2*u*(by-ay)+2*t*(cy-by)}}
function cl(v,lo,hi){return Math.max(lo,Math.min(hi,v))}

/* 配置 */
const C={px:195,py:310,sLen:630,nF:7,fL:108,fW:6.5,fSp:78,fOff:85,amp:22,per:3200,cA:3,oA:58,bF:0.21};
let spd=1,sK=1,wK=1,t0=null;

/* UI */
const $=id=>document.getElementById(id);
$('ss').oninput=function(){spd=+this.value;$('vs').textContent=spd.toFixed(1)+'x'};
$('sk').oninput=function(){sK=+this.value;$('vk').textContent=sK.toFixed(1)+'x'};
$('sw').oninput=function(){wK=+this.value;$('vw').textContent=wK.toFixed(1)+'x'};

/* Defs */
const defs=el('defs',{});
function mkG(id,sd){const f=el('filter',{id,x:'-50%',y:'-50%',width:'200%',height:'200%'});f.appendChild(el('feGaussianBlur',{stdDeviation:String(sd),result:'b'}));const m=el('feMerge',{});m.appendChild(el('feMergeNode',{in:'b'}));m.appendChild(el('feMergeNode',{in:'SourceGraphic'}));f.appendChild(m);return f}
defs.appendChild(mkG('g1',4));defs.appendChild(mkG('g2',9));defs.appendChild(mkG('g3',2.5));
const spG=el('linearGradient',{id:'spG',x1:'0%',y1:'0%',x2:'0%',y2:'100%'});
spG.appendChild(el('stop',{offset:'0%','stop-color':'#f0c860'}));spG.appendChild(el('stop',{offset:'50%','stop-color':'#d49030'}));spG.appendChild(el('stop',{offset:'100%','stop-color':'#a06820'}));
defs.appendChild(spG);
function mkA(id,c){const m=el('marker',{id,viewBox:'0 0 10 10',refX:'9',refY:'5',markerWidth:'7',markerHeight:'7',orient:'auto'});m.appendChild(el('path',{d:'M0,1.5L10,5L0,8.5z',fill:c}));return m}
defs.appendChild(mkA('aL','#ff5040'));defs.appendChild(mkA('aA','#3098e8'));defs.appendChild(mkA('aD','#9070e8'));
svg.appendChild(defs);

/* 背景 */
svg.appendChild(el('rect',{x:0,y:0,width:1400,height:780,fill:'#080e18'}));
const dg=el('g',{opacity:'0.025'});
for(let x=0;x<=1400;x+=40)for(let y=0;y<=780;y+=40)dg.appendChild(el('circle',{cx:x,cy:y,r:'0.6',fill:'#c0cce0'}));
svg.appendChild(dg);

/* 鸟身 */
const bG=el('g',{});
bG.appendChild(el('path',{d:`M${C.px-54},${C.py-28}Q${C.px-76},${C.py-2},${C.px-58},${C.py+34}Q${C.px-32},${C.py+52},${C.px+8},${C.py+24}Q${C.px+28},${C.py+4},${C.px+14},${C.py-14}Q${C.px+4},${C.py-40},${C.px-54},${C.py-28}Z`,fill:'rgba(12,18,32,0.92)',stroke:'rgba(212,144,48,0.1)','stroke-width':'1'}));
bG.appendChild(el('path',{d:`M${C.px-54},${C.py-28}Q${C.px-84},${C.py-42},${C.px-92},${C.py-28}Q${C.px-88},${C.py-18},${C.px-58},${C.py-23}`,fill:'rgba(12,18,32,0.92)',stroke:'rgba(212,144,48,0.06)','stroke-width':'0.6'}));
bG.appendChild(el('circle',{cx:C.px,cy:C.py,r:'6.5',fill:'#d49030',filter:'url(#g3)'}));
bG.appendChild(el('circle',{cx:C.px,cy:C.py,r:'2.8',fill:'#f0c860'}));
svg.appendChild(bG);

/* 气流粒子 */
const aGr=el('g',{});
const aPs=[];
for(let i=0;i<42;i++){const c=el('circle',{r:(0.7+Math.random()*1.6).toFixed(1),fill:'#3098e8',opacity:'0'});aGr.appendChild(c);aPs.push({el:c,x:30+Math.random()*1300,y:Math.random()*780,sp:0.5+Math.random()*1.8})}
const gPs=[];
for(let i=0;i<26;i++){const c=el('circle',{r:(1.1+Math.random()*0.7).toFixed(1),fill:'#00f0b0',opacity:'0'});aGr.appendChild(c);gPs.push({el:c,x:0,y:0,lf:0,on:false,idx:i%C.nF})}
svg.appendChild(aGr);

/* 翅膀组 */
const wG=el('g',{id:'wG'});
const sP=el('path',{d:'',stroke:'url(#spG)','stroke-width':'9','stroke-linecap':'round',fill:'none',filter:'url(#g3)'});
wG.appendChild(sP);
const sH=el('path',{d:'',stroke:'rgba(240,200,96,0.2)','stroke-width':'2.5','stroke-linecap':'round',fill:'none'});
wG.appendChild(sH);

/* 压力场 */
const prP=el('path',{d:'',fill:'rgba(255,80,64,0.06)',opacity:'0'});
wG.appendChild(prP);

/* 薄膜 */
const fms=[];
for(let i=C.nF-1;i>=0;i--){
  const fg=el('g',{});
  const sp=el('path',{d:'',fill:'none',stroke:'#e8b820','stroke-width':'1.2',opacity:'0.55'});
  fg.appendChild(sp);
  const fm=el('path',{d:'',fill:'#00f0b0',opacity:'0.85'});
  fg.appendChild(fm);
  const ed=el('line',{stroke:'#00ffc8','stroke-width':'1.5',opacity:'0.35','stroke-linecap':'round'});
  fg.appendChild(ed);
  wG.appendChild(fg);
  fms[i]={g:fg,fm,sp,ed};
}

/* 力箭头 */
const lA=el('line',{stroke:'#ff5040','stroke-width':'4','marker-end':'url(#aL)',opacity:'0','stroke-linecap':'round'});
wG.appendChild(lA);
const dA=el('line',{stroke:'#9070e8','stroke-width':'2.5','marker-end':'url(#aD)',opacity:'0','stroke-linecap':'round'});
wG.appendChild(dA);
const lL=el('text',{fill:'#ff5040','font-size':'13','font-family':'IBM Plex Mono,monospace','font-weight':'600',opacity:'0'});
lL.textContent='LIFT 升力';wG.appendChild(lL);
const dL=el('text',{fill:'#9070e8','font-size':'11','font-family':'IBM Plex Mono,monospace','font-weight':'600',opacity:'0'});
dL.textContent='DRAG 阻力(减小)';wG.appendChild(dL);
svg.appendChild(wG);

/* 标注 */
const anG=el('g',{'font-family':'IBM Plex Mono,monospace'});
const anD=[
  {t:'弹性碳纤维主梁',c:'#d49030',s:10},
  {t:'柔性薄膜 (仿初级飞羽)',c:'#00f0b0',s:10},
  {t:'扭簧 τ=0.02N·m',c:'#e8b820',s:9},
];
const anE=anD.map(a=>{
  const tx=el('text',{fill:a.c,'font-size':s,'font-weight':'500',opacity:'0'});tx.textContent=a.t;anG.appendChild(tx);
  const ln=el('line',{stroke:'rgba(192,204,224,0.1)','stroke-width':'0.7','stroke-dasharray':'3 3'});anG.appendChild(ln);
  return{el:tx,ln};
});
svg.appendChild(anG);

/* IFR面板 */
const iG=el('g',{});
iG.appendChild(el('rect',{x:28,y:530,width:370,height:220,rx:10,fill:'rgba(8,14,26,0.94)',stroke:'rgba(192,204,224,0.05)','stroke-width':'1'}));
const iTx=[
  {y:558,t:'IFR · 最终理想解原理',c:'#00f0b0',s:12,b:'600'},
  {y:580,t:'▸ 资源利用: 气动力已存在 → 零额外输入',c:'#485870',s:9.5},
  {y:598,t:'▸ 核心矛盾: 升力最大化 ↔ 阻力最小化',c:'#485870',s:9.5},
  {y:616,t:'▸ 破解: 被动响应 → 下扑闭合 / 上扬泄气',c:'#c0cce0',s:9.5},
  {y:634,t:'▸ 理想度: 系统自行消解矛盾,复杂度不增',c:'#c0cce0',s:9.5},
  {y:652,t:'▸ 关键: 扭簧预紧力 + 气动力 → 双向自适应',c:'#e8b820',s:9.5},
  {y:670,t:'▸ 时序: 闭合 → 升推 → 泄气 → 减阻 → ∞',c:'#3098e8',s:9.5},
  {y:690,t:'▸ 失效: 暴雨/结冰 → 膜面附加质量改变',c:'#3a4858',s:9},
  {y:706,t:'▸ 风险: 高频弯折疲劳 / 气动弹性振荡',c:'#3a4858',s:9},
  {y:730,t:'EXTRA ENERGY CONSUMED: 0 W',c:'#00f0b0',s:10,b:'600'},
];
iTx.forEach(r=>{const t=el('text',{x:48,y:r.y,fill:r.c,'font-size':r.s,'font-family':'IBM Plex Mono,monospace'});if(r.b)t.setAttribute('font-weight',r.b);t.textContent=r.t;iG.appendChild(t)});
svg.appendChild(iG);

/* 详情面板 */
const dGr=el('g',{});
dGr.appendChild(el('rect',{x:860,y:530,width:515,height:220,rx:10,fill:'rgba(8,14,26,0.94)',stroke:'rgba(192,204,224,0.05)','stroke-width':'1'}));
const dTtl=el('text',{x:882,y:558,fill:'#00f0b0','font-size':'12','font-family':'IBM Plex Mono,monospace','font-weight':'600'});
dTtl.textContent='DETAIL · 薄膜开合细节';dGr.appendChild(dTtl);
dGr.appendChild(el('line',{x1:890,y1:600,x2:1100,y2:600,stroke:'#d49030','stroke-width':'5','stroke-linecap':'round'}));
const dFs=[];
for(let i=0;i<5;i++){
  const fg=el('g',{});
  const sp=el('circle',{cx:0,cy:0,r:4.5,fill:'none',stroke:'#e8b820','stroke-width':'1.1','stroke-dasharray':'2 2'});
  fg.appendChild(sp);
  const fm=el('line',{x1:0,y1:0,x2:0,y2:0,stroke:'#00f0b0','stroke-width':'5','stroke-linecap':'round',opacity:'0.8'});
  fg.appendChild(fm);
  dGr.appendChild(fg);dFs.push({g:fg,fm,sp});
}
const dArrs=[];for(let i=0;i<4;i++){const a=el('line',{stroke:'#3098e8','stroke-width':'1.4','marker-end':'url(#aA)',opacity:'0'});dGr.appendChild(a);dArrs.push(a)}
const dGLs=[];for(let i=0;i<4;i++){const l=el('line',{stroke:'#3098e8','stroke-width':'0.7','stroke-dasharray':'3 2',opacity:'0'});dGr.appendChild(l);dGLs.push(l)}
const dOvR=el('rect',{x:0,y:0,width:0,height:0,fill:'rgba(0,240,176,0.1)',rx:1});dGr.appendChild(dOvR);
const dOvT=el('text',{x:0,y:0,fill:'#00f0b0','font-size':'8','font-family':'IBM Plex Mono,monospace',opacity:'0'});dGr.appendChild(dOvT);
const dGT=el('text',{x:1115,y:590,fill:'#3098e8','font-size':'10','font-family':'IBM Plex Mono,monospace'});dGr.appendChild(dGT);
const dST=el('text',{x:1115,y:610,fill:'#00f0b0','font-size':'11','font-family':'IBM Plex Mono,monospace','font-weight':'600'});dGr.appendChild(dST);
const dTT=el('text',{x:1115,y:630,fill:'#e8b820','font-size':'9','font-family':'IBM Plex Mono,monospace'});dGr.appendChild(dTT);
const dDT=el('text',{x:1115,y:648,fill:'#485870','font-size':'9','font-family':'IBM Plex Mono,monospace'});dGr.appendChild(dDT);
const dFT=el('text',{x:1115,y:668,fill:'#485870','font-size':'8.5','font-family':'IBM Plex Mono,monospace'});dGr.appendChild(dFT);
const dET=el('text',{x:1115,y:686,fill:'#3a4858','font-size':'8','font-family':'IBM Plex Mono,monospace'});dGr.appendChild(dET);
svg.appendChild(dGr);

/* 波形图 */
const cGr=el('g',{});
cGr.appendChild(el('rect',{x:418,y:530,width:420,height:220,rx:10,fill:'rgba(8,14,26,0.94)',stroke:'rgba(192,204,224,0.05)','stroke-width':'1'}));
const cTtl=el('text',{x:438,y:558,fill:'#c0cce0','font-size':'11','font-family':'IBM Plex Mono,monospace','font-weight':'600'});
cTtl.textContent='LIFT / DRAG WAVEFORM';cGr.appendChild(cTtl);
cGr.appendChild(el('line',{x1:620,y1:548,x2:645,y2:548,stroke:'#ff5040','stroke-width':'2'}));
const cL1=el('text',{x:650,y:552,fill:'#ff5040','font-size':'8','font-family':'IBM Plex Mono,monospace'});cL1.textContent='升力';cGr.appendChild(cL1);
cGr.appendChild(el('line',{x1:700,y1:548,x2:725,y2:548,stroke:'#9070e8','stroke-width':'2'}));
const cL2=el('text',{x:730,y:552,fill:'#9070e8','font-size':'8','font-family':'IBM Plex Mono,monospace'});cL2.textContent='阻力';cGr.appendChild(cL2);
cGr.appendChild(el('line',{x1:450,y1:568,x2:450,y2:735,stroke:'rgba(192,204,224,0.08)','stroke-width':'1'}));
cGr.appendChild(el('line',{x1:450,y1:720,x2:810,y2:720,stroke:'rgba(192,204,224,0.08)','stroke-width':'1'}));
cGr.appendChild(el('line',{x1:450,y1:665,x2:810,y2:665,stroke:'rgba(192,204,224,0.04)','stroke-width':'0.5','stroke-dasharray':'4 4'}));
const lPl=el('path',{fill:'none',stroke:'#ff5040','stroke-width':'1.8',opacity:'0.85'});cGr.appendChild(lPl);
const dPl=el('path',{fill:'none',stroke:'#9070e8','stroke-width':'1.4',opacity:'0.7'});cGr.appendChild(dPl);
const cNow=el('line',{x1:810,y1:568,x2:810,y2:735,stroke:'#00f0b0','stroke-width':'0.8',opacity:'0.35'});cGr.appendChild(cNow);
svg.appendChild(cGr);
const wD={l:[],d:[],mx:160};

/* 相位时钟 */
const pGr=el('g',{transform:'translate(1340,72)'});
pGr.appendChild(el('circle',{cx:0,cy:0,r:36,fill:'rgba(8,14,26,0.92)',stroke:'rgba(192,204,224,0.07)','stroke-width':'1'}));
for(let i=0;i<12;i++){const a=i*Math.PI/6-Math.PI/2;pGr.appendChild(el('line',{x1:(30*Math.cos(a)).toFixed(1),y1:(30*Math.sin(a)).toFixed(1),x2:(34*Math.cos(a)).toFixed(1),y2:(34*Math.sin(a)).toFixed(1),stroke:'rgba(192,204,224,0.12)','stroke-width':'0.7'}))}
['闭合','升推','泄气','减阻'].forEach((t,i)=>{const a=i*Math.PI/2-Math.PI/2;const tx=20*Math.cos(a);const ty=20*Math.sin(a);const te=el('text',{x:tx.toFixed(1),y:(ty+3).toFixed(1),fill:'rgba(192,204,224,0.2)','font-size':'5','font-family':'IBM Plex Mono,monospace','text-anchor':'middle'});te.textContent=t;pGr.appendChild(te)});
const pHand=el('line',{x1:0,y1:0,x2:0,y2:-26,stroke:'#00f0b0','stroke-width':'1.8','stroke-linecap':'round'});pGr.appendChild(pHand);
pGr.appendChild(el('circle',{cx:0,cy:0,r:2.5,fill:'#00f0b0',filter:'url(#g3)'}));
const pLbl=el('text',{x:0,y:50,fill:'#485870','font-size':'7','font-family':'IBM Plex Mono,monospace','text-anchor':'middle'});pLbl.textContent='PHASE';pGr.appendChild(pLbl);
svg.appendChild(pGr);

/* 弹簧路径 */
function spD(r){let d=`M0,${-r}`;const n=8;for(let j=1;j<=n;j++){const a=-Math.PI/2+j*(Math.PI*1.5)/n;d+=` L${(r*0.5*Math.cos(a)).toFixed(1)},${(r*0.5*Math.sin(a)).toFixed(1)}`}return d}

/* 动画 */
function anim(ts){
  if(!t0)t0=ts;
  const el2=(ts-t0)*spd;
  const t=(el2%C.per)/C.per;
  const wD2=-C.amp*Math.cos(2*Math.PI*t);
  const vel=Math.sin(2*Math.PI*t);
  const isDn=vel>0;
  const eff=wK/Math.max(0.3,sK);
  const raw=0.5-0.5*Math.tanh(vel*2.8*eff);
  const op=cl(raw,0,1);
  const bd=wD2*C.bF;
  const ex=C.px+C.sLen,ey=C.py+bd*2.5;
  const mx=C.px+C.sLen*0.52,my=C.py+bd*1.8;

  wG.setAttribute('transform',`rotate(${wD2.toFixed(2)},${C.px},${C.py})`);
  sP.setAttribute('d',`M${C.px},${C.py}Q${mx},${my} ${ex},${ey}`);
  sH.setAttribute('d',`M${C.px},${C.py-3.5}Q${mx},${my-3.5} ${ex},${ey-3.5}`);

  /* 压力场 */
  if(isDn&&op<0.35){
    let pp=`M${C.px},${C.py+6}`;
    for(let i=0;i<=18;i++){const pt=qB(i/18,C.px,C.py,mx,my,ex,ey);pp+=` L${pt.x.toFixed(1)},${(pt.y+10+Math.abs(vel)*10).toFixed(1)}`}
    for(let i=18;i>=0;i--){const pt=qB(i/18,C.px,C.py,mx,my,ex,ey);pp+=` L${pt.x.toFixed(1)},${(pt.y+3).toFixed(1)}`}
    pp+='Z';prP.setAttribute('d',pp);prP.setAttribute('opacity',(Math.abs(vel)*0.5).toFixed(2));
  }else{prP.setAttribute('opacity','0')}

  /* 薄膜 */
  for(let i=0;i<C.nF;i++){
    const dist=C.fOff+i*C.fSp;
    const tp=dist/C.sLen;
    const pt=qB(tp,C.px,C.py,mx,my,ex,ey);
    const tn=qT(tp,C.px,C.py,mx,my,ex,ey);
    const sA=Math.atan2(tn.y,tn.x)*180/Math.PI;
    const rA=C.cA+op*(C.oA-C.cA);
    const aA=sA+rA;
    const hw=C.fW*0.52,tw=C.fW*0.15;
    const cv=op*5;
    const fD=`M0,${-hw}Q${C.fL*0.55},${(-hw+cv).toFixed(1)} ${C.fL},${-tw}L${C.fL},${tw}Q${C.fL*0.55},${(hw+cv).toFixed(1)} 0,${hw}Z`;
    fms[i].fm.setAttribute('d',fD);
    const fOp=0.38+0.62*(1-op*0.35);
    fms[i].fm.setAttribute('fill',op<0.28?'#00f0b0':'#00c890');
    fms[i].fm.setAttribute('opacity',fOp.toFixed(2));
    if(op<0.22)fms[i].fm.setAttribute('filter','url(#g3)');else fms[i].fm.removeAttribute('filter');
    const spR=4.5+op*2.5;
    fms[i].sp.setAttribute('d',spD(spR));
    fms[i].sp.setAttribute('opacity',(0.28+op*0.4).toFixed(2));
    fms[i].ed.setAttribute('x1','0');fms[i].ed.setAttribute('y1',(-hw).toFixed(1));
    fms[i].ed.setAttribute('x2','0');fms[i].ed.setAttribute('y2',hw.toFixed(1));
    fms[i].ed.setAttribute('opacity',(0.18+op*0.5).toFixed(2));
    fms[i].g.setAttribute('transform',`translate(${pt.x.toFixed(1)},${pt.y.toFixed(1)}) rotate(${aA.toFixed(1)})`);
  }

  /* 力矢量 */
  const mp=qB(0.42,C.px,C.py,mx,my,ex,ey);
  const tp2=qB(0.72,C.px,C.py,mx,my,ex,ey);
  if(isDn){
    const s=Math.abs(vel);
    const lL2=45+s*100;
    lA.setAttribute('x1',mp.x);lA.setAttribute('y1',mp.y+18);
    lA.setAttribute('x2',mp.x);lA.setAttribute('y2',(mp.y+18-lL2).toFixed(1));
    lA.setAttribute('opacity',(s*0.88).toFixed(2));lA.setAttribute('stroke-width',(2+s*4).toFixed(1));
    lL.setAttribute('x',(mp.x+10).toFixed(0));lL.setAttribute('y',(mp.y-40-s*32).toFixed(0));
    lL.setAttribute('opacity',(s*0.78).toFixed(2));
    dA.setAttribute('opacity','0');dL.setAttribute('opacity','0');
  }else{
    const s=Math.abs(vel)*(1-op*0.7);
    const dL2=14+s*26;
    dA.setAttribute('x1',tp2.x+12);dA.setAttribute('y1',tp2.y+6);
    dA.setAttribute('x2',tp2.x+12);dA.setAttribute('y2',(tp2.y+6-dL2).toFixed(1));
    dA.setAttribute('opacity',(s*0.55).toFixed(2));
    dL.setAttribute('x',(tp2.x+22).toFixed(0));dL.setAttribute('y',(tp2.y-3).toFixed(0));
    dL.setAttribute('opacity',(s*0.45).toFixed(2));
    lA.setAttribute('opacity','0');lL.setAttribute('opacity','0');
  }

  /* 粒子 */
  aPs.forEach(p=>{
    p.y+=p.sp*wK*0.65;p.x+=Math.sin(p.y*0.007+p.sp)*0.25;
    if(p.y>790){p.y=-8;p.x=30+Math.random()*1300}
    p.el.setAttribute('cx',p.x.toFixed(0));p.el.setAttribute('cy',p.y.toFixed(0));
    const dW=Math.abs(p.y-C.py);
    p.el.setAttribute('opacity',dW<110?(0.06+0.16*(1-dW/110)).toFixed(2):'0.03');
  });
  gPs.forEach(p=>{
    if(!isDn&&op>0.32){
      if(!p.on){p.on=true;p.lf=0;const dist=C.fOff+p.idx*C.fSp;const pt3=qB(dist/C.sLen,C.px,C.py,mx,my,ex,ey);p.x=pt3.x+6;p.y=pt3.y+16}
      p.lf+=0.02*wK;p.y+=1.8*wK;p.x+=Math.sin(p.lf*6+p.idx*2)*0.5;
      const op2=Math.max(0,0.5*(1-p.lf)*(op-0.2));
      p.el.setAttribute('cx',p.x.toFixed(0));p.el.setAttribute('cy',p.y.toFixed(0));
      p.el.setAttribute('opacity',op2.toFixed(2));
      if(p.lf>1.3)p.on=false;
    }else{p.el.setAttribute('opacity','0');p.on=false}
  });

  /* 标注 */
  const a0=qB(0.11,C.px,C.py,mx,my,ex,ey);
  const a1=qB(0.62,C.px,C.py,mx,my,ex,ey);
  const a2=qB(0.3,C.px,C.py,mx,my,ex,ey);
  anE[0].el.setAttribute('x',(a0.x-12).toFixed(0));anE[0].el.setAttribute('y',(a0.y-26).toFixed(0));anE[0].el.setAttribute('opacity','0.65');
  anE[0].ln.setAttribute('x1',a0.x);anE[0].ln.setAttribute('y1',a0.y-4);anE[0].ln.setAttribute('x2',(a0.x-12).toFixed(0));anE[0].ln.setAttribute('y2',(a0.y-20).toFixed(0));
  anE[1].el.setAttribute('x',(a1.x-25).toFixed(0));anE[1].el.setAttribute('y',(a1.y+52+op*16).toFixed(0));anE[1].el.setAttribute('opacity',(0.35+op*0.4).toFixed(2));
  anE[1].ln.setAttribute('x1',a1.x);anE[1].ln.setAttribute('y1',(a1.y+38+op*8).toFixed(0));anE[1].ln.setAttribute('x2',(a1.x-25).toFixed(0));anE[1].ln.setAttribute('y2',(a1.y+47+op*14).toFixed(0));
  anE[2].el.setAttribute('x',(a2.x+15).toFixed(0));anE[2].el.setAttribute('y',(a2.y+20).toFixed(0));anE[2].el.setAttribute('opacity','0.5');
  anE[2].ln.setAttribute('x1',(a2.x+6).toFixed(0));anE[2].ln.setAttribute('y1',(a2.x+6).toFixed(0));anE[2].ln.setAttribute('x2',(a2.x+15).toFixed(0));anE[2].ln.setAttribute('y2',(a2.y+16).toFixed(0));

  /* 详情面板 */
  for(let i=0;i<5;i++){
    const bx=900+i*38,by=600;
    const rA2=C.cA+op*(C.oA-C.cA);
    const rd=rA2*Math.PI/180;
    dFs[i].sp.setAttribute('cx',bx);dFs[i].sp.setAttribute('cy',by);
    dFs[i].fm.setAttribute('x1',bx);dFs[i].fm.setAttribute('y1',by);
    dFs[i].fm.setAttribute('x2',(bx+55*Math.cos(rd)).toFixed(1));dFs[i].fm.setAttribute('y2',(by+55*Math.sin(rd)).toFixed(1));
    dFs[i].fm.setAttribute('opacity',(0.38+0.62*(1-op*0.3)).toFixed(2));
    dFs[i].fm.setAttribute('stroke',op>0.4?'#00c890':'#00f0b0');dFs[i].fm.setAttribute('stroke-width','0.8');
  }
  for(let i=0;i<4;i++){
    const bx=919+i*38;
    if(op>0.3){const aO=cl((op-0.25)*1.0,0,0.7);
      dArrs[i].setAttribute('x1',bx);dArrs[i].setAttribute('y1',608);dArrs[i].setAttribute('x2',bx+1);dArrs[i].setAttribute('y2',(632+op*14).toFixed(0));dArrs[i].setAttribute('opacity',aO.toFixed(2));
      dGLs[i].setAttribute('x1',bx);dGLs[i].setAttribute('y1',604);dGLs[i].setAttribute('x2',bx);dGLs[i].setAttribute('y2',618);dGLs[i].setAttribute('opacity',(aO*0.5).toFixed(2));
    }else{dArrs[i].setAttribute('opacity','0');dGLs[i].setAttribute('opacity','0')}
  }
  if(op<0.32){
    dOvR.setAttribute('x','895');dOvR.setAttribute('y','570');dOvR.setAttribute('width',(165*(1-op*2.8)).toFixed(0));dOvR.setAttribute('height','16');dOvR.setAttribute('opacity',(0.12*(1-op*2.8)).toFixed(2));
    dOvT.setAttribute('x','900');dOvT.setAttribute('y','582');dOvT.setAttribute('opacity',(0.45*(1-op*2.8)).toFixed(2));dOvT.textContent='重叠搭接区';
  }else{dOvR.setAttribute('opacity','0');dOvT.setAttribute('opacity','0')}
  dGT.textContent=op>0.32?`缝隙 ${(2+op*3).toFixed(1)} mm`:'闭合 (0 mm)';dGT.setAttribute('fill',op>0.32?'#3098e8':'#485870');
  dST.textContent=op>0.5?'▲ 泄气减阻模式':'▼ 闭合升推模式';dST.setAttribute('fill',op>0.5?'#3098e8':'#00f0b0');
  dTT.textContent=`τ = ${(0.02*sK).toFixed(3)} N·m`;
  dDT.textContent=op>0.5?'气动力 > 扭簧力 → 吹开':'气动力 < 扭簧力 → 闭合';
  dFT.textContent=op>0.5?`缝隙通气量: ${((op-0.3)*140).toFixed(0)}%`:'气动面连续度: 100%';
  dET.textContent='失效边界: 暴雨/结冰 → 开合失效';

  /* 波形 */
  const lV=isDn?Math.abs(vel)*(1-op*0.12):Math.abs(vel)*0.08*(1-op);
  const dV=isDn?Math.abs(vel)*0.28:Math.abs(vel)*(1-op*0.7);
  wD.l.push(lV);wD.d.push(dV);
  if(wD.l.length>wD.mx){wD.l.shift();wD.d.shift()}
  const cX=458,cY=578,cW=340,cH=125;
  let lp='',dp='';
  wD.l.forEach((v,i)=>{const x=cX+i*(cW/wD.mx);const y=cY+cH*0.45-v*cH*0.75;lp+=(i?'L':'M')+x.toFixed(1)+','+cl(y,cY,cY+cH).toFixed(1)});
  wD.d.forEach((v,i)=>{const x=cX+i*(cW/wD.mx);const y=cY+cH*0.5+v*cH*0.45;dp+=(i?'L':'M')+x.toFixed(1)+','+cl(y,cY,cY+cH).toFixed(1)});
  lPl.setAttribute('d',lp);dPl.setAttribute('d',dp);
  const nX=cX+wD.l.length*(cW/wD.mx);cNow.setAttribute('x1',nX.toFixed(1));cNow.setAttribute('x2',nX.toFixed(1));

  /* 相位时钟 */
  pHand.setAttribute('transform',`rotate(${(-90+t*360).toFixed(1)})`);

  /* UI */
  const pn=$('pn'),pde=$('pd');
  if(isDn){
    if(op<0.28){pn.textContent='下扑 · 闭合';pn.style.color='#00f0b0';pde.textContent='气动力压紧薄膜,形成连续气动面'}
    else{pn.textContent='下扑 · 过渡';pn.style.color='#d49030';pde.textContent='薄膜正在闭合...'}
  }else{
    if(op>0.52){pn.textContent='上扬 · 泄气';pn.style.color='#3098e8';pde.textContent='气动力吹开薄膜,缝隙泄气减阻'}
    else{pn.textContent='上扬 · 过渡';pn.style.color='#d49030';pde.textContent='薄膜正在打开...'}
  }
  $('pb').style.width=(t*100).toFixed(1)+'%';$('pb').style.background=isDn?'#00f0b0':'#3098e8';
  $('vl').textContent=(lV*100).toFixed(0)+'%';$('vl').style.color=lV>0.3?'#ff5040':'#485870';
  $('vd').textContent=(dV*100).toFixed(0)+'%';$('vd').style.color=dV>0.2?'#9070e8':'#485870';

  requestAnimationFrame(anim);
}
requestAnimationFrame(anim);
})();
</script>
</body>
</html>

这个动画以全新的视觉风格重新实现了"分段式柔性蒙皮与被动搭接骨架"的 IFR 最终理想解原理展示,主要特点:

视觉设计:采用深靛蓝底色 + 荧光薄荷绿薄膜 + 琥珀金翼梁的冷色调技术期刊美学,搭配 DM Serif Display 衬线标题与 IBM Plex Mono 等宽数据字体,营造精密工程文档质感。点阵背景、辉光滤镜和压力场可视化增强了空间层次。

核心机制可视化:下扑时薄膜闭合发光(连续气动面 + 底部暖色压力场),上扬时薄膜被动吹开(蓝色缝隙流粒子穿透),升力/阻力矢量箭头实时变化尺寸对比,直观展示升推-减阻矛盾的被动解耦。

三面板信息架构:左下 IFR 原理面板逐条阐释资源利用、矛盾破解与理想度;中部实时波形图滚动显示升力(红)与阻力(紫)的周期性解耦;右下细节面板放大展示薄膜开合状态、缝隙宽度、力矩平衡及通气量。

交互控制:扑动速度、扭簧刚度、来流强度三个滑块实时影响薄膜开合响应——增大扭簧刚度抑制打开幅度,增强来流加速开合响应,可深入体验被动自适应机制的参数敏感性。

<!DOCTYPE html>
<html lang="zh">
<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=DM+Serif+Display&family=Source+Code+Pro:wght@300;400;600&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<style>
:root{--bg:#07080d;--fg:#dfd8c6;--muted:#5c6a7e;--accent:#00e89c;--spar:#d49038;--lift:#ff5530;--drag:#8070f0;--air:#48b0e0;--spring:#f0c840;--card:rgba(10,12,18,0.94);--bdr:rgba(224,216,200,0.05)}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'Source Code Pro',monospace;min-height:100vh;overflow-x:hidden}
.serif{font-family:'DM Serif Display',serif}
input[type=range]{-webkit-appearance:none;appearance:none;width:100%;height:3px;background:rgba(224,216,200,0.07);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;background:var(--accent);border-radius:50%;cursor:pointer;box-shadow:0 0 8px rgba(0,232,156,0.4)}
input[type=range]::-moz-range-thumb{width:13px;height:13px;background:var(--accent);border-radius:50%;cursor:pointer;border:none}
.atmo{background:radial-gradient(ellipse at 22% 38%,rgba(212,144,56,0.022) 0%,transparent 52%),radial-gradient(ellipse at 78% 52%,rgba(0,232,156,0.016) 0%,transparent 46%)}
@keyframes pulse{0%,100%{opacity:.7}50%{opacity:1}}
</style>
</head>
<body class="atmo">

<div class="max-w-7xl mx-auto px-3 py-4 md:px-6">
  <header class="text-center mb-3">
    <h1 class="serif text-3xl md:text-5xl tracking-tight" style="color:var(--fg)">分段式柔性蒙皮与被动搭接骨架</h1>
    <p class="mt-1 text-[10px] tracking-[.3em] uppercase" style="color:var(--muted)">IFR 最终理想解 · 扑翼机原理动画</p>
  </header>

  <div class="relative rounded-2xl overflow-hidden" style="background:linear-gradient(150deg,rgba(7,8,13,.98),rgba(12,10,16,.98));border:1px solid var(--bdr)">
    <svg id="svg" viewBox="0 0 1400 800" style="display:block;width:100%"></svg>
  </div>

  <div class="grid grid-cols-2 md:grid-cols-5 gap-2 mt-3">
    <div class="rounded-xl p-3" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1" style="color:var(--muted)">扑动阶段</div>
      <div id="ph-n" class="text-sm font-semibold" style="color:var(--accent)">下扑·闭合</div>
      <div id="ph-d" class="text-[9px] mt-0.5" style="color:var(--muted)">气动力压紧薄膜</div>
      <div class="mt-1.5 h-1 rounded-full overflow-hidden" style="background:rgba(224,216,200,0.04)"><div id="ph-b" class="h-full rounded-full" style="width:0%;background:var(--accent);transition:none"></div></div>
    </div>
    <div class="rounded-xl p-3" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1" style="color:var(--muted)">扑动速度</div>
      <div class="flex justify-between text-[10px] mb-0.5"><span>慢</span><span id="v-s" style="color:var(--accent)">1.0x</span><span>快</span></div>
      <input type="range" id="s-s" min="0.3" max="2.5" step="0.1" value="1.0">
    </div>
    <div class="rounded-xl p-3" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1" style="color:var(--muted)">扭簧刚度</div>
      <div class="flex justify-between text-[10px] mb-0.5"><span>软</span><span id="v-k" style="color:var(--spring)">1.0x</span><span>硬</span></div>
      <input type="range" id="s-k" min="0.3" max="2.0" step="0.1" value="1.0">
    </div>
    <div class="rounded-xl p-3" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1" style="color:var(--muted)">来流强度</div>
      <div class="flex justify-between text-[10px] mb-0.5"><span>弱</span><span id="v-w" style="color:var(--air)">1.0x</span><span>强</span></div>
      <input type="range" id="s-w" min="0.3" max="2.0" step="0.1" value="1.0">
    </div>
    <div class="rounded-xl p-3" style="background:var(--card);border:1px solid var(--bdr)">
      <div class="text-[9px] uppercase tracking-[.2em] mb-1" style="color:var(--accent)">IFR</div>
      <div class="text-[9px] leading-[1.6]" style="color:var(--muted)">
        <div>被动响应 → 零能耗</div>
        <div>矛盾自解 → 复杂度不增</div>
        <div style="color:var(--accent);margin-top:2px;font-weight:600">额外能耗: 0 W</div>
      </div>
    </div>
  </div>
</div>

<script>
(function(){
'use strict';
const NS='http://www.w3.org/2000/svg';
const svg=document.getElementById('svg');
const $=id=>document.getElementById(id);

function el(t,a){const e=document.createElementNS(NS,t);for(const k in a)e.setAttribute(k,a[k]);return e}
function cl(v,lo,hi){return Math.max(lo,Math.min(hi,v))}
function qB(t,x0,y0,x1,y1,x2,y2){const u=1-t;return{x:u*u*x0+2*u*t*x1+t*t*x2,y:u*u*y0+2*u*t*y1+t*t*y2}}
function qT(t,x0,y0,x1,y1,x2,y2){const u=1-t;return{x:2*u*(x1-x0)+2*t*(x2-x1),y:2*u*(y1-y0)+2*t*(y2-y1)}}

/* ── 配置 ── */
const P={px:210,py:310,sLen:620,nF:7,fL:[108,118,120,112,96,76,54],fW:7.5,fSp:76,fOff:82,amp:22,per:3200,cA:88,oA:26,bend:.2};
let spd=1,sK=1,wK=1,t0=null;

$('s-s').oninput=function(){spd=+this.value;$('v-s').textContent=spd.toFixed(1)+'x'};
$('s-k').oninput=function(){sK=+this.value;$('v-k').textContent=sK.toFixed(1)+'x'};
$('s-w').oninput=function(){wK=+this.value;$('v-w').textContent=wK.toFixed(1)+'x'};

/* ── Defs ── */
const defs=el('defs',{});
function mkG(id,sd){const f=el('filter',{id,x:'-50%',y:'-50%',width:'200%',height:'200%'});f.appendChild(el('feGaussianBlur',{stdDeviation:String(sd),result:'b'}));const m=el('feMerge',{});m.appendChild(el('feMergeNode',{in:'b'}));m.appendChild(el('feMergeNode',{in:'SourceGraphic'}));f.appendChild(m);return f}
defs.appendChild(mkG('g1',4));defs.appendChild(mkG('g2',10));defs.appendChild(mkG('g3',2.5));
const spG=el('linearGradient',{id:'spG',x1:'0%',y1:'0%',x2:'0%',y2:'100%'});
spG.appendChild(el('stop',{offset:'0%','stop-color':'#f0c868'}));spG.appendChild(el('stop',{offset:'50%','stop-color':'#d49038'}));spG.appendChild(el('stop',{offset:'100%','stop-color':'#a87028'}));defs.appendChild(spG);
function mkA(id,c){const m=el('marker',{id,viewBox:'0 0 10 10',refX:'9',refY:'5',markerWidth:'7',markerHeight:'7',orient:'auto'});m.appendChild(el('path',{d:'M0,1.5 L10,5 L0,8.5z',fill:c}));return m}
defs.appendChild(mkA('aL','#ff5530'));defs.appendChild(mkA('aA','#48b0e0'));defs.appendChild(mkA('aD','#8070f0'));
svg.appendChild(defs);

/* ── 背景 ── */
svg.appendChild(el('rect',{x:0,y:0,width:1400,height:800,fill:'#07080d'}));
const dg=el('g',{opacity:'.028'});
for(let x=0;x<=1400;x+=45)for(let y=0;y<=800;y+=45)dg.appendChild(el('circle',{cx:x,cy:y,r:'.7',fill:'#dfd8c6'}));
svg.appendChild(dg);

/* ── 鸟身 ── */
const bG=el('g',{});
bG.appendChild(el('path',{d:`M${P.px-50},${P.py-26} Q${P.px-74},${P.py} ${P.px-56},${P.py+32} Q${P.px-30},${P.py+50} ${P.px+8},${P.py+22} Q${P.px+26},${P.py+3} ${P.px+14},${P.py-13} Q${P.px+3},${P.py-38} ${P.px-50},${P.py-26}Z`,fill:'rgba(12,14,20,.88)',stroke:'rgba(212,144,56,.1)','stroke-width':'1'}));
bG.appendChild(el('path',{d:`M${P.px-50},${P.py-26} Q${P.px-80},${P.py-38} ${P.px-90},${P.py-26} Q${P.px-84},${P.py-18} ${P.px-54},${P.py-22}`,fill:'rgba(12,14,20,.88)',stroke:'rgba(212,144,56,.06)','stroke-width':'.7'}));
bG.appendChild(el('path',{d:`M${P.px-90},${P.py-26} L${P.px-106},${P.py-22} L${P.px-90},${P.py-20}`,fill:'rgba(212,144,56,.28)'}));
bG.appendChild(el('circle',{cx:P.px-70,cy:P.py-26,r:'1.8',fill:'#d49038',opacity:'.55'}));
bG.appendChild(el('circle',{cx:P.px,cy:P.py,r:'8',fill:'#d49038',filter:'url(#g1)',opacity:'.75'}));
bG.appendChild(el('circle',{cx:P.px,cy:P.py,r:'3.2',fill:'#f0c868'}));
svg.appendChild(bG);

/* ── 气流粒子 ── */
const aG=el('g',{});
const aP=[];
for(let i=0;i<48;i++){const c=el('circle',{r:(1+Math.random()*1.4).toFixed(1),fill:'#48b0e0',opacity:'0'});aG.appendChild(c);aP.push({e:c,x:30+Math.random()*1300,y:Math.random()*800,s:.5+Math.random()*1.6,ph:Math.random()*6.28})}
const gP=[];
for(let i=0;i<30;i++){const c=el('circle',{r:(1.1+Math.random()*.7).toFixed(1),fill:'#00e89c',opacity:'0'});aG.appendChild(c);gP.push({e:c,x:0,y:0,vx:0,vy:0,li:0,on:false,idx:i%P.nF})}
svg.appendChild(aG);

/* ── 翅膀组 ── */
const wG=el('g',{id:'wG'});
const spE=el('path',{d:'',stroke:'url(#spG)','stroke-width':'9','stroke-linecap':'round',fill:'none',filter:'url(#g3)'});
wG.appendChild(spE);
const spH=el('path',{d:'',stroke:'rgba(240,200,104,.2)','stroke-width':'2.5','stroke-linecap':'round',fill:'none'});
wG.appendChild(spH);

const flm=[];
for(let i=P.nF-1;i>=0;i--){
  const fg=el('g',{});
  const sp=el('path',{d:'',fill:'none',stroke:'#f0c840','stroke-width':'1.1',opacity:'.55'});
  fg.appendChild(sp);
  const fm=el('path',{d:'',fill:'#00e89c',opacity:'.85','stroke-linejoin':'round'});
  fg.appendChild(fm);
  const ed=el('line',{stroke:'#00ffbb','stroke-width':'1.4',opacity:'.35','stroke-linecap':'round'});
  fg.appendChild(ed);
  wG.appendChild(fg);
  flm[i]={g:fg,fm,sp,ed};
}

/* 升力/阻力箭头 */
const lA=el('line',{stroke:'#ff5530','stroke-width':'4','marker-end':'url(#aL)',opacity:'0','stroke-linecap':'round'});wG.appendChild(lA);
const lL=el('text',{fill:'#ff5530','font-size':'13','font-family':'Source Code Pro,monospace','font-weight':'600',opacity:'0'});lL.textContent='LIFT 升力';wG.appendChild(lL);
const dA=el('line',{stroke:'#8070f0','stroke-width':'3','marker-end':'url(#aD)',opacity:'0','stroke-linecap':'round'});wG.appendChild(dA);
const dL=el('text',{fill:'#8070f0','font-size':'11','font-family':'Source Code Pro,monospace','font-weight':'600',opacity:'0'});dL.textContent='阻力 (减小)';wG.appendChild(dL);
svg.appendChild(wG);

/* ── 标注 ── */
const anG=el('g',{'font-family':'Source Code Pro,monospace'});
const anD=[
  {t:'弹性碳纤维主梁',c:'#d49038',s:10},
  {t:'柔性薄膜 (仿初级飞羽)',c:'#00e89c',s:9.5},
  {t:'扭簧 τ=0.02N·m',c:'#f0c840',s:9},
  {t:'重叠缝隙 2-5mm',c:'#48b0e0',s:8.5},
];
const anE=anD.map(a=>{const t=el('text',{fill:a.c,'font-size':a.s,'font-weight':'500',opacity:'0'});t.textContent=a.t;anG.appendChild(t);const l=el('line',{stroke:a.c,'stroke-width':'.5','stroke-dasharray':'3 3',opacity:'0'});anG.appendChild(l);return{t,l}});
svg.appendChild(anG);

/* ── IFR面板 ── */
const iG=el('g',{});
iG.appendChild(el('rect',{x:25,y:500,width:355,height:282,rx:8,fill:'rgba(10,12,18,.94)',stroke:'rgba(224,216,200,.04)','stroke-width':'1'}));
const iT=el('text',{x:45,y:528,fill:'#00e89c','font-size':'12','font-family':'Source Code Pro,monospace','font-weight':'600'});iT.textContent='IFR · 最终理想解原理';iG.appendChild(iT);
[
  {y:550,t:'▸ 资源:气动力(飞行中已存在,零额外输入)',c:'#5c6a7e'},
  {y:568,t:'▸ 矛盾:升力最大化 ↔ 阻力最小化',c:'#5c6a7e'},
  {y:590,t:'▸ 解法:被动响应 → 自适应开合',c:'#dfd8c6'},
  {y:608,t:'▸ 下扑:气动力 > 扭簧 → 闭合 → 连续气动面',c:'#00e89c'},
  {y:626,t:'▸ 上扬:气动力 < 扭簧 → 吹开 → 缝隙泄气',c:'#48b0e0'},
  {y:648,t:'▸ 理想度:系统自行消解矛盾,复杂度不增',c:'#dfd8c6'},
  {y:666,t:'▸ 关键:扭簧预紧 + 气动力 → 双向自适应',c:'#f0c840'},
  {y:688,t:'▸ 失效边界:暴雨/结冰 → 膜面附加质量改变',c:'#404858'},
  {y:706,t:'▸ 风险:高频弯折疲劳 / 气动弹性振荡',c:'#404858'},
  {y:728,t:'▸ 额外能耗:0 W (纯被动,无作动器)',c:'#00e89c'},
].forEach(l=>{const t=el('text',{x:45,y:l.y,fill:l.c,'font-size':'9','font-family':'Source Code Pro,monospace'});t.textContent=l.t;iG.appendChild(t)});
svg.appendChild(iG);

/* ── 详情面板 ── */
const dtG=el('g',{});
dtG.appendChild(el('rect',{x:810,y:500,width:565,height:282,rx:8,fill:'rgba(10,12,18,.94)',stroke:'rgba(224,216,200,.04)','stroke-width':'1'}));
const dtT=el('text',{x:835,y:528,fill:'#00e89c','font-size':'12','font-family':'Source Code Pro,monospace','font-weight':'600'});dtT.textContent='DETAIL · 薄膜开合细节';dtG.appendChild(dtT);
dtG.appendChild(el('line',{x1:855,y1:588,x2:1095,y2:588,stroke:'#d49038','stroke-width':'5','stroke-linecap':'round'}));
const dF=[];
for(let i=0;i<5;i++){const fg=el('g',{});const sp=el('circle',{r:3.8,fill:'none',stroke:'#f0c840','stroke-width':'1','stroke-dasharray':'2 2'});fg.appendChild(sp);const fm=el('line',{'stroke-width':'4.5','stroke-linecap':'round',stroke:'#00e89c',opacity:'.8'});fg.appendChild(fm);dtG.appendChild(fg);dF.push({g:fg,fm,sp})}
const dAr=[],dGl=[];
for(let i=0;i<4;i++){const a=el('line',{stroke:'#48b0e0','stroke-width':'1.4','marker-end':'url(#aA)',opacity:'0'});dtG.appendChild(a);dAr.push(a);const l=el('line',{stroke:'#48b0e0','stroke-width':'.7','stroke-dasharray':'3 2',opacity:'0'});dtG.appendChild(l);dGl.push(l)}
const dOR=el('rect',{fill:'rgba(0,232,156,.1)',rx:1,opacity:'0'});dtG.appendChild(dOR);
const dOT=el('text',{fill:'#00e89c','font-size':'7.5','font-family':'Source Code Pro,monospace',opacity:'0'});dtG.appendChild(dOT);
const dGT=el('text',{x:1110,y:582,fill:'#48b0e0','font-size':'10','font-family':'Source Code Pro,monospace'});dtG.appendChild(dGT);
const dST=el('text',{x:1110,y:602,fill:'#00e89c','font-size':'11','font-family':'Source Code Pro,monospace','font-weight':'600'});dtG.appendChild(dST);
const dTT=el('text',{x:1110,y:620,fill:'#f0c840','font-size':'9','font-family':'Source Code Pro,monospace'});dtG.appendChild(dTT);
const dDT=el('text',{x:1110,y:636,fill:'#5c6a7e','font-size':'8.5','font-family':'Source Code Pro,monospace'});dtG.appendChild(dDT);

/* 力矩平衡图 */
const fbG=el('g',{transform:'translate(860,660)'});
fbG.appendChild(el('rect',{x:0,y:0,width:200,height:105,rx:6,fill:'rgba(7,8,13,.8)',stroke:'rgba(224,216,200,.035)','stroke-width':'.5'}));
const fbT=el('text',{x:10,y:17,fill:'#dfd8c6','font-size':'9','font-family':'Source Code Pro,monospace','font-weight':'600'});fbT.textContent='力矩平衡 TORQUE BALANCE';fbG.appendChild(fbT);
const fbAL=el('text',{x:10,y:38,fill:'#48b0e0','font-size':'8','font-family':'Source Code Pro,monospace'});fbAL.textContent='气动力矩 →';fbG.appendChild(fbAL);
const fbSL=el('text',{x:10,y:55,fill:'#f0c840','font-size':'8','font-family':'Source Code Pro,monospace'});fbSL.textContent='扭簧力矩 ←';fbG.appendChild(fbSL);
const fbAB=el('rect',{x:10,y:62,width:0,height:8,rx:2,fill:'#48b0e0',opacity:'.7'});fbG.appendChild(fbAB);
const fbSB=el('rect',{x:10,y:74,width:0,height:8,rx:2,fill:'#f0c840',opacity:'.7'});fbG.appendChild(fbSB);
const fbR=el('text',{x:10,y:96,fill:'#00e89c','font-size':'9','font-family':'Source Code Pro,monospace','font-weight':'600'});fbG.appendChild(fbR);
dtG.appendChild(fbG);
svg.appendChild(dtG);

/* ── 波形面板 ── */
const cG=el('g',{});
cG.appendChild(el('rect',{x:400,y:500,width:395,height:282,rx:8,fill:'rgba(10,12,18,.94)',stroke:'rgba(224,216,200,.04)','stroke-width':'1'}));
const cT=el('text',{x:420,y:528,fill:'#dfd8c6','font-size':'12','font-family':'Source Code Pro,monospace','font-weight':'600'});cT.textContent='LIFT / DRAG WAVEFORM';cG.appendChild(cT);
cG.appendChild(el('line',{x1:565,y1:523,x2:588,y2:523,stroke:'#ff5530','stroke-width':'2'}));
const cL1=el('text',{x:593,y:527,fill:'#ff5530','font-size':'8','font-family':'Source Code Pro,monospace'});cL1.textContent='升力';cG.appendChild(cL1);
cG.appendChild(el('line',{x1:635,y1:523,x2:658,y2:523,stroke:'#8070f0','stroke-width':'2'}));
const cL2=el('text',{x:663,y:527,fill:'#8070f0','font-size':'8','font-family':'Source Code Pro,monospace'});cL2.textContent='阻力';cG.appendChild(cL2);
cG.appendChild(el('line',{x1:425,y1:545,x2:425,y2:768,stroke:'rgba(224,216,200,.07)','stroke-width':'1'}));
cG.appendChild(el('line',{x1:425,y1:758,x2:778,y2:758,stroke:'rgba(224,216,200,.07)','stroke-width':'1'}));
cG.appendChild(el('line',{x1:425,y1:658,x2:778,y2:658,stroke:'rgba(224,216,200,.03)','stroke-width':'.5','stroke-dasharray':'4 4'}));
const lP=el('path',{fill:'none',stroke:'#ff5530','stroke-width':'1.8',opacity:'.85'});cG.appendChild(lP);
const dP=el('path',{fill:'none',stroke:'#8070f0','stroke-width':'1.4',opacity:'.7'});cG.appendChild(dP);
const cN=el('line',{x1:778,y1:545,x2:778,y2:768,stroke:'#00e89c','stroke-width':'.8',opacity:'.25'});cG.appendChild(cN);
svg.appendChild(cG);
const wD={l:[],d:[],mx:190};

/* ── 相位时钟 ── */
const ckG=el('g',{transform:'translate(1345,55)'});
ckG.appendChild(el('circle',{cx:0,cy:0,r:34,fill:'rgba(10,12,18,.9)',stroke:'rgba(224,216,200,.05)','stroke-width':'1'}));
for(let i=0;i<12;i++){const a=i*Math.PI/6-Math.PI/2;ckG.appendChild(el('line',{x1:(28*Math.cos(a)).toFixed(1),y1:(28*Math.sin(a)).toFixed(1),x2:(32*Math.cos(a)).toFixed(1),y2:(32*Math.sin(a)).toFixed(1),stroke:'rgba(224,216,200,.1)','stroke-width':'.6'}))}
['闭合','升推','泄气','减阻'].forEach((t,i)=>{const a=i*Math.PI/2-Math.PI/2;const te=el('text',{x:(18*Math.cos(a)).toFixed(1),y:(18*Math.sin(a)+3).toFixed(1),fill:'rgba(224,216,200,.18)','font-size':'4.5','font-family':'Source Code Pro,monospace','text-anchor':'middle'});te.textContent=t;ckG.appendChild(te)});
const ckH=el('line',{x1:0,y1:0,x2:0,y2:-24,stroke:'#00e89c','stroke-width':'1.6','stroke-linecap':'round'});ckG.appendChild(ckH);
ckG.appendChild(el('circle',{cx:0,cy:0,r:2.2,fill:'#00e89c'}));
const ckL=el('text',{x:0,y:47,fill:'#5c6a7e','font-size':'6.5','font-family':'Source Code Pro,monospace','text-anchor':'middle'});ckL.textContent='PHASE';ckG.appendChild(ckL);
svg.appendChild(ckG);

/* ── 能耗标识 ── */
const eT=el('text',{x:1345,y:115,fill:'#00e89c','font-size':'10','font-family':'Source Code Pro,monospace','font-weight':'600','text-anchor':'middle',opacity:'.7'});eT.textContent='EXTRA ENERGY: 0W';svg.appendChild(eT);

/* ── 弹簧路径 ── */
function spD(r){let d=`M0,${-r}`;const n=10;for(let i=1;i<=n;i++){const a=-Math.PI/2+i*(Math.PI*1.5)/n;d+=` L${(r*.5*Math.cos(a)).toFixed(1)},${(r*.5*Math.sin(a)).toFixed(1)}`}return d}

/* ── 薄膜路径 ── */
function fmD(len,w,cv){
  const rw=w*.52,tw=w*.18;
  const cx1=len*.5+cv,cy1=-rw*.55;
  const cx2=len*.5+cv,cy2=rw*.55;
  return`M0,${(-rw).toFixed(1)} Q${cx1.toFixed(1)},${cy1.toFixed(1)} ${len},${(-tw).toFixed(1)} L${len},${tw.toFixed(1)} Q${cx2.toFixed(1)},${cy2.toFixed(1)} 0,${rw.toFixed(1)}Z`;
}

/* ── 主动画 ── */
function run(ts){
  if(!t0)t0=ts;
  const el2=(ts-t0)*spd;
  const per=P.per;
  const t=(el2%per)/per;

  const wDg=-P.amp*Math.cos(2*Math.PI*t);
  const vel=Math.sin(2*Math.PI*t);
  const isDn=vel>0;

  const eff=wK/Math.max(.3,sK);
  const raw=.5-.5*Math.tanh(vel*2.6*eff);
  const op=cl(raw,0,1);

  const bd=wDg*P.bend;
  const eX=P.px+P.sLen,eY=P.py+bd*2.5;
  const mX=P.px+P.sLen*.5,mY=P.py+bd*1.8;

  wG.setAttribute('transform',`rotate(${wDg.toFixed(2)},${P.px},${P.py})`);

  const sd=`M${P.px},${P.py} Q${mX},${mY} ${eX},${eY}`;
  spE.setAttribute('d',sd);
  spH.setAttribute('d',`M${P.px},${P.py-3.5} Q${mX},${mY-3.5} ${eX},${eY-3.5}`);

  /* 薄膜 */
  for(let i=0;i<P.nF;i++){
    const dist=P.fOff+i*P.fSp;
    const tp=dist/P.sLen;
    const pt=qB(tp,P.px,P.py,mX,mY,eX,eY);
    const tn=qT(tp,P.px,P.py,mX,mY,eX,eY);
    const sA=Math.atan2(tn.y,tn.x)*180/Math.PI;
    const rA=P.cA+op*(P.oA-P.cA);
    const aA=sA+rA;
    const cv=op*7*(1-i*.08);
    flm[i].fm.setAttribute('d',fmD(P.fL[i],P.fW,cv));
    const fO=.38+.62*(1-op*.35);
    const cls=op<.3;
    flm[i].fm.setAttribute('fill',cls?'#00e89c':'#00c088');
    flm[i].fm.setAttribute('opacity',fO.toFixed(2));
    if(cls)flm[i].fm.setAttribute('filter','url(#g3)');else flm[i].fm.removeAttribute('filter');
    const sR=5+op*2.5;
    flm[i].sp.setAttribute('d',spD(sR));
    flm[i].sp.setAttribute('opacity',(.28+op*.35).toFixed(2));
    const eH=P.fW*.5;
    flm[i].ed.setAttribute('x1','0');flm[i].ed.setAttribute('y1',(-eH).toFixed(1));
    flm[i].ed.setAttribute('x2','0');flm[i].ed.setAttribute('y2',eH.toFixed(1));
    flm[i].ed.setAttribute('opacity',(.18+op*.4).toFixed(2));
    flm[i].g.setAttribute('transform',`translate(${pt.x.toFixed(1)},${pt.y.toFixed(1)}) rotate(${aA.toFixed(1)})`);
  }

  /* 力矢量 */
  const md=qB(.4,P.px,P.py,mX,mY,eX,eY);
  const tp2=qB(.72,P.px,P.py,mX,mY,eX,eY);
  if(isDn){
    const s=Math.abs(vel);
    const ll=42+s*92;
    lA.setAttribute('x1',md.x);lA.setAttribute('y1',md.y+16);
    lA.setAttribute('x2',md.x);lA.setAttribute('y2',(md.y+16-ll).toFixed(1));
    lA.setAttribute('opacity',(s*.88).toFixed(2));lA.setAttribute('stroke-width',(2+s*3.5).toFixed(1));
    lL.setAttribute('x',(md.x+10).toFixed(0));lL.setAttribute('y',(md.y-38-s*28).toFixed(0));
    lL.setAttribute('opacity',(s*.72).toFixed(2));
    dA.setAttribute('opacity','0');dL.setAttribute('opacity','0');
  }else{
    const s=Math.abs(vel)*(1-op*.65);
    const dl=10+s*22;
    dA.setAttribute('x1',tp2.x+10);dA.setAttribute('y1',tp2.y+4);
    dA.setAttribute('x2',tp2.x+10);dA.setAttribute('y2',(tp2.y+4-dl).toFixed(1));
    dA.setAttribute('opacity',(s*.5).toFixed(2));
    dL.setAttribute('x',(tp2.x+20).toFixed(0));dL.setAttribute('y',(tp2.y-5).toFixed(0));
    dL.setAttribute('opacity',(s*.4).toFixed(2));
    lA.setAttribute('opacity','0');lL.setAttribute('opacity','0');
  }

  /* 气流粒子 */
  aP.forEach(p=>{
    p.y+=p.s*wK*.55;p.x+=Math.sin(p.y*.005+p.ph)*.22;
    if(p.y>810){p.y=-8;p.x=30+Math.random()*1300}
    p.e.setAttribute('cx',p.x.toFixed(0));p.e.setAttribute('cy',p.y.toFixed(0));
    const dW=Math.abs(p.y-P.py);
    p.e.setAttribute('opacity',dW<125?(.05+.13*(1-dW/125)).toFixed(2):'.025');
  });

  /* 缝隙粒子 */
  gP.forEach(p=>{
    if(!isDn&&op>.3){
      if(!p.on){p.on=true;p.li=0;const d=P.fOff+p.idx*P.fSp;const t2=d/P.sLen;const pt3=qB(t2,P.px,P.py,mX,mY,eX,eY);p.x=pt3.x+5;p.y=pt3.y+14;p.vx=(Math.random()-.5)*.4;p.vy=1.2+Math.random()*.8}
      p.li+=.018*wK;p.y+=p.vy*wK;p.x+=p.vx+Math.sin(p.li*5+p.idx*1.5)*.35;
      const o2=Math.max(0,.48*(1-p.li)*(op-.2));
      p.e.setAttribute('cx',p.x.toFixed(0));p.e.setAttribute('cy',p.y.toFixed(0));p.e.setAttribute('opacity',o2.toFixed(2));
      if(p.li>1.3)p.on=false;
    }else{p.e.setAttribute('opacity','0');p.on=false}
  });

  /* 标注 */
  const a0=qB(.1,P.px,P.py,mX,mY,eX,eY);
  const a1=qB(.6,P.px,P.py,mX,mY,eX,eY);
  const a2=qB(.28,P.px,P.py,mX,mY,eX,eY);
  const a3=qB(.48,P.px,P.py,mX,mY,eX,eY);
  const aPs=[{e:anE[0],px:a0.x-10,py:a0.y-28,lx:a0.x,ly:a0.y-4},{e:anE[1],px:a1.x-22,py:a1.y+48+op*14,lx:a1.x,ly:a1.y+32+op*7},{e:anE[2],px:a2.x+14,py:a2.y+24,lx:a2.x+4,ly:a2.y+9},{e:anE[3],px:a3.x+8,py:a3.y+52+op*10,lx:a3.x,ly:a3.y+38+op*5}];
  aPs.forEach((a,i)=>{
    a.e.t.setAttribute('x',a.px.toFixed(0));a.e.t.setAttribute('y',a.py.toFixed(0));
    a.e.t.setAttribute('opacity',i===3?(.25+op*.5).toFixed(2):'.55');
    a.e.l.setAttribute('x1',a.lx.toFixed(0));a.e.l.setAttribute('y1',a.ly.toFixed(0));
    a.e.l.setAttribute('x2',a.px.toFixed(0));a.e.l.setAttribute('y2',(a.py-3).toFixed(0));
    a.e.l.setAttribute('opacity','.2');
  });

  /* 详情面板 */
  for(let i=0;i<5;i++){
    const bx=865+i*42,by=588;
    const rA2=P.cA+op*(P.oA-P.cA);const rd=rA2*Math.PI/180;
    dF[i].sp.setAttribute('cx',bx);dF[i].sp.setAttribute('cy',by);
    dF[i].fm.setAttribute('x1',bx);dF[i].fm.setAttribute('y1',by);
    dF[i].fm.setAttribute('x2',(bx+52*Math.cos(rd)).toFixed(1));dF[i].fm.setAttribute('y2',(by+52*Math.sin(rd)).toFixed(1));
    dF[i].fm.setAttribute('opacity',(.38+.62*(1-op*.3)).toFixed(2));
    dF[i].fm.setAttribute('stroke',op>.4?'#00b080':'#00e89c');dF[i].fm.setAttribute('stroke-width','.6');
  }
  for(let i=0;i<4;i++){
    const bx=886+i*42;
    if(op>.3){const aO=cl((op-.25)*1.1,0,.65);
      dAr[i].setAttribute('x1',bx);dAr[i].setAttribute('y1',596);dAr[i].setAttribute('x2',bx+1);dAr[i].setAttribute('y2',(620+op*12).toFixed(0));dAr[i].setAttribute('opacity',aO.toFixed(2));
      dGl[i].setAttribute('x1',bx);dGl[i].setAttribute('y1',591);dGl[i].setAttribute('x2',bx);dGl[i].setAttribute('y2',605);dGl[i].setAttribute('opacity',(aO*.35).toFixed(2));
    }else{dAr[i].setAttribute('opacity','0');dGl[i].setAttribute('opacity','0')}
  }
  if(op<.35){const oW=Math.max(0,190*(1-op*2.8));dOR.setAttribute('x','863');dOR.setAttribute('y','558');dOR.setAttribute('width',oW.toFixed(0));dOR.setAttribute('height','14');dOR.setAttribute('opacity',(.1*(1-op*2.8)).toFixed(2));dOT.setAttribute('x','868');dOT.setAttribute('y','569');dOT.setAttribute('opacity',(.35*(1-op*2.8)).toFixed(2));dOT.textContent='◀ 重叠搭接区 ▶'}else{dOR.setAttribute('opacity','0');dOT.setAttribute('opacity','0')}
  dGT.textContent=op>.35?`缝隙 ${(2+op*3).toFixed(1)} mm`:'闭合 (0 mm)';dGT.setAttribute('fill',op>.35?'#48b0e0':'#5c6a7e');
  dST.textContent=op>.5?'▲ 泄气减阻模式':'▼ 闭合升推模式';dST.setAttribute('fill',op>.5?'#48b0e0':'#00e89c');
  dTT.textContent=`τ_spring = ${(0.02*sK).toFixed(3)} N·m`;
  dDT.textContent=op>.5?'气动力矩 < 扭簧力矩 → 吹开':'气动力矩 > 扭簧力矩 → 闭合';

  /* 力矩平衡条 */
  const aeroV=isDn?Math.abs(vel)*.85:Math.abs(vel)*.55;
  const sprV=.35*sK;
  const aW=cl(aeroV,0,1)*130;
  const sW=cl(sprV,0,1)*130;
  fbAB.setAttribute('width',aW.toFixed(0));
  fbSB.setAttribute('x',Math.max(10,140-sW).toFixed(0));fbSB.setAttribute('width',sW.toFixed(0));
  fbR.textContent=isDn?'→ 闭合 (气动力矩克服扭簧)':'→ 打开 (扭簧力矩推回)';

  /* 波形 */
  const lV=isDn?Math.abs(vel)*(1-op*.1):Math.abs(vel)*.06*(1-op);
  const dV=isDn?Math.abs(vel)*.22:Math.abs(vel)*(1-op*.7)*.45;
  wD.l.push(lV);wD.d.push(dV);
  if(wD.l.length>wD.mx){wD.l.shift();wD.d.shift()}
  let lp='',dp='';
  const cW=330,cH=88,cX=435,cY=558;
  wD.l.forEach((v,i)=>{const x=cX+i*(cW/wD.mx);const y=cY+cH*.5-v*cH*.9;lp+=(i?'L':'M')+x.toFixed(1)+','+cl(y,cY,cY+cH).toFixed(1)});
  wD.d.forEach((v,i)=>{const x=cX+i*(cW/wD.mx);const y=cY+cH*.5+v*cH*.55;dp+=(i?'L':'M')+x.toFixed(1)+','+cl(y,cY,cY+cH).toFixed(1)});
  lP.setAttribute('d',lp);dP.setAttribute('d',dp);
  const nX=cX+wD.l.length*(cW/wD.mx);cN.setAttribute('x1',nX.toFixed(1));cN.setAttribute('x2',nX.toFixed(1));

  /* 相位时钟 */
  ckH.setAttribute('transform',`rotate(${(-90+t*360).toFixed(1)})`);

  /* UI */
  const pn=$('ph-n'),pd=$('ph-d');
  if(isDn){
    if(op<.3){pn.textContent='下扑 · 闭合';pn.style.color='#00e89c';pd.textContent='气动力压紧薄膜,形成连续气动面'}
    else{pn.textContent='下扑 · 过渡';pn.style.color='#d49038';pd.textContent='薄膜正在被气动力压紧...'}
  }else{
    if(op>.55){pn.textContent='上扬 · 泄气';pn.style.color='#48b0e0';pd.textContent='气动力吹开薄膜,缝隙泄气减阻'}
    else{pn.textContent='上扬 · 过渡';pn.style.color='#d49038';pd.textContent='薄膜正在被气动力吹开...'}
  }
  $('ph-b').style.width=(t*100).toFixed(1)+'%';$('ph-b').style.background=isDn?'#00e89c':'#48b0e0';

  requestAnimationFrame(run);
}
requestAnimationFrame(run);
})();
</script>
</body>
</html>

本动画完整呈现了"分段式柔性蒙皮与被动搭接骨架"的 IFR 最终理想解工作原理,核心设计与实现要点如下:

IFR 聚焦展示:动画直接呈现理想解状态——下扑时薄膜被气动力自动压紧闭合(亮翠绿+辉光=连续气动面),上扬时被气动力吹开泄气(暗青色+蓝色缝隙流=减阻),全程纯被动、零额外能耗。

资源利用可视化:力矩平衡图(右下详情面板内)用双色条直观展示气动力矩与扭簧力矩的实时博弈关系——下扑时蓝色气动力矩条超过金色扭簧条→闭合;上扬时反转→打开。气动力作为已存在的免费资源,无需作动器即驱动开合。

视觉引导体系

  • 闭合态薄膜带辉光滤镜 + 升力大箭头(橙红色,尺寸随速度脉动)→ 关注升力产生
  • 打开态缝隙用蓝色气流箭头+绿色粒子穿透 → 关注减阻机制
  • 相位时钟实时旋转标注当前处于四阶段中的哪一段
  • 波形图同步绘制升力/阻力曲线,红色峰值与紫色谷值形成鲜明对比

交互控制:三个滑块可实时调节扑动速度、扭簧刚度和来流强度——增大扭簧刚度会抑制薄膜打开(需更强气动力才能吹开),增强来流则加速开合响应,用户可直观体验参数对被动响应特性的影响。

动画技术:基于 requestAnimationFrame 的连续渲染,页面加载即自动播放,重新加载自动从头开始。翼梁采用二次贝塞尔曲线模拟弹性弯曲,7片锥形薄膜沿翼梁切线方向安装,开合角度由角速度与扭簧刚度的双曲正切函数平滑插值。

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