multimodalart HF Staff commited on
Commit
304b499
·
verified ·
1 Parent(s): ed12abd

Revert look/pan to keyboard IJKL (replacing mouse-look), keep WASD movement

Browse files
Files changed (1) hide show
  1. index.html +23 -66
index.html CHANGED
@@ -126,6 +126,11 @@
126
  .keycap[data-k="A"]{grid-column:1;grid-row:2}
127
  .keycap[data-k="S"]{grid-column:2;grid-row:2}
128
  .keycap[data-k="D"]{grid-column:3;grid-row:2}
 
 
 
 
 
129
 
130
  .look-info{font-size:12.5px;color:var(--muted);line-height:1.6}
131
  .look-info b{color:var(--text)}
@@ -145,7 +150,7 @@
145
  <div class="logo">🌍</div>
146
  <div>
147
  <h1>ABot-World — Interactive World Rollout</h1>
148
- <p>Upload a starting frame, then steer a live action-conditioned world with WASD + mouse-look.</p>
149
  </div>
150
  </div>
151
  <div class="links">
@@ -164,7 +169,7 @@
164
  <div class="chip"><span class="dot" id="status-dot"></span><span id="status-label">Idle</span></div>
165
  <div class="chip"><span id="fps-value">0</span> fps · <span id="frame-value">0</span> blk</div>
166
  </div>
167
- <div class="capture-hint" id="capture-hint">Click to capture · WASD to move · mouse to look · Esc to release</div>
168
  <div class="overlay" id="overlay">
169
  <div>
170
  <div class="spinner" id="spinner" style="display:none"></div>
@@ -188,16 +193,18 @@
188
  </div>
189
  <div>
190
  <div class="label" style="margin-bottom:8px">Look / pan</div>
191
- <div class="look-info">
192
- Move the world camera with your <b>mouse</b>. Click the view to capture
193
- the pointer, then move the mouse to look &amp; pan. Press <b>Esc</b> to release.
 
 
194
  </div>
195
- <div class="look-badge" id="look-badge"><span class="d"></span><span id="look-badge-text">Mouse-look idle</span></div>
196
  </div>
197
  </div>
198
  <div class="hint-line">
199
  <b>W A S D</b> — move &amp; turn (hold to steer the next block) ·
200
- <b>Mouse</b> — look / pan. Click the video to capture input.
201
  </div>
202
  <div class="active-tags" id="active-tags"></div>
203
  </div>
@@ -243,12 +250,13 @@ import { Client } from "https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.m
243
  const SESSION_ID = (crypto.randomUUID && crypto.randomUUID()) ||
244
  (`s-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`);
245
 
246
- // Movement keys are driven by the keyboard (WASD); look/pan (I J K L) is now
247
- // driven by mouse movement (pointer-lock mouse-look) — see mouse-look block.
248
  const MOVE_KEYS = new Set(["W","A","S","D"]);
249
  const LOOK_KEYS = new Set(["I","J","K","L"]);
250
  const KEY_FROM_CODE = {
251
  KeyW:"W", KeyA:"A", KeyS:"S", KeyD:"D",
 
252
  };
253
 
254
  const state = {
@@ -533,29 +541,25 @@ function startCtrlLoop(){
533
  function stopCtrlLoop(){ if(ctrlTimer){ clearInterval(ctrlTimer); ctrlTimer = null; } }
534
 
535
  function renderKeys(){
536
- // Highlight the on-screen WASD keys that are currently held.
537
  keycaps.forEach(c=>c.classList.toggle("active", state.pressed.has(c.dataset.k)));
538
- // Look/pan status badge reflects live mouse-look direction(s).
539
  const look = Array.from(state.pressed).filter(k=>LOOK_KEYS.has(k));
540
  const looking = look.length > 0;
541
  lookBadge.classList.toggle("active", looking);
542
  const LOOK_LABEL = { I:"up", K:"down", J:"left", L:"right" };
543
  lookBadgeText.textContent = looking
544
  ? "Looking " + look.map(k=>LOOK_LABEL[k]).join(" + ")
545
- : (state.capturing ? "Mouse-look ready" : "Mouse-look idle");
546
  const held = Array.from(state.pressed);
547
  activeTags.textContent = held.length ? "Active: " + held.join(" + ") : "";
548
  }
549
 
550
- // --- Movement keyboard capture (WASD) + mouse-look pointer capture ---
551
- // Clicking the stage captures input. We request Pointer Lock so raw mouse
552
- // movement drives look/pan (I J K L) instead of the old IJKL keys.
553
  function requestCapture(){
554
  state.capturing = true;
555
  stage.focus();
556
- if(stage.requestPointerLock){
557
- try{ stage.requestPointerLock(); }catch{}
558
- }
559
  renderKeys();
560
  }
561
  stage.addEventListener("click", requestCapture);
@@ -564,63 +568,16 @@ document.addEventListener("keydown",(e)=>{
564
  if(!state.capturing) return;
565
  if(e.code === "Escape"){
566
  state.capturing=false; state.pressed.clear();
567
- if(document.exitPointerLock) try{ document.exitPointerLock(); }catch{}
568
  renderKeys(); return;
569
  }
570
  const k = KEY_FROM_CODE[e.code];
571
- if(k && MOVE_KEYS.has(k)){ e.preventDefault(); state.pressed.add(k); renderKeys(); }
572
  });
573
  document.addEventListener("keyup",(e)=>{
574
  const k = KEY_FROM_CODE[e.code];
575
  if(k){ state.pressed.delete(k); renderKeys(); }
576
  });
577
 
578
- // --- Mouse-look: convert pointer movement into look/pan keys (I J K L) ---
579
- // I = look up, K = look down, J = look left, L = look right. A small deadzone
580
- // avoids jitter; each look direction is held briefly after motion then released
581
- // so a continuous drag/move keeps looking while a still mouse stops looking.
582
- const LOOK_DEADZONE = 2; // px of movement before a look direction fires
583
- let lookReleaseTimer = null;
584
- function applyMouseLook(dx, dy){
585
- if(!state.capturing) return;
586
- // Clear previous look keys; movement (WASD) is untouched.
587
- let changed = false;
588
- for(const k of LOOK_KEYS){ if(state.pressed.delete(k)) changed = true; }
589
-
590
- if(Math.abs(dx) > LOOK_DEADZONE){
591
- state.pressed.add(dx > 0 ? "L" : "J"); changed = true; // right / left
592
- }
593
- if(Math.abs(dy) > LOOK_DEADZONE){
594
- state.pressed.add(dy > 0 ? "K" : "I"); changed = true; // down / up
595
- }
596
- if(changed) renderKeys();
597
-
598
- // Auto-release look keys shortly after the mouse stops moving.
599
- if(lookReleaseTimer) clearTimeout(lookReleaseTimer);
600
- lookReleaseTimer = setTimeout(()=>{
601
- let cleared = false;
602
- for(const k of LOOK_KEYS){ if(state.pressed.delete(k)) cleared = true; }
603
- if(cleared) renderKeys();
604
- }, 120);
605
- }
606
- document.addEventListener("mousemove",(e)=>{
607
- if(!state.capturing) return;
608
- // Prefer raw movement deltas (available under pointer lock); fall back to
609
- // client-space deltas for browsers that deny/lack pointer lock.
610
- const dx = (e.movementX !== undefined) ? e.movementX : 0;
611
- const dy = (e.movementY !== undefined) ? e.movementY : 0;
612
- applyMouseLook(dx, dy);
613
- });
614
- // Track pointer-lock state so the badge reflects capture accurately.
615
- document.addEventListener("pointerlockchange", ()=>{
616
- if(document.pointerLockElement !== stage){
617
- // Pointer released (e.g. Esc pressed by the browser): drop look keys.
618
- let cleared = false;
619
- for(const k of LOOK_KEYS){ if(state.pressed.delete(k)) cleared = true; }
620
- if(cleared) renderKeys();
621
- }
622
- });
623
-
624
  promptEl.addEventListener("input", ()=>{ state.prompt = promptEl.value; });
625
 
626
  // --- Start / Stop ---
 
126
  .keycap[data-k="A"]{grid-column:1;grid-row:2}
127
  .keycap[data-k="S"]{grid-column:2;grid-row:2}
128
  .keycap[data-k="D"]{grid-column:3;grid-row:2}
129
+ /* IJKL look cross placement inside its own 3x2 grid */
130
+ .keycap[data-k="I"]{grid-column:2;grid-row:1}
131
+ .keycap[data-k="J"]{grid-column:1;grid-row:2}
132
+ .keycap[data-k="K"]{grid-column:2;grid-row:2}
133
+ .keycap[data-k="L"]{grid-column:3;grid-row:2}
134
 
135
  .look-info{font-size:12.5px;color:var(--muted);line-height:1.6}
136
  .look-info b{color:var(--text)}
 
150
  <div class="logo">🌍</div>
151
  <div>
152
  <h1>ABot-World — Interactive World Rollout</h1>
153
+ <p>Upload a starting frame, then steer a live action-conditioned world with WASD + IJKL.</p>
154
  </div>
155
  </div>
156
  <div class="links">
 
169
  <div class="chip"><span class="dot" id="status-dot"></span><span id="status-label">Idle</span></div>
170
  <div class="chip"><span id="fps-value">0</span> fps · <span id="frame-value">0</span> blk</div>
171
  </div>
172
+ <div class="capture-hint" id="capture-hint">Click to capture · WASD to move · IJKL to look · Esc to release</div>
173
  <div class="overlay" id="overlay">
174
  <div>
175
  <div class="spinner" id="spinner" style="display:none"></div>
 
193
  </div>
194
  <div>
195
  <div class="label" style="margin-bottom:8px">Look / pan</div>
196
+ <div class="keyboard" id="look-keys">
197
+ <span class="keycap" data-k="I">I</span>
198
+ <span class="keycap" data-k="J">J</span>
199
+ <span class="keycap" data-k="K">K</span>
200
+ <span class="keycap" data-k="L">L</span>
201
  </div>
202
+ <div class="look-badge" id="look-badge"><span class="d"></span><span id="look-badge-text">Look idle</span></div>
203
  </div>
204
  </div>
205
  <div class="hint-line">
206
  <b>W A S D</b> — move &amp; turn (hold to steer the next block) ·
207
+ <b>I J K L</b> — look / pan. Click the video to capture input.
208
  </div>
209
  <div class="active-tags" id="active-tags"></div>
210
  </div>
 
250
  const SESSION_ID = (crypto.randomUUID && crypto.randomUUID()) ||
251
  (`s-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`);
252
 
253
+ // Movement keys are driven by the keyboard (WASD); look/pan is driven by the
254
+ // keyboard too (I J K L) — both are handled as held-key controls.
255
  const MOVE_KEYS = new Set(["W","A","S","D"]);
256
  const LOOK_KEYS = new Set(["I","J","K","L"]);
257
  const KEY_FROM_CODE = {
258
  KeyW:"W", KeyA:"A", KeyS:"S", KeyD:"D",
259
+ KeyI:"I", KeyJ:"J", KeyK:"K", KeyL:"L",
260
  };
261
 
262
  const state = {
 
541
  function stopCtrlLoop(){ if(ctrlTimer){ clearInterval(ctrlTimer); ctrlTimer = null; } }
542
 
543
  function renderKeys(){
544
+ // Highlight the on-screen WASD + IJKL keys that are currently held.
545
  keycaps.forEach(c=>c.classList.toggle("active", state.pressed.has(c.dataset.k)));
546
+ // Look/pan status badge reflects the held look keys (I J K L).
547
  const look = Array.from(state.pressed).filter(k=>LOOK_KEYS.has(k));
548
  const looking = look.length > 0;
549
  lookBadge.classList.toggle("active", looking);
550
  const LOOK_LABEL = { I:"up", K:"down", J:"left", L:"right" };
551
  lookBadgeText.textContent = looking
552
  ? "Looking " + look.map(k=>LOOK_LABEL[k]).join(" + ")
553
+ : (state.capturing ? "Look ready" : "Look idle");
554
  const held = Array.from(state.pressed);
555
  activeTags.textContent = held.length ? "Active: " + held.join(" + ") : "";
556
  }
557
 
558
+ // --- Keyboard capture: WASD (move) + IJKL (look/pan) ---
559
+ // Clicking the stage captures input; held keys are sent ~10x/s to the server.
 
560
  function requestCapture(){
561
  state.capturing = true;
562
  stage.focus();
 
 
 
563
  renderKeys();
564
  }
565
  stage.addEventListener("click", requestCapture);
 
568
  if(!state.capturing) return;
569
  if(e.code === "Escape"){
570
  state.capturing=false; state.pressed.clear();
 
571
  renderKeys(); return;
572
  }
573
  const k = KEY_FROM_CODE[e.code];
574
+ if(k && (MOVE_KEYS.has(k) || LOOK_KEYS.has(k))){ e.preventDefault(); state.pressed.add(k); renderKeys(); }
575
  });
576
  document.addEventListener("keyup",(e)=>{
577
  const k = KEY_FROM_CODE[e.code];
578
  if(k){ state.pressed.delete(k); renderKeys(); }
579
  });
580
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  promptEl.addEventListener("input", ()=>{ state.prompt = promptEl.value; });
582
 
583
  // --- Start / Stop ---