faradayfuture commited on
Commit
6440593
·
verified ·
1 Parent(s): 5cd8926

Auto-start synced playback once videos are ready (muted autoplay, falls back to paused if blocked)

Browse files
egoSample/demo02/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
egoSample/demo05/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
egoSample/demo07/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
egoSample/demo08/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
egoSample/demo09/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
egoSample/demo10/viewer.html CHANGED
@@ -278,4 +278,31 @@ if(master){master.addEventListener('loadedmetadata',update);master.addEventListe
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  </script></body></html>
 
278
  // keep orbit responsive even when paused
279
  setInterval(()=>{if((hSt.dirty||dSt.dirty)&&master){hSt.dirty=dSt.dirty=false;const t=master.currentTime;drawHand(idxAt(HANDS.t,t));drawHead(idxAt(HEAD.t,t));}},60);
280
  window.addEventListener('load',update);update();
281
+
282
+ /* auto-start playback: first-time visitors shouldn't have to find the play
283
+ button. Videos are muted, which is what browser autoplay policies require;
284
+ if a browser still refuses, we roll back to the paused state so the manual
285
+ button keeps working exactly as before. */
286
+ (function(){
287
+ var started=false, iv=null;
288
+ function vlist(){try{return Object.values(videos);}catch(e){return [];}}
289
+ function autoStart(){
290
+ if(started||playing)return;
291
+ var vs=vlist();
292
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
293
+ started=true; if(iv){clearInterval(iv);iv=null;}
294
+ vs.forEach(function(v){v.muted=true;});
295
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
296
+ playing=true; playBtn.innerHTML='&#10073;&#10073;'; requestAnimationFrame(loop);
297
+ }).catch(function(){
298
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.innerHTML='&#9654;';
299
+ });
300
+ }
301
+ vlist().forEach(function(v){
302
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
303
+ });
304
+ window.addEventListener('load',autoStart);
305
+ iv=setInterval(autoStart,400);
306
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
307
+ })();
308
  </script></body></html>
ep0/viewer.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 0 · 18.2s · 545 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,4 +230,31 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 0 · 18.2s · 545 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>
ep1/viewer.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 1 · 18.8s · 563 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,4 +230,31 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 1 · 18.8s · 563 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>
ep2/viewer.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 2 · 18.7s · 562 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,4 +230,31 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 2 · 18.7s · 562 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>
ep3/viewer.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 3 · 20.5s · 614 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,4 +230,31 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 3 · 20.5s · 614 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>
ep4/view.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 4 · 22.4s · 673 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,5 +230,32 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
234
  <!-- rev2 regular-file -->
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 4 · 22.4s · 673 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>
261
  <!-- rev2 regular-file -->
ep5/viewer.html CHANGED
@@ -50,7 +50,7 @@ canvas{width:100%;display:block;cursor:pointer}
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
- <div class="sub"><code>Futurist</code> · episode 5 · 18.4s · 553 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
@@ -230,4 +230,31 @@ window.addEventListener('resize',()=>update());
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  </script></body></html>
 
50
  <header>
51
  <a class="back" href="../teleop.html">← all episodes</a>
52
  <h1>Pick up the water bottle and put it in the basket</h1>
53
+ <div class="sub"><code>a2</code> · episode 5 · 18.4s · 553 frames @ 30fps · teleop</div>
54
  </header>
55
  <div class="layout">
56
  <div class="panel"><div class="camgrid" id="camgrid"></div></div>
 
230
  master.addEventListener('loadedmetadata',update);
231
  master.addEventListener('seeked',update);
232
  window.addEventListener('load',update);
233
+
234
+ /* auto-start playback: first-time visitors shouldn't have to find the play
235
+ button. Videos are muted, which is what browser autoplay policies require;
236
+ if a browser still refuses, we roll back to the paused state so the manual
237
+ button keeps working exactly as before. */
238
+ (function(){
239
+ var started=false, iv=null;
240
+ function vlist(){try{return videos;}catch(e){return [];}}
241
+ function autoStart(){
242
+ if(started||playing)return;
243
+ var vs=vlist();
244
+ if(!vs.length||!vs.every(function(v){return v.readyState>=2;}))return;
245
+ started=true; if(iv){clearInterval(iv);iv=null;}
246
+ vs.forEach(function(v){v.muted=true;});
247
+ Promise.all(vs.map(function(v){return Promise.resolve(v.play());})).then(function(){
248
+ playing=true; playBtn.textContent='\u275a\u275a'; requestAnimationFrame(loop);
249
+ }).catch(function(){
250
+ vs.forEach(function(v){try{v.pause();}catch(e){}}); playing=false; playBtn.textContent='\u25b6\ufe0e';
251
+ });
252
+ }
253
+ vlist().forEach(function(v){
254
+ v.addEventListener('canplay',autoStart); v.addEventListener('loadeddata',autoStart);
255
+ });
256
+ window.addEventListener('load',autoStart);
257
+ iv=setInterval(autoStart,400);
258
+ setTimeout(function(){if(iv){clearInterval(iv);iv=null;}},90000);
259
+ })();
260
  </script></body></html>