Spaces:
Running
Running
Download index.html from yxma/react-action-debug: direct link, hf CLI and curl.
- Browser
- Download file 6.63 kB
-
https://huggingface.co/spaces/yxma/react-action-debug/resolve/main/index.html
- Command line
-
hf download hf://spaces/yxma/react-action-debug/index.html
-
curl -L -o index.html https://huggingface.co/spaces/yxma/react-action-debug/resolve/main/index.html
6.63 kB
| <html lang="zh"><head><meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>React action debug — episode_006_seg00</title> | |
| <style> | |
| :root{--bg:#0e1116;--panel:#161b22;--line:#30363d;--fg:#e6edf3;--dim:#8b949e; | |
| --L:#58a6ff;--R:#ff9d4d;--hi:#f85149} | |
| *{box-sizing:border-box} body{margin:0;background:var(--bg);color:var(--fg); | |
| font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace} | |
| header{padding:10px 14px;border-bottom:1px solid var(--line)} | |
| h1{margin:0;font-size:15px;font-weight:600} | |
| .sub{color:var(--dim);font-size:12px;margin-top:2px} | |
| #stage{background:#000;text-align:center;border-bottom:1px solid var(--line)} | |
| #stage img{max-width:100%;display:block;margin:0 auto;image-rendering:auto} | |
| .bar{display:flex;gap:8px;align-items:center;padding:8px 14px;flex-wrap:wrap; | |
| border-bottom:1px solid var(--line)} | |
| button{background:var(--panel);color:var(--fg);border:1px solid var(--line); | |
| border-radius:5px;padding:4px 10px;cursor:pointer;font:inherit} | |
| button:hover{border-color:var(--dim)} button.on{border-color:var(--L);color:var(--L)} | |
| input[type=range]{flex:1;min-width:220px;accent-color:var(--L)} | |
| .tag{color:var(--dim)} .val{font-variant-numeric:tabular-nums} | |
| .readout{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); | |
| gap:6px 16px;padding:8px 14px;border-bottom:1px solid var(--line)} | |
| .readout div{white-space:nowrap} | |
| .L{color:var(--L)} .R{color:var(--R)} | |
| canvas{display:block;width:100%;height:120px;border-bottom:1px solid var(--line)} | |
| .cap{padding:3px 14px;color:var(--dim);font-size:11px} | |
| kbd{background:var(--panel);border:1px solid var(--line);border-radius:3px;padding:0 4px} | |
| </style></head><body> | |
| <header> | |
| <h1>action debug · motherboard / 2026-09-11 / episode_006_seg00</h1> | |
| <div class="sub" id="hdr">loading…</div> | |
| <div class="sub"><a href="shift.html" style="color:#58a6ff">→ mocap 时间偏移检查(±8 帧滑块)</a></div> | |
| </header> | |
| <div id="stage"><img id="frame" alt=""></div> | |
| <div class="bar"> | |
| <button id="play">▶ 播放</button> | |
| <button id="prev">◀ 帧</button><button id="next">帧 ▶</button> | |
| <input id="slider" type="range" min="0" value="0"> | |
| <span class="tag">row</span><span class="val" id="row">—</span> | |
| <button id="stepmode" class="on">步长 2 (15Hz)</button> | |
| <button id="jump">跳到样本窗口</button> | |
| </div> | |
| <div class="readout"> | |
| <div><span class="tag">force</span> <span class="L">L <b class="val" id="fl">—</b> N</span> · <span class="R">R <b class="val" id="fr">—</b> N</span></div> | |
| <div><span class="tag">penetration F/k</span> <span class="L"><b class="val" id="pl">—</b></span> · <span class="R"><b class="val" id="pr">—</b></span> mm</div> | |
| <div><span class="tag">Δ 法向 (1帧)</span> <span class="L"><b class="val" id="d1l">—</b></span> · <span class="R"><b class="val" id="d1r">—</b></span> mm</div> | |
| <div><span class="tag">Δ 法向 (2帧)</span> <span class="L"><b class="val" id="d2l">—</b></span> · <span class="R"><b class="val" id="d2r">—</b></span> mm</div> | |
| </div> | |
| <canvas id="cf"></canvas><div class="cap">force (N) — 蓝 L / 橙 R,红带为样本窗口 rows 1592–1622</div> | |
| <canvas id="cd"></canvas><div class="cap">Δ action 沿传感器法向 (mm per 2 frames) — 训练样本用的就是这个步长</div> | |
| <div class="cap"><kbd>←</kbd><kbd>→</kbd> 单帧 · <kbd>空格</kbd> 播放/暂停 · <kbd>Home</kbd> 回到开头</div> | |
| <script> | |
| const $=id=>document.getElementById(id); | |
| let D=null,i=0,playing=false,step=2,timer=null; | |
| const pad=n=>String(n).padStart(4,'0'); | |
| fetch('data.json').then(r=>r.json()).then(d=>{ | |
| D=d; $('slider').max=d.n-1; | |
| $('hdr').textContent=`rows ${d.start_row}–${d.start_row+d.n-1} · ${d.n} 帧 @ ${d.fps}fps · k=${d.stiffness_n_per_mm} N/mm · 样本窗口 rows 1592–1622 (步长2)`; | |
| draw(); show(0); | |
| }); | |
| function show(k){ | |
| i=Math.max(0,Math.min(D.n-1,k)); | |
| $('frame').src='frames/f'+pad(i+1)+'.jpg'; | |
| $('slider').value=i; $('row').textContent=D.rows[i]; | |
| const f=(a,n)=>a[i]==null?'—':a[i].toFixed(n); | |
| $('fl').textContent=f(D.force_left,2); $('fr').textContent=f(D.force_right,2); | |
| $('pl').textContent=f(D.pen_left,2); $('pr').textContent=f(D.pen_right,2); | |
| $('d1l').textContent=f(D.d1_left,2); $('d1r').textContent=f(D.d1_right,2); | |
| $('d2l').textContent=f(D.d2_left,2); $('d2r').textContent=f(D.d2_right,2); | |
| draw(); | |
| } | |
| function series(c,arrs,cols,zero){ | |
| const ctx=c.getContext('2d'),W=c.width=c.clientWidth*devicePixelRatio, | |
| H=c.height=120*devicePixelRatio; | |
| ctx.clearRect(0,0,W,H); | |
| let lo=Infinity,hi=-Infinity; | |
| arrs.forEach(a=>a.forEach(v=>{if(v!=null){lo=Math.min(lo,v);hi=Math.max(hi,v);}})); | |
| if(zero){lo=Math.min(lo,0);hi=Math.max(hi,0);} | |
| if(!isFinite(lo)){lo=0;hi=1;} if(hi-lo<1e-6)hi=lo+1; | |
| const pad=(hi-lo)*0.08; lo-=pad; hi+=pad; | |
| const X=k=>k/(D.n-1)*W, Y=v=>H-(v-lo)/(hi-lo)*H; | |
| // 样本窗口高亮 | |
| ctx.fillStyle='rgba(248,81,73,.16)'; | |
| ctx.fillRect(X(D.highlight[0]),0,X(D.highlight[1])-X(D.highlight[0]),H); | |
| if(lo<0&&hi>0){ctx.strokeStyle='#30363d';ctx.lineWidth=devicePixelRatio; | |
| ctx.beginPath();ctx.moveTo(0,Y(0));ctx.lineTo(W,Y(0));ctx.stroke();} | |
| arrs.forEach((a,n)=>{ctx.strokeStyle=cols[n];ctx.lineWidth=1.4*devicePixelRatio; | |
| ctx.beginPath();let up=false; | |
| a.forEach((v,k)=>{if(v==null){up=false;return;} | |
| up?ctx.lineTo(X(k),Y(v)):ctx.moveTo(X(k),Y(v));up=true;}); | |
| ctx.stroke();}); | |
| ctx.strokeStyle='#e6edf3';ctx.lineWidth=devicePixelRatio; | |
| ctx.beginPath();ctx.moveTo(X(i),0);ctx.lineTo(X(i),H);ctx.stroke(); | |
| } | |
| function draw(){ if(!D)return; | |
| series($('cf'),[D.force_left,D.force_right],['#58a6ff','#ff9d4d'],true); | |
| series($('cd'),[D.d2_left,D.d2_right],['#58a6ff','#ff9d4d'],true); } | |
| $('slider').oninput=e=>show(+e.target.value); | |
| $('prev').onclick=()=>show(i-step); $('next').onclick=()=>show(i+step); | |
| $('stepmode').onclick=e=>{step=step===1?2:1; | |
| e.target.textContent=step===2?'步长 2 (15Hz)':'步长 1 (30Hz)';e.target.classList.toggle('on',step===2);}; | |
| $('jump').onclick=()=>show(D.highlight[0]); | |
| $('play').onclick=()=>{playing=!playing;$('play').textContent=playing?'⏸ 暂停':'▶ 播放'; | |
| if(playing){timer=setInterval(()=>{if(i>=D.n-1){show(0);}else show(i+step);},1000/30*step);} | |
| else clearInterval(timer);}; | |
| addEventListener('keydown',e=>{ | |
| if(e.key==='ArrowLeft'){show(i-step);e.preventDefault();} | |
| if(e.key==='ArrowRight'){show(i+step);e.preventDefault();} | |
| if(e.key==='Home'){show(0);e.preventDefault();} | |
| if(e.code==='Space'){$('play').click();e.preventDefault();}}); | |
| addEventListener('resize',draw); | |
| </script></body></html> | |