@popaya/pgsg-viewer 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,7 @@ var PGSGViewer = class {
10
10
  const { PGSGPlayCanvasViewer } = await import("./pgsg-playcanvas-viewer-4WORM4WU.js");
11
11
  this.engine = new PGSGPlayCanvasViewer(this.options);
12
12
  } else {
13
- const { PGSGThreeViewer } = await import("./pgsg-three-viewer-2ONIARDQ.js");
13
+ const { PGSGThreeViewer } = await import("./pgsg-three-viewer-Z76CF22S.js");
14
14
  this.engine = new PGSGThreeViewer(this.options);
15
15
  }
16
16
  await this.engine.load();
@@ -30,4 +30,4 @@ var PGSGViewer = class {
30
30
  export {
31
31
  PGSGViewer
32
32
  };
33
- //# sourceMappingURL=chunk-UDJ24YL2.js.map
33
+ //# sourceMappingURL=chunk-FAKOSERU.js.map
@@ -1,7 +1,7 @@
1
1
  import "../chunk-PYYLHUV6.js";
2
2
  import {
3
3
  PGSGViewer
4
- } from "../chunk-UDJ24YL2.js";
4
+ } from "../chunk-FAKOSERU.js";
5
5
  export {
6
6
  PGSGViewer
7
7
  };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import "./chunk-PYYLHUV6.js";
2
2
  import {
3
3
  PGSGViewer
4
- } from "./chunk-UDJ24YL2.js";
4
+ } from "./chunk-FAKOSERU.js";
5
5
  export {
6
6
  PGSGViewer
7
7
  };
@@ -1,6 +1,7 @@
1
1
  // src/viewers/three/pgsg-three-viewer.ts
2
2
  import * as THREE3 from "three";
3
3
  import { GLTFLoader } from "three/examples/jsm/Addons.js";
4
+ import nipplejs from "nipplejs";
4
5
 
5
6
  // src/viewers/spark/SparkSplatRenderer.ts
6
7
  import { SplatMesh } from "@sparkjsdev/spark";
@@ -55,8 +56,17 @@ var WalkCapsuleController = class {
55
56
  pitch = 0;
56
57
  velocity = new THREE.Vector3();
57
58
  onGround = false;
59
+ lastGroundY = null;
58
60
  keys = /* @__PURE__ */ new Set();
59
61
  raycaster = new THREE.Raycaster();
62
+ usePointerLock = false;
63
+ lastTouchX = 0;
64
+ lastTouchY = 0;
65
+ externalMove = new THREE.Vector2(0, 0);
66
+ useGyro = false;
67
+ gyroAlpha = 0;
68
+ gyroBeta = 0;
69
+ gyroGamma = 0;
60
70
  constructor(opts) {
61
71
  this.dom = opts.dom;
62
72
  this.camera = opts.camera;
@@ -68,17 +78,41 @@ var WalkCapsuleController = class {
68
78
  this.walkSpeed = opts.walkSpeed ?? 2.5;
69
79
  this.runMultiplier = opts.runMultiplier ?? 2;
70
80
  this.lookSensitivity = opts.lookSensitivity ?? 22e-4;
81
+ this.usePointerLock = opts.usePointerLock ?? false;
71
82
  const euler = new THREE.Euler().setFromQuaternion(
72
83
  this.camera.quaternion,
73
84
  "YXZ"
74
85
  );
75
86
  this.pitch = euler.x;
76
87
  this.yaw = euler.y;
77
- this.bind();
88
+ if (this.usePointerLock === false) {
89
+ this.bindTouch();
90
+ } else {
91
+ this.bind();
92
+ }
78
93
  }
79
94
  dispose() {
80
- this.unbind();
81
- document.exitPointerLock();
95
+ if (this.usePointerLock === false) {
96
+ this.unbindTouch();
97
+ } else {
98
+ this.unbind();
99
+ if (this.usePointerLock) document.exitPointerLock();
100
+ }
101
+ }
102
+ setMovementVector(x, y) {
103
+ this.externalMove.set(x, y);
104
+ }
105
+ enableGyro() {
106
+ if (typeof DeviceOrientationEvent === "undefined") return;
107
+ if (DeviceOrientationEvent.requestPermission) {
108
+ DeviceOrientationEvent.requestPermission().then((response) => {
109
+ if (response === "granted") {
110
+ this.startGyro();
111
+ }
112
+ }).catch(console.error);
113
+ } else {
114
+ this.startGyro();
115
+ }
82
116
  }
83
117
  // --------------------------------------------------
84
118
  // Input binding (SAFE for pointer lock)
@@ -91,6 +125,10 @@ var WalkCapsuleController = class {
91
125
  window.addEventListener("blur", this.onBlur);
92
126
  this.dom.addEventListener("contextmenu", (e) => e.preventDefault());
93
127
  }
128
+ bindTouch() {
129
+ this.dom.addEventListener("touchstart", this.onTouchStart);
130
+ this.dom.addEventListener("touchmove", this.onTouchMove);
131
+ }
94
132
  unbind() {
95
133
  this.dom.removeEventListener("click", this.onClick);
96
134
  window.removeEventListener("mousemove", this.onMouseMove);
@@ -98,17 +136,23 @@ var WalkCapsuleController = class {
98
136
  window.removeEventListener("keyup", this.onKeyUp);
99
137
  window.removeEventListener("blur", this.onBlur);
100
138
  }
139
+ unbindTouch() {
140
+ this.dom.removeEventListener("touchstart", this.onTouchStart);
141
+ this.dom.removeEventListener("touchmove", this.onTouchMove);
142
+ }
101
143
  onClick = () => {
102
- if (document.pointerLockElement !== this.dom) {
144
+ if (this.usePointerLock && document.pointerLockElement !== this.dom) {
103
145
  this.dom.requestPointerLock();
104
146
  }
105
147
  };
106
148
  onBlur = () => {
107
- document.exitPointerLock();
149
+ if (this.usePointerLock) {
150
+ document.exitPointerLock();
151
+ }
108
152
  this.keys.clear();
109
153
  };
110
154
  onMouseMove = (e) => {
111
- if (document.pointerLockElement !== this.dom) return;
155
+ if (this.usePointerLock && document.pointerLockElement !== this.dom) return;
112
156
  this.yaw -= e.movementX * this.lookSensitivity;
113
157
  this.pitch -= e.movementY * this.lookSensitivity;
114
158
  this.pitch = THREE.MathUtils.clamp(
@@ -126,10 +170,48 @@ var WalkCapsuleController = class {
126
170
  onKeyUp = (e) => {
127
171
  this.keys.delete(e.key.toLowerCase());
128
172
  };
173
+ onTouchStart = (e) => {
174
+ const t = e.touches[0];
175
+ this.lastTouchX = t.clientX;
176
+ this.lastTouchY = t.clientY;
177
+ };
178
+ onTouchMove = (e) => {
179
+ const t = e.touches[0];
180
+ const deltaX = t.clientX - this.lastTouchX;
181
+ const deltaY = t.clientY - this.lastTouchY;
182
+ this.lastTouchX = t.clientX;
183
+ this.lastTouchY = t.clientY;
184
+ this.yaw -= deltaX * 2e-3;
185
+ this.pitch -= deltaY * 2e-3;
186
+ this.pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitch));
187
+ this.camera.quaternion.setFromEuler(
188
+ new THREE.Euler(this.pitch, this.yaw, 0, "YXZ")
189
+ );
190
+ };
191
+ startGyro() {
192
+ this.useGyro = true;
193
+ window.addEventListener("deviceorientation", (e) => {
194
+ if (!e.alpha || !e.beta) return;
195
+ this.gyroAlpha = THREE.MathUtils.degToRad(e.alpha);
196
+ this.gyroBeta = THREE.MathUtils.degToRad(e.beta);
197
+ this.gyroGamma = THREE.MathUtils.degToRad(e.gamma ?? 0);
198
+ });
199
+ }
129
200
  // --------------------------------------------------
130
201
  // Update loop
131
202
  // --------------------------------------------------
132
203
  update(dt) {
204
+ if (this.useGyro) {
205
+ this.yaw = THREE.MathUtils.lerp(this.yaw, -this.gyroAlpha, 0.1);
206
+ this.pitch = THREE.MathUtils.lerp(
207
+ this.pitch,
208
+ this.gyroBeta - Math.PI / 2,
209
+ 0.1
210
+ );
211
+ this.camera.quaternion.setFromEuler(
212
+ new THREE.Euler(this.pitch, this.yaw, 0, "YXZ")
213
+ );
214
+ }
133
215
  if (!Number.isFinite(this.camera.position.y)) return;
134
216
  dt = Math.min(dt, 0.05);
135
217
  const forward = new THREE.Vector3();
@@ -142,6 +224,10 @@ var WalkCapsuleController = class {
142
224
  if (this.keys.has("s")) wish.sub(forward);
143
225
  if (this.keys.has("d")) wish.add(right);
144
226
  if (this.keys.has("a")) wish.sub(right);
227
+ if (this.externalMove.lengthSq() > 0) {
228
+ wish.addScaledVector(forward, this.externalMove.x);
229
+ wish.addScaledVector(right, this.externalMove.y);
230
+ }
145
231
  if (wish.lengthSq() > 0) wish.normalize();
146
232
  const speed = this.walkSpeed * (this.keys.has("shift") ? this.runMultiplier : 1);
147
233
  this.velocity.x = wish.x * speed;
@@ -154,6 +240,28 @@ var WalkCapsuleController = class {
154
240
  const resolved = this.resolveGroundAndCollisions(nextPos);
155
241
  this.camera.position.copy(resolved);
156
242
  }
243
+ snapToGround() {
244
+ const origin = this.camera.position.clone();
245
+ origin.y += 5;
246
+ this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));
247
+ this.raycaster.far = 50;
248
+ const hits = this.raycaster.intersectObjects(this.colliders, true);
249
+ for (const hit of hits) {
250
+ if (!hit.face) continue;
251
+ const normalMatrix = new THREE.Matrix3().getNormalMatrix(
252
+ hit.object.matrixWorld
253
+ );
254
+ const worldNormal = hit.face.normal.clone().applyMatrix3(normalMatrix).normalize();
255
+ if (worldNormal.y > 0.5) {
256
+ this.lastGroundY = hit.point.y;
257
+ this.camera.position.y = this.lastGroundY + this.eyeHeight;
258
+ this.velocity.y = 0;
259
+ this.onGround = true;
260
+ return;
261
+ }
262
+ }
263
+ this.lastGroundY = this.camera.position.y - this.eyeHeight;
264
+ }
157
265
  // --------------------------------------------------
158
266
  // Collision & Ground
159
267
  // --------------------------------------------------
@@ -181,6 +289,7 @@ var WalkCapsuleController = class {
181
289
  if (groundHit) {
182
290
  const groundY = groundHit.point.y;
183
291
  const targetY = groundY + this.eyeHeight;
292
+ this.lastGroundY = groundY;
184
293
  const falling = this.velocity.y <= 0;
185
294
  const maxSnap = 1;
186
295
  if (falling && camPos.y <= targetY + maxSnap) {
@@ -191,7 +300,13 @@ var WalkCapsuleController = class {
191
300
  this.onGround = false;
192
301
  }
193
302
  } else {
194
- this.onGround = false;
303
+ if (this.lastGroundY !== null) {
304
+ camPos.y = this.lastGroundY + this.eyeHeight;
305
+ this.velocity.y = 0;
306
+ this.onGround = true;
307
+ } else {
308
+ this.onGround = false;
309
+ }
195
310
  }
196
311
  const center = camPos.clone();
197
312
  center.y -= this.eyeHeight * 0.9;
@@ -231,6 +346,11 @@ var OrbitCameraController = class {
231
346
  lastY = 0;
232
347
  panning = false;
233
348
  panSpeed = 2e-3;
349
+ usePointerLock = false;
350
+ lastTouchX = 0;
351
+ lastTouchY = 0;
352
+ externalMove = new THREE2.Vector2(0, 0);
353
+ moveSpeed = 5;
234
354
  constructor(camera, dom, opts) {
235
355
  this.camera = camera;
236
356
  this.dom = dom;
@@ -240,12 +360,38 @@ var OrbitCameraController = class {
240
360
  this.maxDistance = opts.maxDistance ?? 500;
241
361
  this.rotateSpeed = opts.rotateSpeed ?? 5e-3;
242
362
  this.zoomSpeed = opts.zoomSpeed ?? 1.1;
363
+ this.usePointerLock = opts.usePointerLock ?? false;
243
364
  this.syncFromCamera();
244
- this.bind();
365
+ if (this.usePointerLock === false) {
366
+ this.bindTouch();
367
+ } else {
368
+ this.bind();
369
+ this.updateCamera();
370
+ }
371
+ }
372
+ update(dt) {
373
+ if (this.externalMove.lengthSq() === 0) return;
374
+ const forward = new THREE2.Vector3();
375
+ this.camera.getWorldDirection(forward);
376
+ forward.y = 0;
377
+ forward.normalize();
378
+ const right = new THREE2.Vector3().crossVectors(forward, new THREE2.Vector3(0, 1, 0)).normalize();
379
+ const move = new THREE2.Vector3().addScaledVector(forward, this.externalMove.x).addScaledVector(right, this.externalMove.y);
380
+ if (move.lengthSq() > 0) move.normalize();
381
+ move.multiplyScalar(this.moveSpeed * dt);
382
+ this.target.add(move);
245
383
  this.updateCamera();
246
384
  }
247
385
  dispose() {
248
- this.unbind();
386
+ if (this.usePointerLock === false) {
387
+ this.unbindTouch();
388
+ } else {
389
+ this.unbind();
390
+ if (this.usePointerLock) document.exitPointerLock();
391
+ }
392
+ }
393
+ setMovementVector(x, y) {
394
+ this.externalMove.set(x, y);
249
395
  }
250
396
  // -----------------------------
251
397
  // Setup
@@ -257,12 +403,20 @@ var OrbitCameraController = class {
257
403
  window.addEventListener("mousemove", this.onMouseMove);
258
404
  this.dom.addEventListener("wheel", this.onWheel, { passive: false });
259
405
  }
406
+ bindTouch() {
407
+ this.dom.addEventListener("touchstart", this.onTouchStart);
408
+ this.dom.addEventListener("touchmove", this.onTouchMove);
409
+ }
260
410
  unbind() {
261
411
  this.dom.removeEventListener("mousedown", this.onMouseDown);
262
412
  window.removeEventListener("mouseup", this.onMouseUp);
263
413
  window.removeEventListener("mousemove", this.onMouseMove);
264
414
  this.dom.removeEventListener("wheel", this.onWheel);
265
415
  }
416
+ unbindTouch() {
417
+ this.dom.removeEventListener("touchstart", this.onTouchStart);
418
+ this.dom.removeEventListener("touchmove", this.onTouchMove);
419
+ }
266
420
  syncFromCamera() {
267
421
  const offset = this.camera.position.clone().sub(this.target);
268
422
  this.distance = offset.length();
@@ -325,6 +479,24 @@ var OrbitCameraController = class {
325
479
  );
326
480
  this.updateCamera();
327
481
  };
482
+ onTouchStart = (e) => {
483
+ const t = e.touches[0];
484
+ this.lastTouchX = t.clientX;
485
+ this.lastTouchY = t.clientY;
486
+ };
487
+ onTouchMove = (e) => {
488
+ const t = e.touches[0];
489
+ const deltaX = t.clientX - this.lastTouchX;
490
+ const deltaY = t.clientY - this.lastTouchY;
491
+ this.lastTouchX = t.clientX;
492
+ this.lastTouchY = t.clientY;
493
+ this.yaw -= deltaX * 2e-3;
494
+ this.pitch -= deltaY * 2e-3;
495
+ this.pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitch));
496
+ this.camera.quaternion.setFromEuler(
497
+ new THREE2.Euler(this.pitch, this.yaw, 0, "YXZ")
498
+ );
499
+ };
328
500
  // -----------------------------
329
501
  // Camera math
330
502
  // -----------------------------
@@ -363,6 +535,7 @@ var PGSGThreeViewer = class {
363
535
  worldRoot = new THREE3.Object3D();
364
536
  splatPivot = new THREE3.Object3D();
365
537
  colliderMesh;
538
+ modeButton;
366
539
  async load() {
367
540
  this.initRenderer();
368
541
  this.initCamera();
@@ -379,7 +552,16 @@ var PGSGThreeViewer = class {
379
552
  if (this.options.colliderSource) {
380
553
  await this.loadCollider(this.options.colliderSource);
381
554
  }
382
- this.switchToOrbit();
555
+ this.scene.updateMatrixWorld(true);
556
+ if (this.isMobile()) {
557
+ this.initJoystick();
558
+ this.initModeToggle();
559
+ this.switchToWalk();
560
+ this.updateModeLabel("WALK");
561
+ const walk = this.controls;
562
+ } else {
563
+ this.switchToOrbit();
564
+ }
383
565
  window.addEventListener("keydown", this.onKeyToggle);
384
566
  }
385
567
  start() {
@@ -423,6 +605,15 @@ var PGSGThreeViewer = class {
423
605
  }, 0);
424
606
  }
425
607
  }
608
+ toggleCameraMode() {
609
+ if (this.controls instanceof WalkCapsuleController) {
610
+ this.switchToOrbit();
611
+ this.updateModeLabel("ORBIT");
612
+ } else {
613
+ this.switchToWalk();
614
+ this.updateModeLabel("WALK");
615
+ }
616
+ }
426
617
  initRenderer() {
427
618
  if (this.renderer) return;
428
619
  this.renderer = new THREE3.WebGLRenderer({
@@ -454,13 +645,79 @@ var PGSGThreeViewer = class {
454
645
  }
455
646
  initCamera() {
456
647
  this.camera = new THREE3.PerspectiveCamera(
457
- 60,
648
+ this.options.camera?.fov ?? 60,
458
649
  this.container.clientWidth / this.container.clientHeight,
459
- 0.01,
460
- 1e4
650
+ this.options.camera?.near ?? 0.01,
651
+ this.options.camera?.far ?? 1e4
461
652
  );
462
653
  this.camera.position.set(0, 1.6, 3);
463
- this.camera.lookAt(0, 0, 0);
654
+ this.camera.lookAt(0, 1.6, 0);
655
+ }
656
+ initJoystick() {
657
+ const zone = document.createElement("div");
658
+ zone.style.position = "absolute";
659
+ zone.style.left = "20px";
660
+ zone.style.bottom = "20px";
661
+ zone.style.width = "150px";
662
+ zone.style.height = "150px";
663
+ zone.style.zIndex = "1000";
664
+ this.container.appendChild(zone);
665
+ const joystick = nipplejs.create({
666
+ zone,
667
+ mode: "static",
668
+ position: { left: "75px", bottom: "75px" },
669
+ color: "white"
670
+ });
671
+ joystick.on("move", (_, data) => {
672
+ const angle = data.angle.radian;
673
+ const force = data.force;
674
+ if (this.controls instanceof WalkCapsuleController) {
675
+ this.controls.setMovementVector(
676
+ Math.sin(angle) * force,
677
+ Math.cos(angle) * force
678
+ );
679
+ }
680
+ if (this.controls instanceof OrbitCameraController) {
681
+ this.controls.setMovementVector(
682
+ Math.sin(angle) * force,
683
+ Math.cos(angle) * force
684
+ );
685
+ }
686
+ });
687
+ joystick.on("end", () => {
688
+ this.controls.setMovementVector(0, 0);
689
+ });
690
+ }
691
+ initModeToggle() {
692
+ const btn = document.createElement("div");
693
+ btn.style.position = "absolute";
694
+ btn.style.right = "20px";
695
+ btn.style.bottom = "40px";
696
+ btn.style.width = "70px";
697
+ btn.style.height = "70px";
698
+ btn.style.borderRadius = "50%";
699
+ btn.style.background = "rgba(255,255,255,0.15)";
700
+ btn.style.backdropFilter = "blur(6px)";
701
+ btn.style.border = "2px solid rgba(255,255,255,0.4)";
702
+ btn.style.display = "flex";
703
+ btn.style.alignItems = "center";
704
+ btn.style.justifyContent = "center";
705
+ btn.style.color = "white";
706
+ btn.style.fontWeight = "bold";
707
+ btn.style.fontSize = "14px";
708
+ btn.style.zIndex = "1000";
709
+ btn.style.userSelect = "none";
710
+ btn.style.cursor = "pointer";
711
+ btn.innerText = "ORBIT";
712
+ btn.addEventListener("click", () => {
713
+ this.toggleCameraMode();
714
+ });
715
+ this.container.appendChild(btn);
716
+ this.modeButton = btn;
717
+ }
718
+ updateModeLabel(mode) {
719
+ if (!this.modeButton) return;
720
+ this.modeButton.innerText = mode;
464
721
  }
465
722
  async loadCollider(url) {
466
723
  const loader = new GLTFLoader();
@@ -470,37 +727,15 @@ var PGSGThreeViewer = class {
470
727
  this.colliders.length = 0;
471
728
  this.colliderMesh.traverse((child) => {
472
729
  if (child.isMesh) {
473
- child.material = new THREE3.MeshNormalMaterial();
730
+ child.material = new THREE3.MeshBasicMaterial({ visible: false });
474
731
  child.updateMatrixWorld(true);
475
732
  this.colliders.push(child);
476
733
  }
477
734
  });
478
735
  this.worldRoot.updateMatrixWorld(true);
479
736
  }
480
- fitCameraToWorldBox(box) {
481
- const center = box.getCenter(new THREE3.Vector3());
482
- const size = box.getSize(new THREE3.Vector3());
483
- const maxDim = Math.max(size.x, size.y, size.z);
484
- const fov = THREE3.MathUtils.degToRad(this.camera.fov);
485
- const distance = maxDim / (2 * Math.tan(fov / 2));
486
- const direction = new THREE3.Vector3(0, 0, 1);
487
- const position = center.clone().add(direction.multiplyScalar(distance * 1.2));
488
- this.camera.position.copy(position);
489
- this.camera.lookAt(center);
490
- this.orbitTarget.copy(center);
491
- }
492
- fitCameraToBounds(bounds) {
493
- const center = bounds.min.clone().add(bounds.max).multiplyScalar(0.5);
494
- const size = bounds.max.clone().sub(bounds.min);
495
- const fov = THREE3.MathUtils.degToRad(this.camera.fov);
496
- const distance = size.z / (2 * Math.tan(fov / 2));
497
- this.camera.position.set(
498
- center.x,
499
- center.y + size.y * 0.4,
500
- center.z + distance * 1.2
501
- );
502
- this.camera.lookAt(center);
503
- this.orbitTarget.copy(center);
737
+ isMobile() {
738
+ return "ontouchstart" in window || navigator.maxTouchPoints > 0 || window.innerWidth < 768;
504
739
  }
505
740
  onKeyToggle = (e) => {
506
741
  if (e.key !== "v") return;
@@ -512,7 +747,7 @@ var PGSGThreeViewer = class {
512
747
  };
513
748
  switchToWalk() {
514
749
  this.controls?.dispose();
515
- this.controls = new WalkCapsuleController({
750
+ const walk = new WalkCapsuleController({
516
751
  camera: this.camera,
517
752
  dom: this.renderer.domElement,
518
753
  colliders: this.colliders,
@@ -520,8 +755,11 @@ var PGSGThreeViewer = class {
520
755
  radius: 0.35,
521
756
  walkSpeed: 2.5,
522
757
  runMultiplier: 2,
523
- gravity: 9.8
758
+ gravity: 9.8,
759
+ usePointerLock: !this.isMobile()
524
760
  });
761
+ this.controls = walk;
762
+ walk.snapToGround();
525
763
  }
526
764
  switchToOrbit() {
527
765
  this.controls?.dispose();
@@ -531,7 +769,8 @@ var PGSGThreeViewer = class {
531
769
  this.renderer.domElement,
532
770
  {
533
771
  target: this.orbitTarget.clone(),
534
- distance: Math.max(distance, 0.5)
772
+ distance: Math.max(distance, 0.5),
773
+ usePointerLock: !this.isMobile()
535
774
  }
536
775
  );
537
776
  }
@@ -539,4 +778,4 @@ var PGSGThreeViewer = class {
539
778
  export {
540
779
  PGSGThreeViewer
541
780
  };
542
- //# sourceMappingURL=pgsg-three-viewer-2ONIARDQ.js.map
781
+ //# sourceMappingURL=pgsg-three-viewer-Z76CF22S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/viewers/three/pgsg-three-viewer.ts","../src/viewers/spark/SparkSplatRenderer.ts","../src/viewers/three/controls/WalkCapsuleController.ts","../src/viewers/three/controls/OrbitCameraController.ts"],"sourcesContent":["import type { PGSGViewerOptions } from \"../../core/types\";\nimport * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/Addons.js\";\nimport nipplejs from \"nipplejs\";\n\nimport { SparkSplatRenderer } from \"../spark/SparkSplatRenderer\";\nimport { WalkCapsuleController } from \"./controls/WalkCapsuleController\";\nimport { OrbitCameraController } from \"./controls/OrbitCameraController\";\n\nexport class PGSGThreeViewer {\n private scene = new THREE.Scene();\n private camera!: THREE.PerspectiveCamera;\n private renderer!: THREE.WebGLRenderer;\n private splats!: SparkSplatRenderer;\n\n private container: HTMLElement;\n\n private controls!: WalkCapsuleController | OrbitCameraController;\n private running = false;\n\n private orbitTarget = new THREE.Vector3();\n private lastTime = performance.now();\n\n private colliders: THREE.Object3D[] = [];\n\n private worldRoot = new THREE.Object3D();\n private splatPivot = new THREE.Object3D();\n private colliderMesh?: THREE.Object3D;\n\n private modeButton?: HTMLDivElement;\n\n constructor(private options: PGSGViewerOptions) {\n this.container = options.container;\n this.options = options;\n if (!this.container) {\n throw new Error(\"[PGSGThreeViewer] Container is required\");\n }\n }\n\n async load() {\n this.initRenderer();\n this.initCamera();\n this.initScene();\n\n this.scene.add(this.worldRoot);\n\n this.splats = new SparkSplatRenderer();\n const { mesh, bounds } = await this.splats.load(this.options.source);\n\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.worldRoot.add(this.splatPivot);\n\n this.worldRoot.rotation.x = Math.PI;\n this.worldRoot.position.y -= bounds.min.y;\n this.worldRoot.updateMatrixWorld(true);\n\n if (this.options.colliderSource) {\n await this.loadCollider(this.options.colliderSource);\n }\n\n this.scene.updateMatrixWorld(true);\n\n if (this.isMobile()) {\n this.initJoystick();\n this.initModeToggle();\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n\n const walk = this.controls as WalkCapsuleController;\n // walk.enableGyro();\n } else {\n this.switchToOrbit();\n }\n window.addEventListener(\"keydown\", this.onKeyToggle);\n }\n\n start() {\n if (this.running) return;\n this.running = true;\n this.renderer.setAnimationLoop((time) => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n\n (this.controls as any)?.update?.(delta);\n\n this.renderer.render(this.scene, this.camera);\n });\n }\n\n pause() {\n this.running = false;\n }\n\n resize() {\n if (!this.renderer || !this.camera) return;\n\n const w = Math.max(1, this.container.clientWidth);\n const h = Math.max(1, this.container.clientHeight);\n\n this.renderer.setSize(w, h);\n this.camera.aspect = w / h;\n this.camera.updateProjectionMatrix();\n }\n\n destroy() {\n this.running = false;\n this.renderer.setAnimationLoop(null);\n this.controls?.dispose();\n this.renderer.dispose();\n }\n\n setCameraMode(mode: \"orbit\" | \"walk\") {\n if (mode === \"orbit\") {\n document.exitPointerLock();\n }\n\n if (mode === \"walk\") {\n // FORCE pointer lock NOW (gesture already happened)\n setTimeout(() => {\n if (document.pointerLockElement !== this.renderer.domElement) {\n this.renderer.domElement.focus();\n this.renderer.domElement.requestPointerLock();\n }\n }, 0);\n }\n }\n\n toggleCameraMode() {\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n this.updateModeLabel(\"ORBIT\");\n } else {\n this.switchToWalk();\n this.updateModeLabel(\"WALK\");\n }\n }\n\n private initRenderer() {\n if (this.renderer) return;\n\n this.renderer = new THREE.WebGLRenderer({\n antialias: this.options.renderer?.antialias ?? false,\n alpha: false,\n powerPreference: \"high-performance\",\n });\n\n this.renderer.setClearColor(0x111111, 1);\n this.renderer.outputColorSpace = THREE.SRGBColorSpace;\n\n this.renderer.setSize(\n this.container.clientWidth,\n this.container.clientHeight,\n );\n\n this.renderer.setPixelRatio(\n this.options.renderer?.pixelRatio ?? window.devicePixelRatio,\n );\n\n this.container.appendChild(this.renderer.domElement);\n\n this.renderer.domElement.addEventListener(\"webglcontextlost\", (e) => {\n e.preventDefault();\n console.log(\"[PGSG Viewer] WebGL context lost\");\n });\n }\n\n private initScene() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x111111);\n\n const gridHelper = new THREE.GridHelper(10, 10);\n // this.scene.add(gridHelper);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x222222, 1.0);\n this.scene.add(light);\n }\n\n private initCamera() {\n this.camera = new THREE.PerspectiveCamera(\n this.options.camera?.fov ?? 60,\n this.container.clientWidth / this.container.clientHeight,\n this.options.camera?.near ?? 0.01,\n this.options.camera?.far ?? 10000,\n );\n\n this.camera.position.set(0, 1.6, 3);\n this.camera.lookAt(0, 1.6, 0);\n }\n\n private initJoystick() {\n const zone = document.createElement(\"div\");\n zone.style.position = \"absolute\";\n zone.style.left = \"20px\";\n zone.style.bottom = \"20px\";\n zone.style.width = \"150px\";\n zone.style.height = \"150px\";\n zone.style.zIndex = \"1000\";\n\n this.container.appendChild(zone);\n\n const joystick = nipplejs.create({\n zone,\n mode: \"static\",\n position: { left: \"75px\", bottom: \"75px\" },\n color: \"white\",\n });\n\n joystick.on(\"move\", (_, data) => {\n const angle = data.angle.radian;\n const force = data.force;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n\n if (this.controls instanceof OrbitCameraController) {\n this.controls.setMovementVector(\n Math.sin(angle) * force,\n Math.cos(angle) * force,\n );\n }\n });\n\n joystick.on(\"end\", () => {\n this.controls.setMovementVector(0, 0);\n });\n }\n\n private initModeToggle() {\n const btn = document.createElement(\"div\");\n\n btn.style.position = \"absolute\";\n btn.style.right = \"20px\";\n btn.style.bottom = \"40px\";\n btn.style.width = \"70px\";\n btn.style.height = \"70px\";\n btn.style.borderRadius = \"50%\";\n btn.style.background = \"rgba(255,255,255,0.15)\";\n btn.style.backdropFilter = \"blur(6px)\";\n btn.style.border = \"2px solid rgba(255,255,255,0.4)\";\n btn.style.display = \"flex\";\n btn.style.alignItems = \"center\";\n btn.style.justifyContent = \"center\";\n btn.style.color = \"white\";\n btn.style.fontWeight = \"bold\";\n btn.style.fontSize = \"14px\";\n btn.style.zIndex = \"1000\";\n btn.style.userSelect = \"none\";\n btn.style.cursor = \"pointer\";\n btn.innerText = \"ORBIT\";\n\n btn.addEventListener(\"click\", () => {\n this.toggleCameraMode();\n });\n\n this.container.appendChild(btn);\n this.modeButton = btn;\n }\n\n private updateModeLabel(mode: \"WALK\" | \"ORBIT\") {\n if (!this.modeButton) return;\n this.modeButton.innerText = mode;\n }\n\n private async loadCollider(url: string) {\n const loader = new GLTFLoader();\n const gltf = await loader.loadAsync(url);\n\n this.colliderMesh = gltf.scene;\n this.worldRoot.add(this.colliderMesh);\n\n this.colliders.length = 0;\n\n this.colliderMesh.traverse((child: any) => {\n if ((child as THREE.Mesh).isMesh) {\n child.material = new THREE.MeshBasicMaterial({ visible: false });\n child.updateMatrixWorld(true);\n this.colliders.push(child);\n }\n });\n\n this.worldRoot.updateMatrixWorld(true);\n }\n\n private isMobile(): boolean {\n return (\n \"ontouchstart\" in window ||\n navigator.maxTouchPoints > 0 ||\n window.innerWidth < 768\n );\n }\n\n private onKeyToggle = (e: KeyboardEvent) => {\n if (e.key !== \"v\") return;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n } else {\n this.switchToWalk();\n }\n };\n\n private switchToWalk() {\n this.controls?.dispose();\n const walk = new WalkCapsuleController({\n camera: this.camera,\n dom: this.renderer.domElement,\n colliders: this.colliders,\n eyeHeight: 1.6,\n radius: 0.35,\n walkSpeed: 2.5,\n runMultiplier: 2.0,\n gravity: 9.8,\n usePointerLock: !this.isMobile(),\n }) as any;\n\n this.controls = walk;\n walk.snapToGround();\n }\n\n private switchToOrbit() {\n this.controls?.dispose();\n\n const distance = this.camera.position.distanceTo(this.orbitTarget);\n\n this.controls = new OrbitCameraController(\n this.camera,\n this.renderer.domElement,\n {\n target: this.orbitTarget.clone(),\n distance: Math.max(distance, 0.5),\n usePointerLock: !this.isMobile(),\n },\n );\n }\n}\n","import { SplatMesh } from \"@sparkjsdev/spark\";\nimport * as THREE from \"three\";\nimport type { ViewerSource } from \"../../core/types\";\nimport { computePLYBounds, parsePLYHeader } from \"../three/utils\";\n\nexport class SparkSplatRenderer {\n private mesh!: SplatMesh;\n\n async load(source: ViewerSource) {\n if (source.type !== \"ply\" && source.type !== \"pgsg\") {\n throw new Error(\"SparkJS supports splat-based sources only\");\n }\n\n // const res = await fetch(source.url);\n // const buffer = await res.arrayBuffer();\n\n // const { vertexCount, headerSize } = parsePLYHeader(buffer);\n // const bounds = computePLYBounds(buffer, headerSize, vertexCount);\n\n this.mesh = new SplatMesh({\n url: source.url,\n });\n\n await this.mesh.initialized;\n this.mesh.updateMatrixWorld(true);\n\n const box = this.mesh.getBoundingBox(true);\n\n const min = box.min.clone();\n const max = box.max.clone();\n\n // Match SparkJS doc defaults\n this.mesh.position.set(0, 0, 0);\n this.mesh.quaternion.identity();\n\n return {\n mesh: this.mesh,\n bounds: {\n min,\n max,\n },\n };\n }\n\n addToScene(scene: THREE.Scene) {\n scene.add(this.mesh);\n }\n\n update(dt: number) {\n // optional: rotation / animation\n }\n\n destroy(scene: THREE.Scene) {\n scene.remove(this.mesh);\n this.mesh.dispose?.();\n }\n}\n","import * as THREE from \"three\";\n\nexport type WalkCapsuleOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n colliders: THREE.Object3D[];\n\n eyeHeight?: number;\n radius?: number;\n gravity?: number;\n walkSpeed?: number;\n runMultiplier?: number;\n lookSensitivity?: number;\n usePointerLock?: boolean;\n};\n\nexport class WalkCapsuleController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private colliders: THREE.Object3D[];\n\n private eyeHeight: number;\n private radius: number;\n\n private gravity: number;\n private walkSpeed: number;\n private runMultiplier: number;\n private lookSensitivity: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private velocity = new THREE.Vector3();\n private onGround = false;\n private lastGroundY: number | null = null;\n\n private keys = new Set<string>();\n private raycaster = new THREE.Raycaster();\n\n private usePointerLock: boolean = false;\n\n private lastTouchX = 0;\n private lastTouchY = 0;\n private externalMove = new THREE.Vector2(0, 0);\n\n private useGyro = false;\n private gyroAlpha = 0;\n private gyroBeta = 0;\n private gyroGamma = 0;\n\n constructor(opts: WalkCapsuleOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.colliders = opts.colliders;\n console.log(\"colliders\", this.colliders.length);\n\n this.eyeHeight = opts.eyeHeight ?? 1.6;\n this.radius = opts.radius ?? 0.35;\n this.gravity = opts.gravity ?? 9.8;\n this.walkSpeed = opts.walkSpeed ?? 2.5;\n this.runMultiplier = opts.runMultiplier ?? 2.0;\n this.lookSensitivity = opts.lookSensitivity ?? 0.0022;\n this.usePointerLock = opts.usePointerLock ?? false;\n\n // Init yaw / pitch from camera\n const euler = new THREE.Euler().setFromQuaternion(\n this.camera.quaternion,\n \"YXZ\",\n );\n this.pitch = euler.x;\n this.yaw = euler.y;\n\n if (this.usePointerLock === false) {\n this.bindTouch();\n } else {\n this.bind();\n }\n }\n\n dispose() {\n if (this.usePointerLock === false) {\n this.unbindTouch();\n } else {\n this.unbind();\n if (this.usePointerLock) document.exitPointerLock();\n }\n }\n\n setMovementVector(x: number, y: number) {\n this.externalMove.set(x, y);\n }\n\n enableGyro() {\n if (typeof DeviceOrientationEvent === \"undefined\") return;\n\n // iOS permission\n if ((DeviceOrientationEvent as any).requestPermission) {\n (DeviceOrientationEvent as any)\n .requestPermission()\n .then((response: string) => {\n if (response === \"granted\") {\n this.startGyro();\n }\n })\n .catch(console.error);\n } else {\n this.startGyro();\n }\n }\n\n // --------------------------------------------------\n // Input binding (SAFE for pointer lock)\n // --------------------------------------------------\n\n private bind() {\n // 🔴 IMPORTANT: pointer lock ONLY on click\n this.dom.addEventListener(\"click\", this.onClick);\n\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"keydown\", this.onKeyDown);\n window.addEventListener(\"keyup\", this.onKeyUp);\n window.addEventListener(\"blur\", this.onBlur);\n\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n }\n\n private bindTouch() {\n this.dom.addEventListener(\"touchstart\", this.onTouchStart);\n this.dom.addEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private unbind() {\n this.dom.removeEventListener(\"click\", this.onClick);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"keydown\", this.onKeyDown);\n window.removeEventListener(\"keyup\", this.onKeyUp);\n window.removeEventListener(\"blur\", this.onBlur);\n }\n\n private unbindTouch() {\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private onClick = () => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) {\n this.dom.requestPointerLock();\n }\n };\n\n private onBlur = () => {\n if (this.usePointerLock) {\n document.exitPointerLock();\n }\n this.keys.clear();\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (this.usePointerLock && document.pointerLockElement !== this.dom) return;\n\n this.yaw -= e.movementX * this.lookSensitivity;\n this.pitch -= e.movementY * this.lookSensitivity;\n\n this.pitch = THREE.MathUtils.clamp(\n this.pitch,\n -Math.PI / 2 + 0.01,\n Math.PI / 2 - 0.01,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n };\n\n private onKeyDown = (e: KeyboardEvent) => {\n this.keys.add(e.key.toLowerCase());\n };\n\n private onKeyUp = (e: KeyboardEvent) => {\n this.keys.delete(e.key.toLowerCase());\n };\n\n private onTouchStart = (e: TouchEvent) => {\n const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\n const t = e.touches[0];\n\n const deltaX = t.clientX - this.lastTouchX;\n const deltaY = t.clientY - this.lastTouchY;\n\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n\n this.yaw -= deltaX * 0.002;\n this.pitch -= deltaY * 0.002;\n\n this.pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitch));\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n };\n\n private startGyro() {\n this.useGyro = true;\n\n window.addEventListener(\"deviceorientation\", (e) => {\n if (!e.alpha || !e.beta) return;\n\n this.gyroAlpha = THREE.MathUtils.degToRad(e.alpha);\n this.gyroBeta = THREE.MathUtils.degToRad(e.beta);\n this.gyroGamma = THREE.MathUtils.degToRad(e.gamma ?? 0);\n });\n }\n\n // --------------------------------------------------\n // Update loop\n // --------------------------------------------------\n\n update(dt: number) {\n if (this.useGyro) {\n this.yaw = THREE.MathUtils.lerp(this.yaw, -this.gyroAlpha, 0.1);\n this.pitch = THREE.MathUtils.lerp(\n this.pitch,\n this.gyroBeta - Math.PI / 2,\n 0.1,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n }\n if (!Number.isFinite(this.camera.position.y)) return;\n\n dt = Math.min(dt, 0.05);\n\n // Direction vectors (yaw-only)\n const forward = new THREE.Vector3();\n this.camera.getWorldDirection(forward);\n forward.y = 0;\n forward.normalize();\n\n const right = new THREE.Vector3()\n .crossVectors(forward, new THREE.Vector3(0, 1, 0))\n .normalize();\n\n const wish = new THREE.Vector3();\n\n // Desktop\n if (this.keys.has(\"w\")) wish.add(forward);\n if (this.keys.has(\"s\")) wish.sub(forward);\n if (this.keys.has(\"d\")) wish.add(right);\n if (this.keys.has(\"a\")) wish.sub(right);\n\n // Mobile\n if (this.externalMove.lengthSq() > 0) {\n wish.addScaledVector(forward, this.externalMove.x);\n wish.addScaledVector(right, this.externalMove.y);\n }\n\n if (wish.lengthSq() > 0) wish.normalize();\n\n // if (this.keys.size > 0) {\n // console.log(\"walking\", [...this.keys]);\n // }\n\n const speed =\n this.walkSpeed * (this.keys.has(\"shift\") ? this.runMultiplier : 1);\n\n this.velocity.x = wish.x * speed;\n this.velocity.z = wish.z * speed;\n\n // gravity (once)\n this.velocity.y -= this.gravity * dt;\n\n // integrate position once\n const nextPos = this.camera.position.clone();\n nextPos.x += this.velocity.x * dt;\n nextPos.z += this.velocity.z * dt;\n nextPos.y += this.velocity.y * dt;\n\n const resolved = this.resolveGroundAndCollisions(nextPos);\n this.camera.position.copy(resolved);\n }\n\n snapToGround() {\n const origin = this.camera.position.clone();\n origin.y += 5;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.far = 50;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n if (worldNormal.y > 0.5) {\n this.lastGroundY = hit.point.y;\n this.camera.position.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n return;\n }\n }\n\n // fallback if no hit\n this.lastGroundY = this.camera.position.y - this.eyeHeight;\n }\n\n // --------------------------------------------------\n // Collision & Ground\n // --------------------------------------------------\n\n private resolveGroundAndCollisions(desiredCamPos: THREE.Vector3) {\n const camPos = desiredCamPos.clone();\n\n // ----- Ground check (robust) -----\n const maxRayDown = 10.0;\n\n const origin = camPos.clone();\n origin.y += 2.0;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.near = 0;\n this.raycaster.far = maxRayDown;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n let groundHit: THREE.Intersection | null = null;\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n // Convert face normal to world space\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n // Accept only surfaces that face upward\n if (worldNormal.y > 0.5) {\n groundHit = hit;\n break;\n }\n }\n\n if (groundHit) {\n const groundY = groundHit.point.y;\n const targetY = groundY + this.eyeHeight;\n\n this.lastGroundY = groundY;\n\n const falling = this.velocity.y <= 0;\n const maxSnap = 1.0;\n\n if (falling && camPos.y <= targetY + maxSnap) {\n camPos.y = targetY;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n } else {\n if (this.lastGroundY !== null) {\n camPos.y = this.lastGroundY + this.eyeHeight;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n }\n\n // ----- Wall push -----\n const center = camPos.clone();\n center.y -= this.eyeHeight * 0.9;\n\n const dirs = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(-1, 0, 0),\n new THREE.Vector3(0, 0, 1),\n new THREE.Vector3(0, 0, -1),\n ];\n\n for (const d of dirs) {\n this.raycaster.set(center, d);\n this.raycaster.far = this.radius + 0.25;\n\n const wallHits = this.raycaster.intersectObjects(this.colliders, true);\n if (!wallHits.length) continue;\n\n const overlap = this.radius + 0.25 - wallHits[0].distance;\n if (overlap > 0) camPos.addScaledVector(d, -overlap);\n }\n\n // console.log({\n // camY: camPos.y.toFixed(2),\n // footY: footY.toFixed(2),\n // groundHit: hits[0]?.point.y.toFixed(2),\n // onGround: this.onGround,\n // });\n\n return camPos;\n }\n}\n","import * as THREE from \"three\";\n\nexport interface OrbitOptions {\n target: THREE.Vector3;\n distance: number;\n minDistance?: number;\n maxDistance?: number;\n rotateSpeed?: number;\n zoomSpeed?: number;\n usePointerLock?: boolean;\n}\n\nexport class OrbitCameraController {\n private camera: THREE.PerspectiveCamera;\n private dom: HTMLElement;\n\n private target: THREE.Vector3;\n private distance: number;\n private minDistance: number;\n private maxDistance: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private rotateSpeed: number;\n private zoomSpeed: number;\n\n private dragging = false;\n private lastX = 0;\n private lastY = 0;\n\n private panning = false;\n private panSpeed = 0.002;\n\n private usePointerLock?: boolean = false;\n private lastTouchX = 0;\n private lastTouchY = 0;\n private externalMove = new THREE.Vector2(0, 0);\n private moveSpeed: number = 5;\n\n constructor(\n camera: THREE.PerspectiveCamera,\n dom: HTMLElement,\n opts: OrbitOptions,\n ) {\n this.camera = camera;\n this.dom = dom;\n\n this.target = opts.target.clone();\n this.distance = opts.distance;\n this.minDistance = opts.minDistance ?? 0.2;\n this.maxDistance = opts.maxDistance ?? 500;\n\n this.rotateSpeed = opts.rotateSpeed ?? 0.005;\n this.zoomSpeed = opts.zoomSpeed ?? 1.1;\n this.usePointerLock = opts.usePointerLock ?? false;\n\n this.syncFromCamera();\n if (this.usePointerLock === false) {\n this.bindTouch();\n } else {\n this.bind();\n this.updateCamera();\n }\n }\n\n update(dt: number) {\n if (this.externalMove.lengthSq() === 0) return;\n\n const forward = new THREE.Vector3();\n this.camera.getWorldDirection(forward);\n forward.y = 0;\n forward.normalize();\n\n const right = new THREE.Vector3()\n .crossVectors(forward, new THREE.Vector3(0, 1, 0))\n .normalize();\n\n const move = new THREE.Vector3()\n .addScaledVector(forward, this.externalMove.x)\n .addScaledVector(right, this.externalMove.y);\n\n if (move.lengthSq() > 0) move.normalize();\n\n move.multiplyScalar(this.moveSpeed * dt);\n\n this.target.add(move);\n\n this.updateCamera();\n }\n\n dispose() {\n if (this.usePointerLock === false) {\n this.unbindTouch();\n } else {\n this.unbind();\n if (this.usePointerLock) document.exitPointerLock();\n }\n }\n\n setMovementVector(x: number, y: number) {\n this.externalMove.set(x, y);\n }\n\n // -----------------------------\n // Setup\n // -----------------------------\n\n private bind() {\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n this.dom.addEventListener(\"mousedown\", this.onMouseDown);\n window.addEventListener(\"mouseup\", this.onMouseUp);\n window.addEventListener(\"mousemove\", this.onMouseMove);\n this.dom.addEventListener(\"wheel\", this.onWheel, { passive: false });\n }\n\n private bindTouch() {\n this.dom.addEventListener(\"touchstart\", this.onTouchStart);\n this.dom.addEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private unbind() {\n this.dom.removeEventListener(\"mousedown\", this.onMouseDown);\n window.removeEventListener(\"mouseup\", this.onMouseUp);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n this.dom.removeEventListener(\"wheel\", this.onWheel);\n }\n\n private unbindTouch() {\n this.dom.removeEventListener(\"touchstart\", this.onTouchStart);\n this.dom.removeEventListener(\"touchmove\", this.onTouchMove);\n }\n\n private syncFromCamera() {\n const offset = this.camera.position.clone().sub(this.target);\n this.distance = offset.length();\n\n const spherical = new THREE.Spherical().setFromVector3(offset);\n this.yaw = spherical.theta;\n this.pitch = spherical.phi;\n }\n\n // -----------------------------\n // Input\n // -----------------------------\n\n private onMouseDown = (e: MouseEvent) => {\n if (e.button === 0) {\n // LEFT = orbit\n this.dragging = true;\n } else if (e.button === 2 || e.button === 1) {\n // RIGHT or MIDDLE = pan\n this.panning = true;\n }\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n };\n\n private onMouseUp = () => {\n this.dragging = false;\n this.panning = false;\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (!this.dragging && !this.panning) return;\n\n const dx = e.clientX - this.lastX;\n const dy = e.clientY - this.lastY;\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n\n // -----------------\n // ORBIT ROTATION\n // -----------------\n if (this.dragging) {\n this.yaw -= dx * this.rotateSpeed;\n this.pitch -= dy * this.rotateSpeed;\n\n this.pitch = THREE.MathUtils.clamp(this.pitch, 0.01, Math.PI - 0.01);\n\n this.updateCamera();\n return;\n }\n\n // -----------------\n // PANNING\n // -----------------\n if (this.panning) {\n const panScale = this.distance * this.panSpeed;\n\n const right = new THREE.Vector3();\n const up = new THREE.Vector3();\n\n this.camera.getWorldDirection(up);\n right.crossVectors(this.camera.up, up).normalize();\n up.crossVectors(\n right,\n this.camera.getWorldDirection(new THREE.Vector3()),\n ).normalize();\n\n const panOffset = new THREE.Vector3()\n .addScaledVector(right, dx * panScale)\n .addScaledVector(up, -dy * panScale);\n\n this.target.add(panOffset);\n this.camera.position.add(panOffset);\n\n // no updateCamera() — we already moved both\n }\n };\n\n private onWheel = (e: WheelEvent) => {\n e.preventDefault();\n\n const zoomFactor = Math.pow(this.zoomSpeed, e.deltaY / 100);\n this.distance *= zoomFactor;\n\n this.distance = THREE.MathUtils.clamp(\n this.distance,\n this.minDistance,\n this.maxDistance,\n );\n\n this.updateCamera();\n };\n\n private onTouchStart = (e: TouchEvent) => {\n const t = e.touches[0];\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n };\n\n private onTouchMove = (e: TouchEvent) => {\n const t = e.touches[0];\n\n const deltaX = t.clientX - this.lastTouchX;\n const deltaY = t.clientY - this.lastTouchY;\n\n this.lastTouchX = t.clientX;\n this.lastTouchY = t.clientY;\n\n this.yaw -= deltaX * 0.002;\n this.pitch -= deltaY * 0.002;\n\n this.pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.pitch));\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n };\n\n // -----------------------------\n // Camera math\n // -----------------------------\n\n private updateCamera() {\n const spherical = new THREE.Spherical(this.distance, this.pitch, this.yaw);\n\n const pos = new THREE.Vector3()\n .setFromSpherical(spherical)\n .add(this.target);\n\n this.camera.position.copy(pos);\n this.camera.lookAt(this.target);\n }\n\n setTarget(v: THREE.Vector3) {\n this.target.copy(v);\n this.updateCamera();\n }\n}\n"],"mappings":"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","names":["THREE","THREE"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  PGSGViewer
3
- } from "../chunk-UDJ24YL2.js";
3
+ } from "../chunk-FAKOSERU.js";
4
4
 
5
5
  // src/react/PGSGCanvas.tsx
6
6
  import * as React from "react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popaya/pgsg-viewer",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -26,6 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@sparkjsdev/spark": "^0.1.10",
29
+ "nipplejs": "^0.10.2",
29
30
  "playcanvas": "^2.14.4",
30
31
  "react": "^18.2.0",
31
32
  "three": "^0.182.0"
@@ -35,4 +36,4 @@
35
36
  "tsup": "^8.0.0",
36
37
  "typescript": "^5.4.0"
37
38
  }
38
- }
39
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/viewers/three/pgsg-three-viewer.ts","../src/viewers/spark/SparkSplatRenderer.ts","../src/viewers/three/controls/WalkCapsuleController.ts","../src/viewers/three/controls/OrbitCameraController.ts"],"sourcesContent":["import type { PGSGViewerOptions } from \"../../core/types\";\nimport * as THREE from \"three\";\nimport { GLTFLoader } from \"three/examples/jsm/Addons.js\";\n\nimport { SparkSplatRenderer } from \"../spark/SparkSplatRenderer\";\nimport { WalkCapsuleController } from \"./controls/WalkCapsuleController\";\nimport { OrbitCameraController } from \"./controls/OrbitCameraController\";\n\nexport class PGSGThreeViewer {\n private scene = new THREE.Scene();\n private camera!: THREE.PerspectiveCamera;\n private renderer!: THREE.WebGLRenderer;\n private splats!: SparkSplatRenderer;\n\n private container: HTMLElement;\n\n private controls!: WalkCapsuleController | OrbitCameraController;\n private running = false;\n\n private orbitTarget = new THREE.Vector3();\n private lastTime = performance.now();\n\n private colliders: THREE.Object3D[] = [];\n\n private worldRoot = new THREE.Object3D();\n private splatPivot = new THREE.Object3D();\n private colliderMesh?: THREE.Object3D;\n\n constructor(private options: PGSGViewerOptions) {\n this.container = options.container;\n this.options = options;\n if (!this.container) {\n throw new Error(\"[PGSGThreeViewer] Container is required\");\n }\n }\n\n async load() {\n this.initRenderer();\n this.initCamera();\n this.initScene();\n\n this.scene.add(this.worldRoot);\n\n this.splats = new SparkSplatRenderer();\n const { mesh, bounds } = await this.splats.load(this.options.source);\n\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.worldRoot.add(this.splatPivot);\n\n this.worldRoot.rotation.x = Math.PI;\n this.worldRoot.position.y -= bounds.min.y;\n this.worldRoot.updateMatrixWorld(true);\n\n // const box = mesh.getBoundingBox();\n // box.applyMatrix4(this.worldRoot.matrixWorld);\n // this.fitCameraToWorldBox(box);\n\n if (this.options.colliderSource) {\n await this.loadCollider(this.options.colliderSource);\n }\n\n // const center = bounds.min.clone().add(bounds.max).multiplyScalar(0.5);\n // const size = bounds.max.clone().sub(bounds.min);\n\n // console.log(\"Center:\", center);\n // console.log(\"Size:\", size);\n\n // this.fitCameraToBounds(bounds);\n\n this.switchToOrbit();\n window.addEventListener(\"keydown\", this.onKeyToggle);\n }\n\n start() {\n if (this.running) return;\n this.running = true;\n this.renderer.setAnimationLoop((time) => {\n const now = performance.now();\n const delta = (now - this.lastTime) / 1000;\n this.lastTime = now;\n\n (this.controls as any)?.update?.(delta);\n\n this.renderer.render(this.scene, this.camera);\n });\n }\n\n pause() {\n this.running = false;\n }\n\n resize() {\n if (!this.renderer || !this.camera) return;\n\n const w = Math.max(1, this.container.clientWidth);\n const h = Math.max(1, this.container.clientHeight);\n\n this.renderer.setSize(w, h);\n this.camera.aspect = w / h;\n this.camera.updateProjectionMatrix();\n }\n\n destroy() {\n this.running = false;\n this.renderer.setAnimationLoop(null);\n this.controls?.dispose();\n this.renderer.dispose();\n }\n\n setCameraMode(mode: \"orbit\" | \"walk\") {\n if (mode === \"orbit\") {\n document.exitPointerLock();\n }\n\n if (mode === \"walk\") {\n // FORCE pointer lock NOW (gesture already happened)\n setTimeout(() => {\n if (document.pointerLockElement !== this.renderer.domElement) {\n this.renderer.domElement.focus();\n this.renderer.domElement.requestPointerLock();\n }\n }, 0);\n }\n }\n\n private initRenderer() {\n if (this.renderer) return;\n\n this.renderer = new THREE.WebGLRenderer({\n antialias: this.options.renderer?.antialias ?? false,\n alpha: false,\n powerPreference: \"high-performance\",\n });\n\n this.renderer.setClearColor(0x111111, 1);\n this.renderer.outputColorSpace = THREE.SRGBColorSpace;\n\n this.renderer.setSize(\n this.container.clientWidth,\n this.container.clientHeight,\n );\n\n this.renderer.setPixelRatio(\n this.options.renderer?.pixelRatio ?? window.devicePixelRatio,\n );\n\n this.container.appendChild(this.renderer.domElement);\n\n this.renderer.domElement.addEventListener(\"webglcontextlost\", (e) => {\n e.preventDefault();\n console.log(\"[PGSG Viewer] WebGL context lost\");\n });\n }\n\n private initScene() {\n this.scene = new THREE.Scene();\n this.scene.background = new THREE.Color(0x111111);\n\n const gridHelper = new THREE.GridHelper(10, 10);\n // this.scene.add(gridHelper);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x222222, 1.0);\n this.scene.add(light);\n }\n\n private initCamera() {\n this.camera = new THREE.PerspectiveCamera(\n 60,\n this.container.clientWidth / this.container.clientHeight,\n 0.01,\n 10000,\n );\n\n this.camera.position.set(0, 1.6, 3);\n this.camera.lookAt(0, 0, 0);\n }\n\n private async loadCollider(url: string) {\n const loader = new GLTFLoader();\n const gltf = await loader.loadAsync(url);\n\n this.colliderMesh = gltf.scene;\n this.worldRoot.add(this.colliderMesh);\n\n this.colliders.length = 0;\n\n this.colliderMesh.traverse((child: any) => {\n if ((child as THREE.Mesh).isMesh) {\n child.material = new THREE.MeshNormalMaterial();\n child.updateMatrixWorld(true);\n this.colliders.push(child);\n }\n });\n\n this.worldRoot.updateMatrixWorld(true);\n }\n\n private fitCameraToWorldBox(box: THREE.Box3) {\n const center = box.getCenter(new THREE.Vector3());\n const size = box.getSize(new THREE.Vector3());\n\n const maxDim = Math.max(size.x, size.y, size.z);\n\n const fov = THREE.MathUtils.degToRad(this.camera.fov);\n const distance = maxDim / (2 * Math.tan(fov / 2));\n\n const direction = new THREE.Vector3(0, 0, 1); // view from front\n const position = center\n .clone()\n .add(direction.multiplyScalar(distance * 1.2));\n\n this.camera.position.copy(position);\n this.camera.lookAt(center);\n\n this.orbitTarget.copy(center);\n }\n\n private fitCameraToBounds(bounds: {\n min: THREE.Vector3;\n max: THREE.Vector3;\n }) {\n const center = bounds.min.clone().add(bounds.max).multiplyScalar(0.5);\n const size = bounds.max.clone().sub(bounds.min);\n\n const fov = THREE.MathUtils.degToRad(this.camera.fov);\n const distance = size.z / (2 * Math.tan(fov / 2));\n\n this.camera.position.set(\n center.x,\n center.y + size.y * 0.4,\n center.z + distance * 1.2,\n );\n\n this.camera.lookAt(center);\n this.orbitTarget.copy(center);\n }\n\n private onKeyToggle = (e: KeyboardEvent) => {\n if (e.key !== \"v\") return;\n\n if (this.controls instanceof WalkCapsuleController) {\n this.switchToOrbit();\n } else {\n this.switchToWalk();\n }\n };\n\n private switchToWalk() {\n this.controls?.dispose();\n this.controls = new WalkCapsuleController({\n camera: this.camera,\n dom: this.renderer.domElement,\n colliders: this.colliders,\n eyeHeight: 1.6,\n radius: 0.35,\n walkSpeed: 2.5,\n runMultiplier: 2.0,\n gravity: 9.8,\n }) as any;\n }\n\n private switchToOrbit() {\n this.controls?.dispose();\n\n const distance = this.camera.position.distanceTo(this.orbitTarget);\n\n this.controls = new OrbitCameraController(\n this.camera,\n this.renderer.domElement,\n {\n target: this.orbitTarget.clone(),\n distance: Math.max(distance, 0.5),\n },\n );\n }\n}\n","import { SplatMesh } from \"@sparkjsdev/spark\";\nimport * as THREE from \"three\";\nimport type { ViewerSource } from \"../../core/types\";\nimport { computePLYBounds, parsePLYHeader } from \"../three/utils\";\n\nexport class SparkSplatRenderer {\n private mesh!: SplatMesh;\n\n async load(source: ViewerSource) {\n if (source.type !== \"ply\" && source.type !== \"pgsg\") {\n throw new Error(\"SparkJS supports splat-based sources only\");\n }\n\n // const res = await fetch(source.url);\n // const buffer = await res.arrayBuffer();\n\n // const { vertexCount, headerSize } = parsePLYHeader(buffer);\n // const bounds = computePLYBounds(buffer, headerSize, vertexCount);\n\n this.mesh = new SplatMesh({\n url: source.url,\n });\n\n await this.mesh.initialized;\n this.mesh.updateMatrixWorld(true);\n\n const box = this.mesh.getBoundingBox(true);\n\n const min = box.min.clone();\n const max = box.max.clone();\n\n // Match SparkJS doc defaults\n this.mesh.position.set(0, 0, 0);\n this.mesh.quaternion.identity();\n\n return {\n mesh: this.mesh,\n bounds: {\n min,\n max,\n },\n };\n }\n\n addToScene(scene: THREE.Scene) {\n scene.add(this.mesh);\n }\n\n update(dt: number) {\n // optional: rotation / animation\n }\n\n destroy(scene: THREE.Scene) {\n scene.remove(this.mesh);\n this.mesh.dispose?.();\n }\n}\n","import * as THREE from \"three\";\n\nexport type WalkCapsuleOptions = {\n dom: HTMLElement;\n camera: THREE.PerspectiveCamera;\n colliders: THREE.Object3D[];\n\n eyeHeight?: number;\n radius?: number;\n gravity?: number;\n walkSpeed?: number;\n runMultiplier?: number;\n lookSensitivity?: number;\n};\n\nexport class WalkCapsuleController {\n private dom: HTMLElement;\n private camera: THREE.PerspectiveCamera;\n private colliders: THREE.Object3D[];\n\n private eyeHeight: number;\n private radius: number;\n\n private gravity: number;\n private walkSpeed: number;\n private runMultiplier: number;\n private lookSensitivity: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private velocity = new THREE.Vector3();\n private onGround = false;\n\n private keys = new Set<string>();\n private raycaster = new THREE.Raycaster();\n\n constructor(opts: WalkCapsuleOptions) {\n this.dom = opts.dom;\n this.camera = opts.camera;\n this.colliders = opts.colliders;\n console.log(\"colliders\", this.colliders.length);\n\n this.eyeHeight = opts.eyeHeight ?? 1.6;\n this.radius = opts.radius ?? 0.35;\n this.gravity = opts.gravity ?? 9.8;\n this.walkSpeed = opts.walkSpeed ?? 2.5;\n this.runMultiplier = opts.runMultiplier ?? 2.0;\n this.lookSensitivity = opts.lookSensitivity ?? 0.0022;\n\n // Init yaw / pitch from camera\n const euler = new THREE.Euler().setFromQuaternion(\n this.camera.quaternion,\n \"YXZ\",\n );\n this.pitch = euler.x;\n this.yaw = euler.y;\n\n this.bind();\n }\n\n dispose() {\n this.unbind();\n document.exitPointerLock();\n }\n\n // --------------------------------------------------\n // Input binding (SAFE for pointer lock)\n // --------------------------------------------------\n\n private bind() {\n // 🔴 IMPORTANT: pointer lock ONLY on click\n this.dom.addEventListener(\"click\", this.onClick);\n\n window.addEventListener(\"mousemove\", this.onMouseMove);\n window.addEventListener(\"keydown\", this.onKeyDown);\n window.addEventListener(\"keyup\", this.onKeyUp);\n window.addEventListener(\"blur\", this.onBlur);\n\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n }\n\n private unbind() {\n this.dom.removeEventListener(\"click\", this.onClick);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n window.removeEventListener(\"keydown\", this.onKeyDown);\n window.removeEventListener(\"keyup\", this.onKeyUp);\n window.removeEventListener(\"blur\", this.onBlur);\n }\n\n private onClick = () => {\n if (document.pointerLockElement !== this.dom) {\n this.dom.requestPointerLock();\n }\n };\n\n private onBlur = () => {\n document.exitPointerLock();\n this.keys.clear();\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (document.pointerLockElement !== this.dom) return;\n\n this.yaw -= e.movementX * this.lookSensitivity;\n this.pitch -= e.movementY * this.lookSensitivity;\n\n this.pitch = THREE.MathUtils.clamp(\n this.pitch,\n -Math.PI / 2 + 0.01,\n Math.PI / 2 - 0.01,\n );\n\n this.camera.quaternion.setFromEuler(\n new THREE.Euler(this.pitch, this.yaw, 0, \"YXZ\"),\n );\n };\n\n private onKeyDown = (e: KeyboardEvent) => {\n this.keys.add(e.key.toLowerCase());\n };\n\n private onKeyUp = (e: KeyboardEvent) => {\n this.keys.delete(e.key.toLowerCase());\n };\n\n // --------------------------------------------------\n // Update loop\n // --------------------------------------------------\n\n update(dt: number) {\n if (!Number.isFinite(this.camera.position.y)) return;\n\n dt = Math.min(dt, 0.05);\n\n // Direction vectors (yaw-only)\n const forward = new THREE.Vector3();\n this.camera.getWorldDirection(forward);\n forward.y = 0;\n forward.normalize();\n\n const right = new THREE.Vector3()\n .crossVectors(forward, new THREE.Vector3(0, 1, 0))\n .normalize();\n\n const wish = new THREE.Vector3();\n if (this.keys.has(\"w\")) wish.add(forward);\n if (this.keys.has(\"s\")) wish.sub(forward);\n if (this.keys.has(\"d\")) wish.add(right);\n if (this.keys.has(\"a\")) wish.sub(right);\n\n if (wish.lengthSq() > 0) wish.normalize();\n\n // if (this.keys.size > 0) {\n // console.log(\"walking\", [...this.keys]);\n // }\n\n const speed =\n this.walkSpeed * (this.keys.has(\"shift\") ? this.runMultiplier : 1);\n\n this.velocity.x = wish.x * speed;\n this.velocity.z = wish.z * speed;\n\n // gravity (once)\n this.velocity.y -= this.gravity * dt;\n\n // integrate position once\n const nextPos = this.camera.position.clone();\n nextPos.x += this.velocity.x * dt;\n nextPos.z += this.velocity.z * dt;\n nextPos.y += this.velocity.y * dt;\n\n const resolved = this.resolveGroundAndCollisions(nextPos);\n this.camera.position.copy(resolved);\n }\n\n // --------------------------------------------------\n // Collision & Ground\n // --------------------------------------------------\n\n private resolveGroundAndCollisions(desiredCamPos: THREE.Vector3) {\n const camPos = desiredCamPos.clone();\n\n // ----- Ground check (robust) -----\n const maxRayDown = 10.0;\n\n const origin = camPos.clone();\n origin.y += 2.0;\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.near = 0;\n this.raycaster.far = maxRayDown;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n let groundHit: THREE.Intersection | null = null;\n\n for (const hit of hits) {\n if (!hit.face) continue;\n\n // Convert face normal to world space\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(\n hit.object.matrixWorld,\n );\n\n const worldNormal = hit.face.normal\n .clone()\n .applyMatrix3(normalMatrix)\n .normalize();\n\n // Accept only surfaces that face upward\n if (worldNormal.y > 0.5) {\n groundHit = hit;\n break;\n }\n }\n\n if (groundHit) {\n const groundY = groundHit.point.y;\n const targetY = groundY + this.eyeHeight;\n\n const falling = this.velocity.y <= 0;\n const maxSnap = 1.0;\n\n if (falling && camPos.y <= targetY + maxSnap) {\n camPos.y = targetY;\n this.velocity.y = 0;\n this.onGround = true;\n } else {\n this.onGround = false;\n }\n } else {\n this.onGround = false;\n }\n\n // ----- Wall push -----\n const center = camPos.clone();\n center.y -= this.eyeHeight * 0.9;\n\n const dirs = [\n new THREE.Vector3(1, 0, 0),\n new THREE.Vector3(-1, 0, 0),\n new THREE.Vector3(0, 0, 1),\n new THREE.Vector3(0, 0, -1),\n ];\n\n for (const d of dirs) {\n this.raycaster.set(center, d);\n this.raycaster.far = this.radius + 0.25;\n\n const wallHits = this.raycaster.intersectObjects(this.colliders, true);\n if (!wallHits.length) continue;\n\n const overlap = this.radius + 0.25 - wallHits[0].distance;\n if (overlap > 0) camPos.addScaledVector(d, -overlap);\n }\n\n // console.log({\n // camY: camPos.y.toFixed(2),\n // footY: footY.toFixed(2),\n // groundHit: hits[0]?.point.y.toFixed(2),\n // onGround: this.onGround,\n // });\n\n return camPos;\n }\n}\n","import * as THREE from \"three\";\n\nexport interface OrbitOptions {\n target: THREE.Vector3;\n distance: number;\n minDistance?: number;\n maxDistance?: number;\n rotateSpeed?: number;\n zoomSpeed?: number;\n}\n\nexport class OrbitCameraController {\n private camera: THREE.PerspectiveCamera;\n private dom: HTMLElement;\n\n private target: THREE.Vector3;\n private distance: number;\n private minDistance: number;\n private maxDistance: number;\n\n private yaw = 0;\n private pitch = 0;\n\n private rotateSpeed: number;\n private zoomSpeed: number;\n\n private dragging = false;\n private lastX = 0;\n private lastY = 0;\n\n private panning = false;\n private panSpeed = 0.002;\n\n constructor(\n camera: THREE.PerspectiveCamera,\n dom: HTMLElement,\n opts: OrbitOptions\n ) {\n this.camera = camera;\n this.dom = dom;\n\n this.target = opts.target.clone();\n this.distance = opts.distance;\n this.minDistance = opts.minDistance ?? 0.2;\n this.maxDistance = opts.maxDistance ?? 500;\n\n this.rotateSpeed = opts.rotateSpeed ?? 0.005;\n this.zoomSpeed = opts.zoomSpeed ?? 1.1;\n\n this.syncFromCamera();\n this.bind();\n this.updateCamera();\n }\n\n dispose() {\n this.unbind();\n }\n\n // -----------------------------\n // Setup\n // -----------------------------\n\n private bind() {\n this.dom.addEventListener(\"contextmenu\", (e) => e.preventDefault());\n this.dom.addEventListener(\"mousedown\", this.onMouseDown);\n window.addEventListener(\"mouseup\", this.onMouseUp);\n window.addEventListener(\"mousemove\", this.onMouseMove);\n this.dom.addEventListener(\"wheel\", this.onWheel, { passive: false });\n }\n\n private unbind() {\n this.dom.removeEventListener(\"mousedown\", this.onMouseDown);\n window.removeEventListener(\"mouseup\", this.onMouseUp);\n window.removeEventListener(\"mousemove\", this.onMouseMove);\n this.dom.removeEventListener(\"wheel\", this.onWheel);\n }\n\n private syncFromCamera() {\n const offset = this.camera.position.clone().sub(this.target);\n this.distance = offset.length();\n\n const spherical = new THREE.Spherical().setFromVector3(offset);\n this.yaw = spherical.theta;\n this.pitch = spherical.phi;\n }\n\n // -----------------------------\n // Input\n // -----------------------------\n\n private onMouseDown = (e: MouseEvent) => {\n if (e.button === 0) {\n // LEFT = orbit\n this.dragging = true;\n } else if (e.button === 2 || e.button === 1) {\n // RIGHT or MIDDLE = pan\n this.panning = true;\n }\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n };\n\n private onMouseUp = () => {\n this.dragging = false;\n this.panning = false;\n };\n\n private onMouseMove = (e: MouseEvent) => {\n if (!this.dragging && !this.panning) return;\n\n const dx = e.clientX - this.lastX;\n const dy = e.clientY - this.lastY;\n\n this.lastX = e.clientX;\n this.lastY = e.clientY;\n\n // -----------------\n // ORBIT ROTATION\n // -----------------\n if (this.dragging) {\n this.yaw -= dx * this.rotateSpeed;\n this.pitch -= dy * this.rotateSpeed;\n\n this.pitch = THREE.MathUtils.clamp(this.pitch, 0.01, Math.PI - 0.01);\n\n this.updateCamera();\n return;\n }\n\n // -----------------\n // PANNING\n // -----------------\n if (this.panning) {\n const panScale = this.distance * this.panSpeed;\n\n const right = new THREE.Vector3();\n const up = new THREE.Vector3();\n\n this.camera.getWorldDirection(up);\n right.crossVectors(this.camera.up, up).normalize();\n up.crossVectors(\n right,\n this.camera.getWorldDirection(new THREE.Vector3())\n ).normalize();\n\n const panOffset = new THREE.Vector3()\n .addScaledVector(right, dx * panScale)\n .addScaledVector(up, -dy * panScale);\n\n this.target.add(panOffset);\n this.camera.position.add(panOffset);\n\n // no updateCamera() — we already moved both\n }\n };\n\n private onWheel = (e: WheelEvent) => {\n e.preventDefault();\n\n const zoomFactor = Math.pow(this.zoomSpeed, e.deltaY / 100);\n this.distance *= zoomFactor;\n\n this.distance = THREE.MathUtils.clamp(\n this.distance,\n this.minDistance,\n this.maxDistance\n );\n\n this.updateCamera();\n };\n\n // -----------------------------\n // Camera math\n // -----------------------------\n\n private updateCamera() {\n const spherical = new THREE.Spherical(this.distance, this.pitch, this.yaw);\n\n const pos = new THREE.Vector3()\n .setFromSpherical(spherical)\n .add(this.target);\n\n this.camera.position.copy(pos);\n this.camera.lookAt(this.target);\n }\n\n setTarget(v: THREE.Vector3) {\n this.target.copy(v);\n this.updateCamera();\n }\n}\n"],"mappings":"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","names":["THREE","THREE"]}