独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>柔性铰接底盘 · 攀爬原理动画</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Noto+Sans+SC:wght@300;400;700&display=swap" rel="stylesheet">
<style>
:root{--bg:#060a12;--bg2:#0c1220;--fg:#d8e4f0;--muted:#5a7090;--accent:#00e5c8;--accent2:#ff6b35;--gold:#ffd700;--coral:#ff3366;--card:#0e1726;--border:#1c2d45}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--fg);font-family:'Noto Sans SC',sans-serif;min-height:100vh;display:flex;flex-direction:column;align-items:center;overflow-x:hidden}
header{text-align:center;padding:1.6rem 1rem .8rem}
header h1{font-family:'Orbitron',sans-serif;font-weight:900;font-size:clamp(1rem,3vw,1.7rem);letter-spacing:.14em;color:var(--accent);text-shadow:0 0 28px rgba(0,229,200,.25)}
header p{color:var(--muted);font-size:.85rem;margin-top:.35rem;font-weight:300;letter-spacing:.06em}
.wrap{width:95%;max-width:1020px;background:var(--card);border:1px solid var(--border);border-radius:12px;overflow:hidden;box-shadow:0 0 50px rgba(0,229,200,.04),0 16px 40px rgba(0,0,0,.35);margin:.8rem 0}
svg{width:100%;height:auto;display:block}
.ctrls{display:flex;gap:1.6rem;padding:.9rem 1.6rem;background:var(--bg2);border-top:1px solid var(--border);flex-wrap:wrap;justify-content:center;align-items:center}
.cg{display:flex;align-items:center;gap:.6rem}
.cg label{font-size:.78rem;color:var(--muted);white-space:nowrap}
.cg input[type=range]{-webkit-appearance:none;appearance:none;width:110px;height:4px;background:var(--border);border-radius:2px;outline:none}
.cg input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:15px;height:15px;background:var(--accent);border-radius:50%;cursor:pointer;box-shadow:0 0 6px rgba(0,229,200,.35)}
.cg .vd{font-family:'Orbitron',sans-serif;font-size:.72rem;color:var(--accent);min-width:2.4rem}
.btn{font-family:'Noto Sans SC',sans-serif;font-size:.78rem;padding:.35rem .9rem;background:transparent;color:var(--accent);border:1px solid var(--accent);border-radius:6px;cursor:pointer;transition:all .2s}
.btn:hover{background:rgba(0,229,200,.1)}
.cards{width:95%;max-width:1020px;display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:.9rem;padding:0 0 2rem}
.card{background:var(--card);border:1px solid var(--border);border-radius:8px;padding:1.1rem}
.card h3{font-family:'Orbitron',sans-serif;font-size:.65rem;letter-spacing:.1em;color:var(--accent2);margin-bottom:.5rem;text-transform:uppercase}
.card p{font-size:.8rem;color:var(--muted);line-height:1.65}
.hl{color:var(--accent);font-weight:700}
</style>
</head>
<body>
<header>
<h1>FLEXIBLE ARTICULATED CHASSIS</h1>
<p>多段铰接柔性底盘 · 被动重塑攀爬原理 · IFR 演示</p>
</header>
<div class="wrap">
<svg id="svg" viewBox="0 0 820 470" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="gl" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="4" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<filter id="gl2" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="7" result="b"/><feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
<pattern id="grid" width="22" height="22" patternUnits="userSpaceOnUse"><path d="M22 0L0 0 0 22" fill="none" stroke="#141e32" stroke-width=".4"/></pattern>
<linearGradient id="stG" x1="0" y1="0" x2="0" y2="1"><stop offset="0%" stop-color="#1a2640"/><stop offset="100%" stop-color="#0f1828"/></linearGradient>
</defs>
<rect width="820" height="470" fill="#070c16"/>
<rect width="820" height="470" fill="url(#grid)" opacity=".35"/>
<g id="gStairs"></g>
<g id="gShadow"></g>
<g id="gTrack"></g>
<g id="gSegs"></g>
<g id="gJoints"></g>
<g id="gFx"></g>
<g id="gAnn"></g>
</svg>
<div class="ctrls">
<div class="cg"><label>动画速度</label><input type="range" id="rSpeed" min=".2" max="3" step=".1" value="1"><span class="vd" id="vSpeed">1.0x</span></div>
<div class="cg"><label>台阶高度</label><input type="range" id="rStep" min="30" max="80" step="5" value="55"><span class="vd" id="vStep">55</span></div>
<button class="btn" id="bReset">重置动画</button>
</div>
</div>
<div class="cards">
<div class="card"><h3>Core Principle</h3><p>底盘由 <span class="hl">5 段独立驱动舱段</span> 通过万向节串联,放弃刚性轮毂,使车体形态随地形被动重塑,像毛毛虫一样蠕动攀爬。</p></div>
<div class="card"><h3>Key Parameters</h3><p>万向节最大偏转 <span class="hl">45°</span>,独立驱动舱段 <span class="hl">5 段</span>,各段电机独立驱动外围宽体橡胶履带。</p></div>
<div class="card"><h3>IFR Insight</h3><p>系统无需主动感知地形——<span class="hl">接触力本身即控制信号</span>,地形塑造形态,形态适配地形,资源自洽,矛盾自消解。</p></div>
</div>
<script>
(function(){
const NS='http://www.w3.org/2000/svg';
const el=id=>document.getElementById(id);
const gStairs=el('gStairs'),gShadow=el('gShadow'),gTrack=el('gTrack'),gSegs=el('gSegs'),gJoints=el('gJoints'),gFx=el('gFx'),gAnn=el('gAnn');
/* ── 参数 ── */
const NSeg=5,SW=50,SH=20,JG=6,TT=7,MB=Math.PI/4,UNIT=SW+JG,RL=NSeg*SW+(NSeg-1)*JG;
let stepRise=55,stepRun=105,groundY=395,speed=1,progress=0,lastT=null,paused=false,pauseT=0;
/* ── 路径 ── */
let prof=[],cumD=[];
function buildProf(){
const sX=300;
prof=[
{x:20,y:groundY},{x:sX,y:groundY},
{x:sX,y:groundY-stepRise},{x:sX+stepRun,y:groundY-stepRise},
{x:sX+stepRun,y:groundY-2*stepRise},{x:sX+2*stepRun,y:groundY-2*stepRise},
{x:sX+2*stepRun,y:groundY-3*stepRise},{x:800,y:groundY-3*stepRise}
];
cumD=[0];
for(let i=1;i<prof.length;i++){const dx=prof[i].x-prof[i-1].x,dy=prof[i].y-prof[i-1].y;cumD.push(cumD[i-1]+Math.sqrt(dx*dx+dy*dy));}
}
function totalLen(){return cumD[cumD.length-1]}
function ptAt(a){
a=Math.max(0,Math.min(a,totalLen()));
for(let i=1;i<cumD.length;i++){
if(a<=cumD[i]+.01){
const sl=cumD[i]-cumD[i-1],t=sl>0?(a-cumD[i-1])/sl:0;
return{x:prof[i-1].x+t*(prof[i].x-prof[i-1].x),y:prof[i-1].y+t*(prof[i].y-prof[i-1].y),a:Math.atan2(prof[i].y-prof[i-1].y,prof[i].x-prof[i-1].x)};
}
}
const l=prof[prof.length-1];return{x:l.x,y:l.y,a:0};
}
/* ── 运动学链 ── */
function compute(fe){
const st=[];
// 段0跟随路径
const p0=ptAt(fe-SW/2);
st.push({cx:p0.x+Math.sin(p0.a)*SH/2,cy:p0.y-Math.cos(p0.a)*SH/2,a:p0.a,ja:0});
for(let i=1;i<NSeg;i++){
const prev=st[i-1];
const des=ptAt(fe-SW/2-i*UNIT);
let d=des.a-prev.a;
while(d>Math.PI)d-=2*Math.PI;while(d<-Math.PI)d+=2*Math.PI;
d=Math.max(-MB,Math.min(MB,d));
const sa=prev.a+d;
const pd={x:Math.cos(prev.a),y:Math.sin(prev.a)};
const cd={x:Math.cos(sa),y:Math.sin(sa)};
const pb={x:prev.cx-pd.x*SW/2,y:prev.cy-pd.y*SW/2};
const gd={x:-(pd.x+cd.x)/2,y:-(pd.y+cd.y)/2};
const gl=Math.sqrt(gd.x*gd.x+gd.y*gd.y)||1;
gd.x/=gl;gd.y/=gl;
const cf={x:pb.x+gd.x*JG,y:pb.y+gd.y*JG};
st.push({cx:cf.x-cd.x*SW/2,cy:cf.y-cd.y*SW/2,a:sa,ja:d});
}
return st;
}
/* ── SVG 工具 ── */
function mk(t,a){const e=document.createElementNS(NS,t);for(const[k,v]of Object.entries(a))e.setAttribute(k,v);return e;}
/* ── 绘制台阶 ── */
function drawStairs(){
gStairs.innerHTML='';
const sX=300;
for(let i=0;i<3;i++){
const x1=sX+i*stepRun,y1=groundY,x2=x1+stepRun,y2=groundY-(i+1)*stepRise;
gStairs.appendChild(mk('polygon',{points:`${x1},${y1} ${x2},${y1} ${x2},${y2} ${x1},${y2}`,fill:'url(#stG)',stroke:'#253550','stroke-width':1}));
// 横线纹理
for(let yy=Math.min(y1,y2)+12;yy<Math.max(y1,y2);yy+=14){
gStairs.appendChild(mk('line',{x1:x1+4,x2:x2-4,y1:yy,y2:yy,stroke:'#1a2842','stroke-width':.6}));
}
gStairs.appendChild(mk('line',{x1:x1,y1:y1,x2:x1,y2:y2,stroke:'#3a5a80','stroke-width':1.8}));
gStairs.appendChild(mk('line',{x1:x1,y1:y2,x2:x2,y2:y2,stroke:'#3a5a80','stroke-width':1.2}));
// 台阶编号
const tx=mk('text',{x:(x1+x2)/2,y:y2-8,'text-anchor':'middle','font-family':'Orbitron,sans-serif','font-size':'9',fill:'#2e4a68',opacity:.7});
tx.textContent='S'+(i+1);gStairs.appendChild(tx);
}
// 地面线
gStairs.appendChild(mk('line',{x1:20,y1:groundY,x2:sX,y2:groundY,stroke:'#3a5a80','stroke-width':1.5}));
const topY=groundY-3*stepRise;
gStairs.appendChild(mk('line',{x1:sX+2*stepRun,y1:topY,x2:800,y2:topY,stroke:'#3a5a80','stroke-width':1.5}));
// 高度标注
const dimX=sX-18;
for(let i=0;i<3;i++){
const yt=groundY-(i+1)*stepRise,yb=groundY-i*stepRise;
gStairs.appendChild(mk('line',{x1:dimX,y1:yt,x2:dimX,y2:yb,stroke:'#4a6a90','stroke-width':.8,'marker-start':'none','marker-end':'none'}));
gStairs.appendChild(mk('line',{x1:dimX-3,y1:yt,x2:dimX+3,y2:yt,stroke:'#4a6a90','stroke-width':.8}));
gStairs.appendChild(mk('line',{x1:dimX-3,y1:yb,x2:dimX+3,y2:yb,stroke:'#4a6a90','stroke-width':.8}));
const dt=mk('text',{x:dimX-4,y:(yt+yb)/2+3,'text-anchor':'end','font-family':'Orbitron,sans-serif','font-size':'7',fill:'#5a8aaa'});
dt.textContent=stepRise;gStairs.appendChild(dt);
}
}
/* ── 角落计算 ── */
function corners(s){
const c=Math.cos(s.a),sn=Math.sin(s.a),hw=SW/2,hh=SH/2;
return[
{x:s.cx+c*hw-sn*hh,y:s.cy+sn*hw+c*hh}, // 前下
{x:s.cx+c*hw+sn*hh,y:s.cy+sn*hw-c*hh}, // 前上
{x:s.cx-c*hw+sn*hh,y:s.cy-sn*hw-c*hh}, // 后上
{x:s.cx-c*hw-sn*hh,y:s.cy-sn*hw+c*hh}, // 后下
];
}
/* ── 弧线点 ── */
function arcPts(cx,cy,r,sa,ea,n){
const p=[];for(let i=0;i<=n;i++){const a=sa+(i/n)*(ea-sa);p.push({x:cx+r*Math.cos(a),y:cy+r*Math.sin(a)});}return p;
}
/* ── 绘制机器人 ── */
function drawRobot(st,fe){
gShadow.innerHTML='';gTrack.innerHTML='';gSegs.innerHTML='';gJoints.innerHTML='';gFx.innerHTML='';
// 投影
for(let i=0;i<NSeg;i++){
const s=st[i],cn=corners(s);
const sp=cn.map(p=>`${p.x+3},${p.y+5}`).join(' ');
gShadow.appendChild(mk('polygon',{points:sp,fill:'rgba(0,0,0,.18)',filter:'url(#gl)'}));
}
// 履带轮廓路径
const allC=st.map(s=>corners(s));
let d='';
// 底边 前→后
d+=`M${allC[0][0].x},${allC[0][0].y} `;
for(let i=0;i<NSeg;i++){d+=`L${allC[i][3].x},${allC[i][3].y} `;if(i<NSeg-1)d+=`L${allC[i+1][0].x},${allC[i+1][0].y} `;}
// 后盖弧
const ls=st[NSeg-1];
const bcx=ls.cx-Math.cos(ls.a)*SW/2,bcy=ls.cy-Math.sin(ls.a)*SW/2;
const bap=arcPts(bcx,bcy,SH/2,ls.a+Math.PI/2,ls.a+3*Math.PI/2,10);
for(const p of bap)d+=`L${p.x},${p.y} `;
// 顶边 后→前
for(let i=NSeg-1;i>=0;i--){d+=`L${allC[i][2].x},${allC[i][2].y} `;if(i>0)d+=`L${allC[i-1][1].x},${allC[i-1][1].y} `;}
// 前盖弧
const fs=st[0];
const fcx=fs.cx+Math.cos(fs.a)*SW/2,fcy=fs.cy+Math.sin(fs.a)*SW/2;
const fap=arcPts(fcx,fcy,SH/2,fs.a-Math.PI/2,fs.a+Math.PI/2,10);
for(const p of fap)d+=`L${p.x},${p.y} `;
d+='Z';
// 履带底色
gTrack.appendChild(mk('path',{d,fill:'none',stroke:'#c85520','stroke-width':TT,'stroke-linejoin':'round','stroke-linecap':'round',opacity:.75}));
// 履带花纹
gTrack.appendChild(mk('path',{d,fill:'none',stroke:'#ff8844','stroke-width':TT-2.5,'stroke-dasharray':'4 5.5','stroke-dashoffset':-fe*1.4,'stroke-linejoin':'round','stroke-linecap':'round',opacity:.45}));
// 履带高光
gTrack.appendChild(mk('path',{d,fill:'none',stroke:'#ffaa66','stroke-width':1.2,'stroke-dasharray':'2 9','stroke-dashoffset':-fe*1.4+3,'stroke-linejoin':'round','stroke-linecap':'round',opacity:.3}));
// 舱段
for(let i=0;i<NSeg;i++){
const s=st[i],cn=allC[i];
const pts=cn.map(p=>`${p.x},${p.y}`).join(' ');
gSegs.appendChild(mk('polygon',{points:pts,fill:'#0b2530',stroke:'#00c8aa','stroke-width':1.4,opacity:.92}));
// 电机轮
gSegs.appendChild(mk('circle',{cx:s.cx,cy:s.cy,r:6.5,fill:'none',stroke:'#00e5c8','stroke-width':.9,opacity:.6}));
gSegs.appendChild(mk('circle',{cx:s.cx,cy:s.cy,r:2.8,fill:'#00e5c8',opacity:.85}));
// 舱段编号
const nt=mk('text',{x:s.cx,y:s.cy+3.5,'text-anchor':'middle','font-family':'Orbitron,sans-serif','font-size':'6',fill:'#005544',opacity:.7,'font-weight':'700'});
nt.textContent=i+1;gSegs.appendChild(nt);
}
// 关节
for(let i=0;i<NSeg-1;i++){
const s1=st[i],s2=st[i+1];
const b1={x:s1.cx-Math.cos(s1.a)*SW/2,y:s1.cy-Math.sin(s1.a)*SW/2};
const f2={x:s2.cx+Math.cos(s2.a)*SW/2,y:s2.cy+Math.sin(s2.a)*SW/2};
const jx=(b1.x+f2.x)/2,jy=(b1.y+f2.y)/2;
const ad=Math.abs(s2.ja)*180/Math.PI;
const active=ad>5;
// 连接线
gJoints.appendChild(mk('line',{x1:b1.x,y1:b1.y,x2:f2.x,y2:f2.y,stroke:active?'#ffd700':'#1a3a4a','stroke-width':active?1.5:.8,opacity:active?.7:.4}));
// 关节点
gJoints.appendChild(mk('circle',{cx:jx,cy:jy,r:active?4.5:3,fill:active?'#ffd700':'#15303e',stroke:active?'#ffaa00':'#254050','stroke-width':active?1.8:1,filter:active?'url(#gl)':'none'}));
// 角度标注
if(ad>8){
const at=mk('text',{x:jx,y:jy-10,'text-anchor':'middle','font-family':'Orbitron,sans-serif','font-size':'8.5',fill:'#ffd700',filter:'url(#gl)',opacity:.95});
at.textContent=Math.round(ad)+'°';gJoints.appendChild(at);
}
}
// 接触力效果
for(let i=0;i<NSeg;i++){
const s=st[i];
// 检测是否在台阶立面附近
const faceXs=[300,300+stepRun,300+2*stepRun];
for(const fx of faceXs){
if(Math.abs(s.cx-fx)<SW*.7&&Math.abs(s.a)>0.15){
const fy1=groundY,fy2=groundY-stepRise;
// 力箭头
const al=22;
const ax=fx-4,ay=Math.max(fy2,Math.min(fy1,s.cy));
const ex=ax-al*Math.sin(s.a)*.6,ey=ay+al*Math.cos(s.a)*.6;
gFx.appendChild(mk('line',{x1:ax,y1:ay,x2:ex,y2:ey,stroke:'#ff3366','stroke-width':2,opacity:.7}));
// 箭头头部
const hd=5,ha=.45;
gFx.appendChild(mk('polygon',{points:`${ex},${ey} ${ex+hd*Math.cos(s.a+ha+Math.PI/2)},${ey+hd*Math.sin(s.a+ha+Math.PI/2)} ${ex+hd*Math.cos(s.a-ha+Math.PI/2)},${ey+hd*Math.sin(s.a-ha+Math.PI/2)}`,fill:'#ff3366',opacity:.7}));
// 接触火花
for(let k=0;k<3;k++){
const ox=ax+4+Math.random()*8,oy=ay-4+Math.random()*8;
gFx.appendChild(mk('circle',{cx:ox,cy:oy,r:1+Math.random(),fill:'#ff6644',opacity:.3+Math.random()*.4}));
}
}
}
}
}
/* ── 标注 ── */
function drawAnn(st,fe){
gAnn.innerHTML='';
const tl=totalLen();
// 阶段标签
let phase='';
if(fe<280)phase='平地行进 — 舱段共面';
else if(fe<tl-200)phase='自适应攀爬 — 被动折叠';
else phase='恢复平直 — 自重复位';
const pt=mk('text',{x:410,y:452,'text-anchor':'middle','font-family':'Noto Sans SC,sans-serif','font-size':'12.5',fill:'#00e5c8',opacity:.7,'font-weight':'400'});
pt.textContent='▸ '+phase;gAnn.appendChild(pt);
// IFR 标注(攀爬阶段显示)
if(fe>310&&fe<tl-180){
const op=Math.min(1,(fe-310)/60)*Math.min(1,(tl-180-fe)/60)*.85;
// 连接线
const tgt=st[0];
const lx=Math.min(tgt.cx+40,620),ly=Math.max(tgt.cy-50,60);
gAnn.appendChild(mk('line',{x1:tgt.cx,y1:tgt.cy-14,x2:lx,y2:ly+12,stroke:'#ffd700','stroke-width':.7,'stroke-dasharray':'3 3',opacity:op*.6}));
const t1=mk('text',{x:lx+4,y:ly,'text-anchor':'start','font-family':'Noto Sans SC,sans-serif','font-size':'10.5',fill:'#ffd700',opacity:op,'font-weight':'700'});
t1.textContent='IFR:接触力 = 控制信号';gAnn.appendChild(t1);
const t2=mk('text',{x:lx+4,y:ly+15,'text-anchor':'start','font-family':'Noto Sans SC,sans-serif','font-size':'9',fill:'#aa9040',opacity:op*.8});
t2.textContent='地形塑造形态 → 形态适配地形';gAnn.appendChild(t2);
}
// 履带驱动方向标注
if(fe>290&&fe<tl-100){
const op2=Math.min(1,(fe-290)/50)*.55;
// 在履带上方画运动箭头
const midSeg=st[Math.floor(NSeg/2)];
const arrX=midSeg.cx,arrY=midSeg.cy-SH/2-TT-6;
const ad=midSeg.a;
gAnn.appendChild(mk('line',{x1:arrX-12*Math.cos(ad),y1:arrY-12*Math.sin(ad),x2:arrX+12*Math.cos(ad),y2:arrY+12*Math.sin(ad),stroke:'#ff6b35','stroke-width':1.3,opacity:op2,'marker-end':'none'}));
const at=mk('text',{x:arrX,y:arrY-6,'text-anchor':'middle','font-family':'Orbitron,sans-serif','font-size':'7',fill:'#ff6b35',opacity:op2});
at.textContent='TRACK DRIVE';gAnn.appendChild(at);
}
// 进度条
const pbW=180,pbX=620,pbY=450,pbH=4;
gAnn.appendChild(mk('rect',{x:pbX,y:pbY,width:pbW,height:pbH,rx:2,fill:'#1a2540',opacity:.5}));
const pct=Math.max(0,Math.min(1,(fe-RL)/(tl-RL)));
gAnn.appendChild(mk('rect',{x:pbX,y:pbY,width:pbW*pct,height:pbH,rx:2,fill:'#00e5c8',opacity:.6}));
}
/* ── 动画循环 ── */
function animate(ts){
if(!lastT)lastT=ts;
const dt=(ts-lastT)/1000;
lastT=ts;
if(paused){
pauseT-=dt;
if(pauseT<=0)paused=false;
}else{
progress+=dt*55*speed;
if(progress>totalLen()+60){
progress=RL+20;
paused=true;pauseT=.6;
}
}
const fe=progress;
const st=compute(fe);
drawRobot(st,fe);
drawAnn(st,fe);
requestAnimationFrame(animate);
}
/* ── 控件 ── */
const rSpeed=el('rSpeed'),vSpeed=el('vSpeed'),rStep=el('rStep'),vStep=el('vStep'),bReset=el('bReset');
rSpeed.oninput=()=>{speed=parseFloat(rSpeed.value);vSpeed.textContent=speed.toFixed(1)+'x';};
rStep.oninput=()=>{stepRise=parseInt(rStep.value);vStep.textContent=stepRise;buildProf();drawStairs();};
bReset.onclick=()=>{progress=RL+20;lastT=null;paused=false;};
/* ── 初始化 ── */
buildProf();drawStairs();
progress=RL+20;
function start(){requestAnimationFrame(animate);}
if(document.readyState==='complete')start();
else window.addEventListener('load',start);
document.addEventListener('DOMContentLoaded',()=>{if(!lastT)start();});
})();
</script>
</body>
</html>
实现说明:
核心原理动画化:采用正向运动学链(Forward Kinematic Chain)模拟 5 段铰接底盘的被动折叠过程。首段沿地形路径行走,后续各段受 45° 关节限位约束逐级跟随弯曲,自然呈现"毛毛虫式"攀爬形态。
IFR 思想视觉引导:
- 接触力即控制信号:当舱段接触台阶立面时,自动显示红色力箭头与接触火花,金色标注 "IFR:接触力 = 控制信号" 在攀爬阶段淡入,强调无需主动传感的自适应机制。
- 关节激活可视化:弯曲超过 5° 的关节以金色发光高亮,并实时显示偏转角度数值,直观展示"地形塑造形态"的过程。
履带动画:通过
stroke-dashoffset随进度变量连续偏移,模拟履带花纹的滚动效果;三层叠绘(底色 + 花纹 + 高光)营造厚度与质感。交互控制:
- 速度滑块(0.2x–3x):调节攀爬动画速率
- 台阶高度滑块(30–80):动态重建台阶几何,实时观察不同高度的适应性
- 重置按钮:重新从平地起步
自动播放:页面加载后立即启动
requestAnimationFrame循环,循环结束自动重置并短暂停顿后重播,确保"重开即播"。
积分规则:第一轮对话扣减8分,后续每轮扣6分
等待动画代码生成...
