notaneimu commited on
Commit
53ebb98
·
1 Parent(s): a44c082

update viewer

Browse files
Files changed (4) hide show
  1. app.py +1 -1
  2. viewer/index.html +19 -6
  3. viewer/index.js +38 -15
  4. viewer/index.js.map +0 -0
app.py CHANGED
@@ -322,7 +322,7 @@ def viewer_url_for_output(ply_filename: str, settings_filename: str) -> str:
322
  # Use absolute paths with /gradio_api/file= prefix for content and settings
323
  content_path = f"/gradio_api/file=outputs/{ply_filename}"
324
  settings_path = f"/gradio_api/file=outputs/{settings_filename}"
325
- return f"/gradio_api/file=viewer/index.html?content={content_path}&settings={settings_path}&noanim"
326
 
327
 
328
  def viewer_placeholder_html() -> str:
 
322
  # Use absolute paths with /gradio_api/file= prefix for content and settings
323
  content_path = f"/gradio_api/file=outputs/{ply_filename}"
324
  settings_path = f"/gradio_api/file=outputs/{settings_filename}"
325
+ return f"/gradio_api/file=viewer/index.html?content={content_path}&settings={settings_path}&noanim&minimal"
326
 
327
 
328
  def viewer_placeholder_html() -> str:
viewer/index.html CHANGED
@@ -18,7 +18,7 @@
18
  const posterUrl = url.searchParams.get('poster');
19
  const skyboxUrl = url.searchParams.get('skybox');
20
  const settingsUrl = url.searchParams.has('settings') ? url.searchParams.get('settings') : './settings.json';
21
- const contentUrl = url.searchParams.has('content') ? url.searchParams.get('content') : './scene.ply';
22
 
23
  const sseConfig = {
24
  poster: posterUrl && createImage(posterUrl),
@@ -27,6 +27,7 @@
27
  contents: fetch(contentUrl),
28
  noui: url.searchParams.has('noui'),
29
  noanim: url.searchParams.has('noanim'),
 
30
  ministats: url.searchParams.has('ministats'),
31
  colorize: url.searchParams.has('colorize'),
32
  unified: url.searchParams.has('unified'),
@@ -91,13 +92,13 @@
91
 
92
  <div class="spacer"></div>
93
 
94
- <button id="orbitCamera" class="controlButton toggle left">
95
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
96
  <g class='stroke'><use href="#orbitIcon"/></g>
97
  <g class='fill'><use href="#orbitIcon"/></g>
98
  </svg>
99
  </button>
100
- <button id="flyCamera" class="controlButton toggle right">
101
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
102
  <g class='stroke'><use href="#flyIcon"/></g>
103
  <g class='fill'><use href="#flyIcon"/></g>
@@ -123,7 +124,7 @@
123
  <g class='fill'><use href="#infoIcon"/></g>
124
  </svg>
125
  </button>
126
- <button id="settings" class="controlButton">
127
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
128
  <g class='stroke'><use href="#settingsIcon"/></g>
129
  <g class='fill'><use href="#settingsIcon"/></g>
@@ -196,8 +197,20 @@
196
  <span class="control-key">Left Mouse</span>
197
  </div>
198
  <div class="control-item">
199
- <span class="control-action">Fly</span>
200
- <span class="control-key">W,S,A,D</span>
 
 
 
 
 
 
 
 
 
 
 
 
201
  </div>
202
  <div class="control-spacer"></div>
203
  <div class="control-item">
 
18
  const posterUrl = url.searchParams.get('poster');
19
  const skyboxUrl = url.searchParams.get('skybox');
20
  const settingsUrl = url.searchParams.has('settings') ? url.searchParams.get('settings') : './settings.json';
21
+ const contentUrl = url.searchParams.has('content') ? url.searchParams.get('content') : './scene.compressed.ply';
22
 
23
  const sseConfig = {
24
  poster: posterUrl && createImage(posterUrl),
 
27
  contents: fetch(contentUrl),
28
  noui: url.searchParams.has('noui'),
29
  noanim: url.searchParams.has('noanim'),
30
+ minimal: url.searchParams.has('minimal'),
31
  ministats: url.searchParams.has('ministats'),
32
  colorize: url.searchParams.has('colorize'),
33
  unified: url.searchParams.has('unified'),
 
92
 
93
  <div class="spacer"></div>
94
 
95
+ <button id="orbitCamera" class="controlButton toggle left hidden">
96
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
97
  <g class='stroke'><use href="#orbitIcon"/></g>
98
  <g class='fill'><use href="#orbitIcon"/></g>
99
  </svg>
100
  </button>
101
+ <button id="flyCamera" class="controlButton toggle right hidden">
102
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
103
  <g class='stroke'><use href="#flyIcon"/></g>
104
  <g class='fill'><use href="#flyIcon"/></g>
 
124
  <g class='fill'><use href="#infoIcon"/></g>
125
  </svg>
126
  </button>
127
+ <button id="settings" class="controlButton hidden">
128
  <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
129
  <g class='stroke'><use href="#settingsIcon"/></g>
130
  <g class='fill'><use href="#settingsIcon"/></g>
 
197
  <span class="control-key">Left Mouse</span>
198
  </div>
199
  <div class="control-item">
200
+ <span class="control-action">Fly Forward / Backward</span>
201
+ <span class="control-key">W / S or Up / Down Arrows</span>
202
+ </div>
203
+ <div class="control-item">
204
+ <span class="control-action">Fly Left / Right</span>
205
+ <span class="control-key">A / D or Left / Right Arrows</span>
206
+ </div>
207
+ <div class="control-item">
208
+ <span class="control-action">Fly Up / Down</span>
209
+ <span class="control-key">Q / E</span>
210
+ </div>
211
+ <div class="control-item">
212
+ <span class="control-action">Fast / Slow</span>
213
+ <span class="control-key">Shift / Ctrl</span>
214
  </div>
215
  <div class="control-spacer"></div>
216
  <div class="control-item">
viewer/index.js CHANGED
@@ -101739,7 +101739,7 @@ const initUI = (global) => {
101739
  state.animationPaused = true;
101740
  });
101741
  const updatePlayPause = () => {
101742
- if (state.cameraMode !== 'anim' || state.animationPaused) {
101743
  dom.play.classList.remove('hidden');
101744
  dom.pause.classList.add('hidden');
101745
  }
@@ -101747,12 +101747,16 @@ const initUI = (global) => {
101747
  dom.play.classList.add('hidden');
101748
  dom.pause.classList.remove('hidden');
101749
  }
101750
- if (state.cameraMode === 'anim') {
101751
  dom.timelineContainer.classList.remove('hidden');
101752
  }
101753
  else {
101754
  dom.timelineContainer.classList.add('hidden');
101755
  }
 
 
 
 
101756
  };
101757
  // Update UI on animation changes
101758
  events.on('cameraMode:changed', updatePlayPause);
@@ -101797,10 +101801,20 @@ const initUI = (global) => {
101797
  });
101798
  });
101799
  // Camera mode UI
101800
- events.on('cameraMode:changed', () => {
101801
  dom.orbitCamera.classList[state.cameraMode === 'orbit' ? 'add' : 'remove']('active');
101802
  dom.flyCamera.classList[state.cameraMode === 'fly' ? 'add' : 'remove']('active');
101803
- });
 
 
 
 
 
 
 
 
 
 
101804
  dom.settings.addEventListener('click', () => {
101805
  dom.settingsPanel.classList.toggle('hidden');
101806
  });
@@ -102813,12 +102827,12 @@ class CameraManager {
102813
  // set the global animation flag
102814
  state.hasAnimation = !!controllers.anim;
102815
  state.animationDuration = controllers.anim ? controllers.anim.animState.cursor.duration : 0;
102816
- // initialize camera mode and initial camera position
102817
- state.cameraMode = state.hasAnimation ? 'anim' : (isObjectExperience ? 'orbit' : 'fly');
102818
  this.camera.copy(resetCamera);
102819
  const target = new Camera(this.camera); // the active controller updates this
102820
  const from = new Camera(this.camera); // stores the previous camera state during transition
102821
- let fromMode = isObjectExperience ? 'orbit' : 'fly';
102822
  // enter the initial controller
102823
  getController(state.cameraMode).onEnter(this.camera);
102824
  // transition time between cameras
@@ -102856,7 +102870,7 @@ class CameraManager {
102856
  controllers.orbit.goto(resetCamera);
102857
  break;
102858
  case 'playPause':
102859
- if (state.hasAnimation) {
102860
  if (state.cameraMode === 'anim') {
102861
  state.animationPaused = !state.animationPaused;
102862
  }
@@ -103234,7 +103248,10 @@ class InputController {
103234
  }
103235
  this._state.shift += key[keyCode.SHIFT];
103236
  this._state.ctrl += key[keyCode.CTRL];
103237
- if (state.cameraMode !== 'fly' && this._state.axis.length() > 0) {
 
 
 
103238
  state.cameraMode = 'fly';
103239
  }
103240
  const orbit = +(state.cameraMode === 'orbit');
@@ -103242,13 +103259,17 @@ class InputController {
103242
  const double = +(this._state.touches > 1);
103243
  const pan = this._state.mouse[2] || +(button[2] === -1) || double;
103244
  const orbitFactor = fly ? camera.fov / 120 : 1;
 
 
103245
  const { deltas } = this.frame;
103246
  // desktop move
103247
  const v = tmpV1.set(0, 0, 0);
103248
  const keyMove = this._state.axis.clone().normalize();
103249
- v.add(keyMove.mulScalar(fly * this.moveSpeed * (this._state.shift ? 4 : this._state.ctrl ? 0.25 : 1) * dt));
103250
- const panMove = screenToWorld(camera, mouse[0], mouse[1], distance);
103251
- v.add(panMove.mulScalar(pan));
 
 
103252
  const wheelMove = new Vec3(0, 0, -wheel[0]);
103253
  v.add(wheelMove.mulScalar(this.wheelSpeed * dt));
103254
  // FIXME: need to flip z axis for orbit camera
@@ -103260,8 +103281,10 @@ class InputController {
103260
  deltas.rotate.append([v.x, v.y, v.z]);
103261
  // mobile move
103262
  v.set(0, 0, 0);
103263
- const orbitMove = screenToWorld(camera, touch[0], touch[1], distance);
103264
- v.add(orbitMove.mulScalar(orbit * pan));
 
 
103265
  flyMove.set(leftInput[0], 0, -leftInput[1]);
103266
  v.add(flyMove.mulScalar(fly * this.moveSpeed * dt));
103267
  pinchMove.set(0, 0, pinch[0]);
@@ -104288,7 +104311,7 @@ const main = (app, camera, settingsJson, config) => {
104288
  hqMode: true,
104289
  progress: 0,
104290
  inputMode: 'desktop',
104291
- cameraMode: 'orbit',
104292
  hasAnimation: false,
104293
  animationDuration: 0,
104294
  animationTime: 0,
 
101739
  state.animationPaused = true;
101740
  });
101741
  const updatePlayPause = () => {
101742
+ if (config.minimal || state.cameraMode !== 'anim' || state.animationPaused) {
101743
  dom.play.classList.remove('hidden');
101744
  dom.pause.classList.add('hidden');
101745
  }
 
101747
  dom.play.classList.add('hidden');
101748
  dom.pause.classList.remove('hidden');
101749
  }
101750
+ if (!config.minimal && state.cameraMode === 'anim') {
101751
  dom.timelineContainer.classList.remove('hidden');
101752
  }
101753
  else {
101754
  dom.timelineContainer.classList.add('hidden');
101755
  }
101756
+ if (config.minimal) {
101757
+ dom.play.classList.add('hidden');
101758
+ dom.pause.classList.add('hidden');
101759
+ }
101760
  };
101761
  // Update UI on animation changes
101762
  events.on('cameraMode:changed', updatePlayPause);
 
101801
  });
101802
  });
101803
  // Camera mode UI
101804
+ const updateCameraMode = () => {
101805
  dom.orbitCamera.classList[state.cameraMode === 'orbit' ? 'add' : 'remove']('active');
101806
  dom.flyCamera.classList[state.cameraMode === 'fly' ? 'add' : 'remove']('active');
101807
+ };
101808
+ events.on('cameraMode:changed', updateCameraMode);
101809
+ updateCameraMode(); // Initialize on load
101810
+ // Hide mode buttons if nomode config is set
101811
+ if (config.minimal) {
101812
+ dom.orbitCamera.classList.add('hidden');
101813
+ dom.flyCamera.classList.add('hidden');
101814
+ dom.play.classList.add('hidden');
101815
+ dom.timelineContainer.classList.add('hidden');
101816
+ dom.settings.classList.add('hidden');
101817
+ }
101818
  dom.settings.addEventListener('click', () => {
101819
  dom.settingsPanel.classList.toggle('hidden');
101820
  });
 
102827
  // set the global animation flag
102828
  state.hasAnimation = !!controllers.anim;
102829
  state.animationDuration = controllers.anim ? controllers.anim.animState.cursor.duration : 0;
102830
+ // initialize camera mode and initial camera position - always start in fly mode
102831
+ state.cameraMode = 'fly';
102832
  this.camera.copy(resetCamera);
102833
  const target = new Camera(this.camera); // the active controller updates this
102834
  const from = new Camera(this.camera); // stores the previous camera state during transition
102835
+ let fromMode = 'fly';
102836
  // enter the initial controller
102837
  getController(state.cameraMode).onEnter(this.camera);
102838
  // transition time between cameras
 
102870
  controllers.orbit.goto(resetCamera);
102871
  break;
102872
  case 'playPause':
102873
+ if (state.hasAnimation && !global.config.minimal && !global.config.noanim) {
102874
  if (state.cameraMode === 'anim') {
102875
  state.animationPaused = !state.animationPaused;
102876
  }
 
103248
  }
103249
  this._state.shift += key[keyCode.SHIFT];
103250
  this._state.ctrl += key[keyCode.CTRL];
103251
+ // Switch to fly mode when using keyboard axis or zooming with wheel
103252
+ const hasWheelZoom = wheel[0] !== 0;
103253
+ const hasPinchZoom = pinch[0] !== 0;
103254
+ if (state.cameraMode !== 'fly' && (this._state.axis.length() > 0 || hasWheelZoom || hasPinchZoom)) {
103255
  state.cameraMode = 'fly';
103256
  }
103257
  const orbit = +(state.cameraMode === 'orbit');
 
103259
  const double = +(this._state.touches > 1);
103260
  const pan = this._state.mouse[2] || +(button[2] === -1) || double;
103261
  const orbitFactor = fly ? camera.fov / 120 : 1;
103262
+ // Speed multiplier for consistent movement (keyboard uses moveSpeed)
103263
+ const speedMultiplier = this._state.shift ? 4 : this._state.ctrl ? 0.25 : 1;
103264
  const { deltas } = this.frame;
103265
  // desktop move
103266
  const v = tmpV1.set(0, 0, 0);
103267
  const keyMove = this._state.axis.clone().normalize();
103268
+ v.add(keyMove.mulScalar(fly * this.moveSpeed * speedMultiplier * dt));
103269
+ // Pan movement - use minimum distance of 1 to ensure panning works in fly mode
103270
+ const panDistance = Math.max(distance, 1);
103271
+ const panMove = screenToWorld(camera, mouse[0], mouse[1], panDistance);
103272
+ v.add(panMove.mulScalar(pan * this.moveSpeed * 0.15));
103273
  const wheelMove = new Vec3(0, 0, -wheel[0]);
103274
  v.add(wheelMove.mulScalar(this.wheelSpeed * dt));
103275
  // FIXME: need to flip z axis for orbit camera
 
103281
  deltas.rotate.append([v.x, v.y, v.z]);
103282
  // mobile move
103283
  v.set(0, 0, 0);
103284
+ // Touch pan movement - use minimum distance for fly mode compatibility
103285
+ const touchPanDistance = Math.max(distance, 1);
103286
+ const orbitMove = screenToWorld(camera, touch[0], touch[1], touchPanDistance);
103287
+ v.add(orbitMove.mulScalar(orbit * pan * this.moveSpeed * 0.15));
103288
  flyMove.set(leftInput[0], 0, -leftInput[1]);
103289
  v.add(flyMove.mulScalar(fly * this.moveSpeed * dt));
103290
  pinchMove.set(0, 0, pinch[0]);
 
104311
  hqMode: true,
104312
  progress: 0,
104313
  inputMode: 'desktop',
104314
+ cameraMode: 'fly',
104315
  hasAnimation: false,
104316
  animationDuration: 0,
104317
  animationTime: 0,
viewer/index.js.map CHANGED
The diff for this file is too large to render. See raw diff