Spaces:
Running
Running
| <html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>VTWM — action conditioning</title><style> | |
| :root{ | |
| --bg:#f7f7f8; --panel:#ffffff; --ink:#16181d; --sub:#5c6270; --line:#e6e8ec; | |
| --accent:#4f46e5; --accent2:#0ea5e9; | |
| --ok:#0f9d58; --okbg:#e7f6ee; --warn:#c77700; --warnbg:#fdf3e3; --bad:#d92d20; --badbg:#fdeceb; | |
| --win:#0f9d58; --winbg:#e7f6ee; | |
| --radius:16px; --shadow:0 1px 2px rgba(16,24,40,.04),0 8px 24px rgba(16,24,40,.06); | |
| } | |
| @media(prefers-color-scheme:dark){:root{ | |
| --bg:#0d0f14; --panel:#151922; --ink:#eaecef; --sub:#98a1b3; --line:#232936; | |
| --accent:#8b8cf7; --accent2:#38bdf8; | |
| --ok:#37d399; --okbg:#0f2a20; --warn:#f2b34b; --warnbg:#2a2110; --bad:#f77066; --badbg:#2a1414; | |
| --win:#37d399; --winbg:#0f2a20; | |
| --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 24px rgba(0,0,0,.35); | |
| }} | |
| *{box-sizing:border-box} | |
| html{scroll-behavior:smooth;scroll-padding-top:96px} | |
| body{margin:0;background:var(--bg);color:var(--ink); | |
| font:15px/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased} | |
| .wrap{max-width:1200px;margin:0 auto;padding:0 20px} | |
| .hero{padding:56px 0 26px} | |
| .hero .kick{color:var(--accent);font-weight:700;letter-spacing:.08em;text-transform:uppercase;font-size:12px} | |
| .hero h1{margin:.25em 0 .35em;font-size:clamp(26px,4vw,40px);line-height:1.1;letter-spacing:-.02em} | |
| .hero p.lede{margin:0;color:var(--sub);max-width:74ch;font-size:16px} | |
| .reading{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius); | |
| padding:14px 18px;margin:18px 0 4px;box-shadow:var(--shadow);font-size:13.5px;color:var(--sub)} | |
| .reading b{color:var(--ink)} | |
| .dot{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:5px} | |
| .legend{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px;margin:22px 0 4px} | |
| .chip{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:12px 14px;box-shadow:var(--shadow)} | |
| .chip b{display:block;font-size:14px;margin-bottom:3px}.chip span{color:var(--sub);font-size:12.5px;line-height:1.45} | |
| nav.sticky{position:sticky;top:0;z-index:20;background:color-mix(in srgb,var(--bg) 82%,transparent); | |
| backdrop-filter:saturate(150%) blur(10px);border-bottom:1px solid var(--line);margin-top:24px} | |
| nav.sticky .wrap{display:flex;gap:7px;flex-wrap:wrap;align-items:center;padding-top:10px;padding-bottom:10px} | |
| nav.sticky a{color:var(--sub);text-decoration:none;font-weight:600;font-size:13px;padding:5px 11px;border-radius:999px;border:1px solid transparent} | |
| nav.sticky a:hover{color:var(--ink);border-color:var(--line);background:var(--panel)} | |
| nav.sticky .ngrp{color:var(--accent);font-weight:700;text-transform:uppercase;letter-spacing:.06em;font-size:10.5px;padding-left:8px} | |
| .band{border-top:1px solid var(--line);margin-top:8px} | |
| .band-h{padding:34px 0 2px}.band-h .t{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--accent)} | |
| .band-h h2.big{margin:.2em 0 .1em;font-size:24px;letter-spacing:-.01em} | |
| .band-h p{margin:0;color:var(--sub);max-width:80ch;font-size:14.5px} | |
| section.run{padding:30px 0;border-top:1px solid var(--line)} | |
| .run-head h2{margin:0 0 4px;font-size:20px;letter-spacing:-.01em} | |
| .run-head p{margin:0 0 18px;color:var(--sub);max-width:82ch} | |
| .cols{display:grid;grid-template-columns:minmax(400px,1fr) minmax(430px,1.15fr);gap:26px;align-items:start} | |
| @media(max-width:980px){.cols{grid-template-columns:1fr}} | |
| .xwrap{display:grid;grid-template-columns:minmax(280px,.7fr) minmax(520px,1.6fr);gap:26px;align-items:start} | |
| @media(max-width:980px){.xwrap{grid-template-columns:1fr}} | |
| h3{font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--sub);margin:0 0 12px} | |
| .qt{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--line); | |
| border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow);font-variant-numeric:tabular-nums} | |
| .qt th{text-align:right;font-size:12px;color:var(--sub);font-weight:600;padding:11px 14px;border-bottom:1px solid var(--line)} | |
| .qt th:first-child{text-align:left} | |
| .qt td{padding:9px 14px;border-bottom:1px solid var(--line)} | |
| .qt tr:last-child td{border-bottom:none} | |
| .qt .mname{font-weight:500}.qt .arrow{color:var(--sub);font-size:11px} | |
| .qt .num{text-align:right} | |
| .qt tr.grp td{background:color-mix(in srgb,var(--accent) 7%,var(--panel));font-size:11px;text-transform:uppercase; | |
| letter-spacing:.05em;color:var(--sub);font-weight:700;padding:7px 14px} | |
| .gap-ok{color:var(--ok);background:var(--okbg);font-weight:600;border-radius:6px} | |
| .gap-warn{color:var(--warn);background:var(--warnbg);font-weight:600;border-radius:6px} | |
| .gap-bad{color:var(--bad);background:var(--badbg);font-weight:700;border-radius:6px} | |
| .win{color:var(--win);background:var(--winbg);font-weight:700;border-radius:6px} | |
| .seg{display:inline-flex;background:var(--panel);border:1px solid var(--line);border-radius:999px;padding:3px;margin-bottom:14px} | |
| .seg-b{border:none;background:transparent;color:var(--sub);font:inherit;font-weight:600;font-size:13px;padding:5px 16px;border-radius:999px;cursor:pointer} | |
| .seg-b.active{background:var(--accent);color:#fff} | |
| .pane{display:none}.pane.show{display:block} | |
| .grid{display:grid;grid-template-columns:repeat(2,1fr);gap:14px} | |
| @media(max-width:560px){.grid{grid-template-columns:1fr}} | |
| .xgal{display:grid;grid-template-columns:1fr 1fr;gap:16px} | |
| @media(max-width:720px){.xgal{grid-template-columns:1fr}} | |
| .xcol-h{font-size:12px;font-weight:700;letter-spacing:.03em;color:var(--ink);margin:0 0 10px; | |
| padding:6px 10px;background:var(--panel);border:1px solid var(--line);border-radius:8px;display:inline-block} | |
| .cgrid{display:grid;grid-template-columns:1fr;gap:12px} | |
| .scard{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:10px;box-shadow:var(--shadow)} | |
| .scard-h{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--sub);font-weight:700;margin:2px 4px 8px} | |
| .vid{margin:0 0 8px}.vid:last-of-type{margin-bottom:2px} | |
| .vid video{width:100%;display:block;border-radius:8px;background:#000;aspect-ratio:2/1;object-fit:cover} | |
| .vid figcaption{font-size:11.5px;color:var(--sub);margin-top:4px;display:flex;justify-content:space-between} | |
| .vid .gtp{color:var(--accent2);font-weight:600} | |
| .empty{color:var(--sub);font-style:italic;padding:16px} | |
| .ctrl{display:flex;align-items:center;gap:9px;margin-top:8px;padding:2px 2px 0} | |
| .pp{flex:0 0 auto;width:30px;height:30px;border-radius:8px;border:1px solid var(--line);background:var(--panel); | |
| color:var(--ink);font-size:12px;cursor:pointer;display:grid;place-items:center} | |
| .pp:hover{border-color:var(--accent)} | |
| .scrub{flex:1 1 auto;-webkit-appearance:none;appearance:none;height:5px;border-radius:999px;background:var(--line);cursor:pointer;outline:none} | |
| .scrub::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--accent);border:2px solid var(--panel);box-shadow:0 1px 3px rgba(0,0,0,.3)} | |
| .scrub::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--accent);border:2px solid var(--panel)} | |
| .tlabel{flex:0 0 auto;font-size:11px;color:var(--sub);font-variant-numeric:tabular-nums;min-width:38px;text-align:right} | |
| footer{border-top:1px solid var(--line);padding:26px 0 50px;color:var(--sub);font-size:12.5px;margin-top:20px} | |
| </style></head><body><div class="wrap"> | |
| <header class="hero"><div class="kick">Tactile world model · action conditioning</div> | |
| <h1>Does spatial sensor-pose conditioning help contact dynamics?</h1> | |
| <p class="lede">Goal: a better action-conditioning method for visuo-tactile contact. We render each GelSight | |
| sensor's projected image location as a per-frame Gaussian heatmap and inject it (zero-init) into the view | |
| tokens — CameraCtrl/EA-WM style. <b>Result across all representations (heatmap channel, mask channel, in-target overlay): in-target > side-channel (novel ablation), but none beats contact-supervision (contactw1 0.202).</b> Below: exactly what each model adds, the added | |
| input, and the prediction results.</p></header> | |
| <div class="band-h"><div class="t">1 · What each model adds (single-variable chain)</div></div> | |
| <table class="qt"><thead><tr><th>knob</th><th>p01rand</th><th>contactw1</th><th>senshm(σ1.6)</th><th>senshm(σ0.6)</th><th>senshm+depth</th></tr></thead><tbody> | |
| <tr><td class="mname">contact-region supervision</td><td class="num">✗</td><td class="num win">✓ w1.0</td><td class="num">✓</td><td class="num">✓</td><td class="num">✓</td></tr> | |
| <tr><td class="mname">sensor-pose heatmap (spatial cond)</td><td class="num">✗</td><td class="num">✗</td><td class="num">✓</td><td class="num">✓</td><td class="num">✓</td></tr> | |
| <tr><td class="mname">heatmap σ</td><td class="num">—</td><td class="num">—</td><td class="num">1.6</td><td class="num">0.6</td><td class="num">0.6</td></tr> | |
| <tr><td class="mname">depth channel</td><td class="num">—</td><td class="num">—</td><td class="num">✗</td><td class="num">✗</td><td class="num">✓</td></tr></tbody></table> | |
| <div class="band-h"><div class="t">2 · Contact IoU (val) — spatial conditioning HURTS</div></div> | |
| <table class="qt"><thead><tr><th>run</th><th>contact IoU (val)↑</th><th>view LPIPS↓</th><th>tactile-L LPIPS↓</th></tr></thead><tbody> | |
| <tr><td class="mname">p01rand</td><td class="num">0.173</td><td class="num">—</td><td class="num">—</td></tr> | |
| <tr><td class="mname">contactw1 (best)</td><td class="num win">0.202</td><td class="num win">0.046</td><td class="num">0.094</td></tr> | |
| <tr><td class="mname">senshm σ1.6</td><td class="num bad">0.147</td><td class="num bad">0.069</td><td class="num">0.095</td></tr> | |
| <tr><td class="mname">senshm heatmap (σ0.6/depth)</td><td class="num bad">0.146 / 0.157</td><td class="num">—</td><td class="num">—</td></tr><tr><td class="mname">B · mask channel</td><td class="num bad">0.158</td><td class="num">—</td><td class="num">—</td></tr><tr><td class="mname">A · overlay-in-target</td><td class="num">0.169</td><td class="num">—</td><td class="num">—</td></tr></tbody></table><p style="color:var(--sub);font-size:13px"><b>Key ablation (novel):</b> in-target overlay (0.169) > side-channel mask (0.158) > heatmap (0.15) — representation ordering matches Genima/In-Video-Instructions. But all < contactw1 (0.202): spatial pose re-representation adds no held-out contact signal (camera-frame ≠ gel-frame).</p> | |
| <p style="color:var(--sub);font-size:13.5px">Adding the heatmap degraded <b>both</b> visual and tactile, train and val — while latent val_loss stayed ~equal (0.0467). The signal is <b>redundant</b> (pose already in the global action tokens + visible in the views) and a <b>harmful perturbation</b>; and the camera-frame location doesn't map to gel-frame contact.</p> | |
| <div class="band-h"><div class="t">3 · The added INPUT — sensor-pose heatmap</div> | |
| <p>Each GelSight sensor's 3D pose is projected (calibrated) into every camera view and rendered as a Gaussian. Left: it tracks the sensors over time across 3 views. Right: the 16×16 heatmap the model receives.</p></div> | |
| <img src="proj_track.png" style="max-width:100%;border:1px solid var(--line);border-radius:12px;margin-bottom:12px"> | |
| <img src="input_heatmap.png" style="max-width:100%;border:1px solid var(--line);border-radius:12px"> | |
| <div class="band-h"><div class="t">4 · Input + prediction (contact maps)</div> | |
| <p>Columns: <b>view + sensor heatmap (INPUT) · GT contact · contactw1 pred · senshm pred</b> (red = above τ=8).</p></div> | |
| <img src="why_figure.png" style="max-width:100%;border:1px solid var(--line);border-radius:12px"> | |
| <div class="band-h"><div class="t">5 · Prediction videos — p01rand | contactw1 | senshm</div> | |
| <p>Matched val windows. Play/scrub; view is the clock.</p></div> | |
| <section class="run"><div class="run-head"><h2>window 0</h2><p>2026-05-10__episode_005.pt · t=606 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w0_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w0_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w0_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w0_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section><section class="run"><div class="run-head"><h2>window 1</h2><p>2026-05-10__episode_006.pt · t=1116 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w1_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w1_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w1_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w1_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section><section class="run"><div class="run-head"><h2>window 2</h2><p>2026-05-10__episode_006.pt · t=1226 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w2_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w2_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w2_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w2_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section><section class="run"><div class="run-head"><h2>window 3</h2><p>2026-05-10__episode_006.pt · t=1238 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w3_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w3_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w3_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w3_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section><section class="run"><div class="run-head"><h2>window 4</h2><p>2026-05-10__episode_006.pt · t=1420 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w4_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w4_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w4_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w4_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section><section class="run"><div class="run-head"><h2>window 5</h2><p>2026-05-10__episode_006.pt · t=2460 — GT ‖ prediction. rows: middle view, tactile L/R.</p></div><div class="xgal" style="grid-template-columns:1fr 1fr 1fr"><div class="scard"><div class="scard-h">contactw1</div><figure class="vid"><video src="media/w5_contactw1_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_contactw1_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_contactw1_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">overlay</div><figure class="vid"><video src="media/w5_overlay_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_overlay_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_overlay_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div><div class="scard"><div class="scard-h">mask</div><figure class="vid"><video src="media/w5_mask_view.mp4" muted playsinline preload="auto" data-lead="1"></video><figcaption>middle view <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_mask_tl.mp4" muted playsinline preload="auto"></video><figcaption>tactile · left <span class="gtp">GT · pred</span></figcaption></figure><figure class="vid"><video src="media/w5_mask_tr.mp4" muted playsinline preload="auto"></video><figcaption>tactile · right <span class="gtp">GT · pred</span></figcaption></figure><div class="ctrl"><button class="pp">▶</button><input class="scrub" type="range" min="0" max="1000" value="0" step="1"></input><span class="tlabel">0/16</span></div></div></div></section> | |
| </div><script> | |
| document.querySelectorAll('.qual').forEach(q=>{ | |
| const panes=q.querySelectorAll('.pane'), btns=q.querySelectorAll('.seg-b'); | |
| function sel(t){panes.forEach(p=>p.classList.toggle('show',p.dataset.split===t)); | |
| btns.forEach(b=>b.classList.toggle('active',b.dataset.t===t));} | |
| btns.forEach(b=>b.addEventListener('click',()=>sel(b.dataset.t))); | |
| }); | |
| const FPS=6; | |
| document.querySelectorAll('.scard').forEach(card=>{ | |
| const vids=[...card.querySelectorAll('video')]; | |
| const lead=card.querySelector('video[data-lead]')||vids[0]; | |
| const bar=card.querySelector('.scrub'), btn=card.querySelector('.pp'), lbl=card.querySelector('.tlabel'); | |
| let userPaused=false, visible=false, dur=0, nF=16; | |
| function seekAll(t){vids.forEach(v=>{if(Math.abs(v.currentTime-t)>0.03){try{v.currentTime=t;}catch(e){}}});} | |
| function paint(){const t=lead.currentTime; if(dur) bar.value=Math.round(t/dur*1000); | |
| lbl.textContent=Math.min(Math.round(t*FPS),nF)+'/'+nF;} | |
| lead.addEventListener('loadedmetadata',()=>{dur=lead.duration||0;nF=Math.max(1,Math.round(dur*FPS));paint();}); | |
| lead.addEventListener('timeupdate',()=>{ | |
| vids.forEach(v=>{if(v!==lead&&Math.abs(v.currentTime-lead.currentTime)>0.05){try{v.currentTime=lead.currentTime;}catch(e){}}});paint();}); | |
| lead.addEventListener('ended',()=>{seekAll(0); if(!userPaused&&visible) playAll();}); | |
| function playAll(){btn.textContent='⏸';vids.forEach(v=>v.play().catch(()=>{}));} | |
| function pauseAll(){btn.textContent='▶';vids.forEach(v=>v.pause());} | |
| btn.addEventListener('click',()=>{ if(lead.paused){userPaused=false;playAll();} else {userPaused=true;pauseAll();} }); | |
| bar.addEventListener('input',()=>{userPaused=true;pauseAll();seekAll(parseInt(bar.value,10)/1000*(dur||0));paint();}); | |
| new IntersectionObserver(es=>es.forEach(e=>{visible=e.isIntersecting; | |
| if(visible&&!userPaused) playAll(); else if(!visible) pauseAll();}),{threshold:0.2}).observe(card); | |
| }); | |
| </script></body></html> |