@popaya/pgsg-viewer 0.1.0 → 0.1.2

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-ZU5OI33Q.js");
13
+ const { PGSGThreeViewer } = await import("./pgsg-three-viewer-2ONIARDQ.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-TBA7YDMF.js.map
33
+ //# sourceMappingURL=chunk-UDJ24YL2.js.map
@@ -26,6 +26,7 @@ interface PGSGViewerOptions {
26
26
  source: ViewerSource;
27
27
  camera?: CameraOptions;
28
28
  controls?: ControlOptions;
29
+ colliderSource?: string;
29
30
  renderer?: {
30
31
  pixelRatio?: number;
31
32
  antialias?: boolean;
@@ -1,7 +1,7 @@
1
1
  import "../chunk-PYYLHUV6.js";
2
2
  import {
3
3
  PGSGViewer
4
- } from "../chunk-TBA7YDMF.js";
4
+ } from "../chunk-UDJ24YL2.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-TBA7YDMF.js";
4
+ } from "./chunk-UDJ24YL2.js";
5
5
  export {
6
6
  PGSGViewer
7
7
  };
@@ -1,9 +1,9 @@
1
1
  // src/viewers/three/pgsg-three-viewer.ts
2
- import * as THREE4 from "three";
2
+ import * as THREE3 from "three";
3
+ import { GLTFLoader } from "three/examples/jsm/Addons.js";
3
4
 
4
5
  // src/viewers/spark/SparkSplatRenderer.ts
5
6
  import { SplatMesh } from "@sparkjsdev/spark";
6
- import * as THREE from "three";
7
7
  var SparkSplatRenderer = class {
8
8
  mesh;
9
9
  async load(source) {
@@ -13,13 +13,18 @@ var SparkSplatRenderer = class {
13
13
  this.mesh = new SplatMesh({
14
14
  url: source.url
15
15
  });
16
- this.mesh.quaternion.set(1, 0, 0, 0);
16
+ await this.mesh.initialized;
17
+ this.mesh.updateMatrixWorld(true);
18
+ const box = this.mesh.getBoundingBox(true);
19
+ const min = box.min.clone();
20
+ const max = box.max.clone();
17
21
  this.mesh.position.set(0, 0, 0);
22
+ this.mesh.quaternion.identity();
18
23
  return {
19
24
  mesh: this.mesh,
20
25
  bounds: {
21
- min: new THREE.Vector3(0, 0, 0),
22
- max: new THREE.Vector3(0, 0, 0)
26
+ min,
27
+ max
23
28
  }
24
29
  };
25
30
  }
@@ -35,7 +40,7 @@ var SparkSplatRenderer = class {
35
40
  };
36
41
 
37
42
  // src/viewers/three/controls/WalkCapsuleController.ts
38
- import * as THREE2 from "three";
43
+ import * as THREE from "three";
39
44
  var WalkCapsuleController = class {
40
45
  dom;
41
46
  camera;
@@ -48,21 +53,22 @@ var WalkCapsuleController = class {
48
53
  lookSensitivity;
49
54
  yaw = 0;
50
55
  pitch = 0;
51
- velocity = new THREE2.Vector3();
56
+ velocity = new THREE.Vector3();
52
57
  onGround = false;
53
58
  keys = /* @__PURE__ */ new Set();
54
- raycaster = new THREE2.Raycaster();
59
+ raycaster = new THREE.Raycaster();
55
60
  constructor(opts) {
56
61
  this.dom = opts.dom;
57
62
  this.camera = opts.camera;
58
63
  this.colliders = opts.colliders;
64
+ console.log("colliders", this.colliders.length);
59
65
  this.eyeHeight = opts.eyeHeight ?? 1.6;
60
66
  this.radius = opts.radius ?? 0.35;
61
67
  this.gravity = opts.gravity ?? 9.8;
62
68
  this.walkSpeed = opts.walkSpeed ?? 2.5;
63
69
  this.runMultiplier = opts.runMultiplier ?? 2;
64
70
  this.lookSensitivity = opts.lookSensitivity ?? 22e-4;
65
- const euler = new THREE2.Euler().setFromQuaternion(
71
+ const euler = new THREE.Euler().setFromQuaternion(
66
72
  this.camera.quaternion,
67
73
  "YXZ"
68
74
  );
@@ -105,13 +111,13 @@ var WalkCapsuleController = class {
105
111
  if (document.pointerLockElement !== this.dom) return;
106
112
  this.yaw -= e.movementX * this.lookSensitivity;
107
113
  this.pitch -= e.movementY * this.lookSensitivity;
108
- this.pitch = THREE2.MathUtils.clamp(
114
+ this.pitch = THREE.MathUtils.clamp(
109
115
  this.pitch,
110
116
  -Math.PI / 2 + 0.01,
111
117
  Math.PI / 2 - 0.01
112
118
  );
113
119
  this.camera.quaternion.setFromEuler(
114
- new THREE2.Euler(this.pitch, this.yaw, 0, "YXZ")
120
+ new THREE.Euler(this.pitch, this.yaw, 0, "YXZ")
115
121
  );
116
122
  };
117
123
  onKeyDown = (e) => {
@@ -126,30 +132,25 @@ var WalkCapsuleController = class {
126
132
  update(dt) {
127
133
  if (!Number.isFinite(this.camera.position.y)) return;
128
134
  dt = Math.min(dt, 0.05);
129
- const forward = new THREE2.Vector3();
135
+ const forward = new THREE.Vector3();
130
136
  this.camera.getWorldDirection(forward);
131
137
  forward.y = 0;
132
138
  forward.normalize();
133
- const right = new THREE2.Vector3().crossVectors(forward, new THREE2.Vector3(0, 1, 0)).normalize();
134
- const wish = new THREE2.Vector3();
139
+ const right = new THREE.Vector3().crossVectors(forward, new THREE.Vector3(0, 1, 0)).normalize();
140
+ const wish = new THREE.Vector3();
135
141
  if (this.keys.has("w")) wish.add(forward);
136
142
  if (this.keys.has("s")) wish.sub(forward);
137
143
  if (this.keys.has("d")) wish.add(right);
138
144
  if (this.keys.has("a")) wish.sub(right);
139
145
  if (wish.lengthSq() > 0) wish.normalize();
140
- if (this.keys.size > 0) {
141
- console.log("walking", [...this.keys]);
142
- }
143
146
  const speed = this.walkSpeed * (this.keys.has("shift") ? this.runMultiplier : 1);
144
147
  this.velocity.x = wish.x * speed;
145
148
  this.velocity.z = wish.z * speed;
146
- if (!this.onGround) {
147
- this.velocity.y -= this.gravity * dt;
148
- } else {
149
- this.velocity.y = 0;
150
- }
149
+ this.velocity.y -= this.gravity * dt;
151
150
  const nextPos = this.camera.position.clone();
152
- nextPos.addScaledVector(this.velocity, dt);
151
+ nextPos.x += this.velocity.x * dt;
152
+ nextPos.z += this.velocity.z * dt;
153
+ nextPos.y += this.velocity.y * dt;
153
154
  const resolved = this.resolveGroundAndCollisions(nextPos);
154
155
  this.camera.position.copy(resolved);
155
156
  }
@@ -158,16 +159,31 @@ var WalkCapsuleController = class {
158
159
  // --------------------------------------------------
159
160
  resolveGroundAndCollisions(desiredCamPos) {
160
161
  const camPos = desiredCamPos.clone();
161
- const footY = camPos.y - this.eyeHeight;
162
- const origin = new THREE2.Vector3(camPos.x, footY + 0.5, camPos.z);
163
- this.raycaster.set(origin, new THREE2.Vector3(0, -1, 0));
164
- this.raycaster.far = 2;
162
+ const maxRayDown = 10;
163
+ const origin = camPos.clone();
164
+ origin.y += 2;
165
+ this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));
166
+ this.raycaster.near = 0;
167
+ this.raycaster.far = maxRayDown;
165
168
  const hits = this.raycaster.intersectObjects(this.colliders, true);
166
- if (hits.length) {
167
- const groundY = hits[0].point.y;
169
+ let groundHit = null;
170
+ for (const hit of hits) {
171
+ if (!hit.face) continue;
172
+ const normalMatrix = new THREE.Matrix3().getNormalMatrix(
173
+ hit.object.matrixWorld
174
+ );
175
+ const worldNormal = hit.face.normal.clone().applyMatrix3(normalMatrix).normalize();
176
+ if (worldNormal.y > 0.5) {
177
+ groundHit = hit;
178
+ break;
179
+ }
180
+ }
181
+ if (groundHit) {
182
+ const groundY = groundHit.point.y;
168
183
  const targetY = groundY + this.eyeHeight;
169
- const epsilon = 0.02;
170
- if (camPos.y <= targetY + epsilon) {
184
+ const falling = this.velocity.y <= 0;
185
+ const maxSnap = 1;
186
+ if (falling && camPos.y <= targetY + maxSnap) {
171
187
  camPos.y = targetY;
172
188
  this.velocity.y = 0;
173
189
  this.onGround = true;
@@ -180,10 +196,10 @@ var WalkCapsuleController = class {
180
196
  const center = camPos.clone();
181
197
  center.y -= this.eyeHeight * 0.9;
182
198
  const dirs = [
183
- new THREE2.Vector3(1, 0, 0),
184
- new THREE2.Vector3(-1, 0, 0),
185
- new THREE2.Vector3(0, 0, 1),
186
- new THREE2.Vector3(0, 0, -1)
199
+ new THREE.Vector3(1, 0, 0),
200
+ new THREE.Vector3(-1, 0, 0),
201
+ new THREE.Vector3(0, 0, 1),
202
+ new THREE.Vector3(0, 0, -1)
187
203
  ];
188
204
  for (const d of dirs) {
189
205
  this.raycaster.set(center, d);
@@ -193,18 +209,12 @@ var WalkCapsuleController = class {
193
209
  const overlap = this.radius + 0.25 - wallHits[0].distance;
194
210
  if (overlap > 0) camPos.addScaledVector(d, -overlap);
195
211
  }
196
- console.log({
197
- camY: camPos.y.toFixed(2),
198
- footY: footY.toFixed(2),
199
- groundHit: hits[0]?.point.y.toFixed(2),
200
- onGround: this.onGround
201
- });
202
212
  return camPos;
203
213
  }
204
214
  };
205
215
 
206
216
  // src/viewers/three/controls/OrbitCameraController.ts
207
- import * as THREE3 from "three";
217
+ import * as THREE2 from "three";
208
218
  var OrbitCameraController = class {
209
219
  camera;
210
220
  dom;
@@ -256,7 +266,7 @@ var OrbitCameraController = class {
256
266
  syncFromCamera() {
257
267
  const offset = this.camera.position.clone().sub(this.target);
258
268
  this.distance = offset.length();
259
- const spherical = new THREE3.Spherical().setFromVector3(offset);
269
+ const spherical = new THREE2.Spherical().setFromVector3(offset);
260
270
  this.yaw = spherical.theta;
261
271
  this.pitch = spherical.phi;
262
272
  }
@@ -285,21 +295,21 @@ var OrbitCameraController = class {
285
295
  if (this.dragging) {
286
296
  this.yaw -= dx * this.rotateSpeed;
287
297
  this.pitch -= dy * this.rotateSpeed;
288
- this.pitch = THREE3.MathUtils.clamp(this.pitch, 0.01, Math.PI - 0.01);
298
+ this.pitch = THREE2.MathUtils.clamp(this.pitch, 0.01, Math.PI - 0.01);
289
299
  this.updateCamera();
290
300
  return;
291
301
  }
292
302
  if (this.panning) {
293
303
  const panScale = this.distance * this.panSpeed;
294
- const right = new THREE3.Vector3();
295
- const up = new THREE3.Vector3();
304
+ const right = new THREE2.Vector3();
305
+ const up = new THREE2.Vector3();
296
306
  this.camera.getWorldDirection(up);
297
307
  right.crossVectors(this.camera.up, up).normalize();
298
308
  up.crossVectors(
299
309
  right,
300
- this.camera.getWorldDirection(new THREE3.Vector3())
310
+ this.camera.getWorldDirection(new THREE2.Vector3())
301
311
  ).normalize();
302
- const panOffset = new THREE3.Vector3().addScaledVector(right, dx * panScale).addScaledVector(up, -dy * panScale);
312
+ const panOffset = new THREE2.Vector3().addScaledVector(right, dx * panScale).addScaledVector(up, -dy * panScale);
303
313
  this.target.add(panOffset);
304
314
  this.camera.position.add(panOffset);
305
315
  }
@@ -308,7 +318,7 @@ var OrbitCameraController = class {
308
318
  e.preventDefault();
309
319
  const zoomFactor = Math.pow(this.zoomSpeed, e.deltaY / 100);
310
320
  this.distance *= zoomFactor;
311
- this.distance = THREE3.MathUtils.clamp(
321
+ this.distance = THREE2.MathUtils.clamp(
312
322
  this.distance,
313
323
  this.minDistance,
314
324
  this.maxDistance
@@ -319,8 +329,8 @@ var OrbitCameraController = class {
319
329
  // Camera math
320
330
  // -----------------------------
321
331
  updateCamera() {
322
- const spherical = new THREE3.Spherical(this.distance, this.pitch, this.yaw);
323
- const pos = new THREE3.Vector3().setFromSpherical(spherical).add(this.target);
332
+ const spherical = new THREE2.Spherical(this.distance, this.pitch, this.yaw);
333
+ const pos = new THREE2.Vector3().setFromSpherical(spherical).add(this.target);
324
334
  this.camera.position.copy(pos);
325
335
  this.camera.lookAt(this.target);
326
336
  }
@@ -340,72 +350,35 @@ var PGSGThreeViewer = class {
340
350
  throw new Error("[PGSGThreeViewer] Container is required");
341
351
  }
342
352
  }
343
- scene = new THREE4.Scene();
353
+ scene = new THREE3.Scene();
344
354
  camera;
345
355
  renderer;
346
356
  splats;
347
357
  container;
348
358
  controls;
349
359
  running = false;
350
- orbitTarget = new THREE4.Vector3();
351
- // 🔑 CRITICAL
360
+ orbitTarget = new THREE3.Vector3();
352
361
  lastTime = performance.now();
353
362
  colliders = [];
354
- groundY = 0;
355
- FLOOR_Y = -1.6;
356
- splatPivot = new THREE4.Object3D();
357
- splatMesh;
358
- splatPresets = [
359
- // P0: identity
360
- { r: [0, 0, 0], s: [1, 1, 1] },
361
- // P1: Z-up -> Y-up (common GS)
362
- { r: [-Math.PI / 2, 0, 0], s: [1, 1, 1] },
363
- // P2: Z-up -> Y-up + 90° roll (your screenshot strongly suggests this)
364
- { r: [-Math.PI / 2, 0, Math.PI / 2], s: [1, 1, 1] },
365
- // P3: Z-up -> Y-up + -90° roll
366
- { r: [-Math.PI / 2, 0, -Math.PI / 2], s: [1, 1, 1] },
367
- // P4: Z-up -> Y-up + flip forward
368
- { r: [-Math.PI / 2, Math.PI, 0], s: [1, 1, 1] },
369
- // P5: Z-up -> Y-up + 90° roll + flip forward
370
- { r: [-Math.PI / 2, Math.PI, Math.PI / 2], s: [1, 1, 1] },
371
- // P6: Z-up -> Y-up + handedness fix
372
- { r: [-Math.PI / 2, 0, 0], s: [1, 1, -1] },
373
- // P7: Z-up -> Y-up + 90° roll + handedness fix
374
- { r: [-Math.PI / 2, 0, Math.PI / 2], s: [1, 1, -1] }
375
- ];
376
- splatPresetIndex = 0;
363
+ worldRoot = new THREE3.Object3D();
364
+ splatPivot = new THREE3.Object3D();
365
+ colliderMesh;
377
366
  async load() {
378
367
  this.initRenderer();
379
368
  this.initCamera();
380
369
  this.initScene();
370
+ this.scene.add(this.worldRoot);
381
371
  this.splats = new SparkSplatRenderer();
382
372
  const { mesh, bounds } = await this.splats.load(this.options.source);
383
373
  this.splatPivot.clear();
384
374
  this.splatPivot.add(mesh);
385
- this.scene.add(this.splatPivot);
386
- this.splatPivot.position.y -= bounds.min.y;
387
- this.splatPivot.updateMatrixWorld(true);
388
- this.groundY = 0;
389
- const ground = new THREE4.Mesh(
390
- new THREE4.PlaneGeometry(500, 500),
391
- new THREE4.MeshBasicMaterial({ visible: false })
392
- );
393
- ground.rotation.x = -Math.PI / 2;
394
- ground.position.y = this.FLOOR_Y;
395
- ground.updateMatrixWorld(true);
396
- this.scene.add(ground);
397
- this.colliders = [ground];
398
- console.log("[PLY bounds]", bounds.min, bounds.max);
399
- this.addBoxCollider(
400
- new THREE4.Vector3(0.2, 3, 10),
401
- // thickness, height, length
402
- new THREE4.Vector3(2.5, 1.5, 0)
403
- // center
404
- );
405
- this.addBoxCollider(
406
- new THREE4.Vector3(1.5, 0.8, 0.8),
407
- new THREE4.Vector3(0, 0.4, -1)
408
- );
375
+ this.worldRoot.add(this.splatPivot);
376
+ this.worldRoot.rotation.x = Math.PI;
377
+ this.worldRoot.position.y -= bounds.min.y;
378
+ this.worldRoot.updateMatrixWorld(true);
379
+ if (this.options.colliderSource) {
380
+ await this.loadCollider(this.options.colliderSource);
381
+ }
409
382
  this.switchToOrbit();
410
383
  window.addEventListener("keydown", this.onKeyToggle);
411
384
  }
@@ -452,13 +425,13 @@ var PGSGThreeViewer = class {
452
425
  }
453
426
  initRenderer() {
454
427
  if (this.renderer) return;
455
- this.renderer = new THREE4.WebGLRenderer({
456
- antialias: this.options.renderer?.antialias ?? true,
428
+ this.renderer = new THREE3.WebGLRenderer({
429
+ antialias: this.options.renderer?.antialias ?? false,
457
430
  alpha: false,
458
431
  powerPreference: "high-performance"
459
432
  });
460
433
  this.renderer.setClearColor(1118481, 1);
461
- this.renderer.outputColorSpace = THREE4.SRGBColorSpace;
434
+ this.renderer.outputColorSpace = THREE3.SRGBColorSpace;
462
435
  this.renderer.setSize(
463
436
  this.container.clientWidth,
464
437
  this.container.clientHeight
@@ -469,49 +442,65 @@ var PGSGThreeViewer = class {
469
442
  this.container.appendChild(this.renderer.domElement);
470
443
  this.renderer.domElement.addEventListener("webglcontextlost", (e) => {
471
444
  e.preventDefault();
472
- console.error("[PGSG] WebGL context lost");
445
+ console.log("[PGSG Viewer] WebGL context lost");
473
446
  });
474
447
  }
475
448
  initScene() {
476
- this.scene = new THREE4.Scene();
477
- this.scene.background = new THREE4.Color(1118481);
478
- const ground = new THREE4.Mesh(
479
- new THREE4.PlaneGeometry(500, 500),
480
- new THREE4.MeshStandardMaterial({ color: 2236962 })
481
- );
482
- ground.rotation.x = -Math.PI / 2;
483
- ground.position.y = this.FLOOR_Y;
484
- ground.receiveShadow = true;
485
- ground.name = "ground";
486
- this.colliders.push(ground);
487
- const light = new THREE4.HemisphereLight(16777215, 2236962, 1);
449
+ this.scene = new THREE3.Scene();
450
+ this.scene.background = new THREE3.Color(1118481);
451
+ const gridHelper = new THREE3.GridHelper(10, 10);
452
+ const light = new THREE3.HemisphereLight(16777215, 2236962, 1);
488
453
  this.scene.add(light);
489
- const axes = new THREE4.AxesHelper(0.5);
490
454
  }
491
455
  initCamera() {
492
- this.camera = new THREE4.PerspectiveCamera(
493
- this.options.camera?.fov ?? 60,
456
+ this.camera = new THREE3.PerspectiveCamera(
457
+ 60,
494
458
  this.container.clientWidth / this.container.clientHeight,
495
- this.options.camera?.near ?? 0.01,
496
- this.options.camera?.far ?? 1e4
459
+ 0.01,
460
+ 1e4
497
461
  );
498
462
  this.camera.position.set(0, 1.6, 3);
499
- this.camera.lookAt(0, 1.6, 0);
463
+ this.camera.lookAt(0, 0, 0);
464
+ }
465
+ async loadCollider(url) {
466
+ const loader = new GLTFLoader();
467
+ const gltf = await loader.loadAsync(url);
468
+ this.colliderMesh = gltf.scene;
469
+ this.worldRoot.add(this.colliderMesh);
470
+ this.colliders.length = 0;
471
+ this.colliderMesh.traverse((child) => {
472
+ if (child.isMesh) {
473
+ child.material = new THREE3.MeshNormalMaterial();
474
+ child.updateMatrixWorld(true);
475
+ this.colliders.push(child);
476
+ }
477
+ });
478
+ this.worldRoot.updateMatrixWorld(true);
479
+ }
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);
500
491
  }
501
492
  fitCameraToBounds(bounds) {
502
493
  const center = bounds.min.clone().add(bounds.max).multiplyScalar(0.5);
503
494
  const size = bounds.max.clone().sub(bounds.min);
504
- const maxDim = Math.max(size.x, size.y, size.z);
505
- const fov = THREE4.MathUtils.degToRad(this.camera.fov);
506
- const aspect = this.camera.aspect;
507
- const fitHeightDistance = maxDim * 0.5 / Math.tan(fov * 0.5);
508
- const fitWidthDistance = fitHeightDistance / aspect;
509
- const distance = Math.max(fitHeightDistance, fitWidthDistance) * 1.2;
510
- const dir = new THREE4.Vector3(1, 0.6, 1).normalize();
511
- this.orbitTarget.copy(center);
512
- this.camera.position.copy(center).addScaledVector(dir, distance);
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
+ );
513
502
  this.camera.lookAt(center);
514
- this.camera.updateProjectionMatrix();
503
+ this.orbitTarget.copy(center);
515
504
  }
516
505
  onKeyToggle = (e) => {
517
506
  if (e.key !== "v") return;
@@ -523,8 +512,6 @@ var PGSGThreeViewer = class {
523
512
  };
524
513
  switchToWalk() {
525
514
  this.controls?.dispose();
526
- this.camera.position.y = this.FLOOR_Y + 1.6;
527
- this.snapPlayerToGround();
528
515
  this.controls = new WalkCapsuleController({
529
516
  camera: this.camera,
530
517
  dom: this.renderer.domElement,
@@ -548,43 +535,8 @@ var PGSGThreeViewer = class {
548
535
  }
549
536
  );
550
537
  }
551
- snapPlayerToGround() {
552
- const origin = this.camera.position.clone();
553
- origin.y = 50;
554
- const ray = new THREE4.Raycaster(
555
- origin,
556
- new THREE4.Vector3(0, -1, 0),
557
- 0,
558
- 100
559
- );
560
- const hits = ray.intersectObjects(this.colliders, true);
561
- if (!hits.length) return;
562
- const groundY = hits[0].point.y;
563
- this.camera.position.y = groundY + 1.6;
564
- }
565
- addBoxCollider(size, position, rotation) {
566
- const geo = new THREE4.BoxGeometry(size.x, size.y, size.z);
567
- const mat = new THREE4.MeshBasicMaterial({ visible: false });
568
- const box = new THREE4.Mesh(geo, mat);
569
- box.position.copy(position);
570
- if (rotation) box.rotation.copy(rotation);
571
- box.updateMatrixWorld(true);
572
- this.scene.add(box);
573
- this.colliders.push(box);
574
- return box;
575
- }
576
- applySplatPreset(i) {
577
- const p = this.splatPresets[i % this.splatPresets.length];
578
- this.splatPresetIndex = i % this.splatPresets.length;
579
- this.splatPivot.rotation.set(p.r[0], p.r[1], p.r[2]);
580
- this.splatPivot.scale.set(p.s[0], p.s[1], p.s[2]);
581
- this.splatPivot.updateMatrixWorld(true);
582
- console.log(
583
- `[SPLAT PRESET ${this.splatPresetIndex}] rot=(${p.r.map((x) => x.toFixed(3)).join(",")}) scale=(${p.s.join(",")})`
584
- );
585
- }
586
538
  };
587
539
  export {
588
540
  PGSGThreeViewer
589
541
  };
590
- //# sourceMappingURL=pgsg-three-viewer-ZU5OI33Q.js.map
542
+ //# sourceMappingURL=pgsg-three-viewer-2ONIARDQ.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\";\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"]}
@@ -6,7 +6,8 @@ type PGSGCanvasProps = {
6
6
  className?: string;
7
7
  onReady?: (viewer: PGSGViewer) => void;
8
8
  type?: "pgsg" | "ply";
9
+ colliderSrc?: string;
9
10
  };
10
- declare function PGSGCanvas({ src, type, className, onReady }: PGSGCanvasProps): react_jsx_runtime.JSX.Element;
11
+ declare function PGSGCanvas({ src, type, className, onReady, colliderSrc, }: PGSGCanvasProps): react_jsx_runtime.JSX.Element;
11
12
 
12
13
  export { PGSGCanvas, type PGSGCanvasProps };
@@ -1,11 +1,17 @@
1
1
  import {
2
2
  PGSGViewer
3
- } from "../chunk-TBA7YDMF.js";
3
+ } from "../chunk-UDJ24YL2.js";
4
4
 
5
5
  // src/react/PGSGCanvas.tsx
6
6
  import * as React from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
- function PGSGCanvas({ src, type = "pgsg", className, onReady }) {
8
+ function PGSGCanvas({
9
+ src,
10
+ type = "pgsg",
11
+ className,
12
+ onReady,
13
+ colliderSrc
14
+ }) {
9
15
  const ref = React.useRef(null);
10
16
  const viewRef = React.useRef(null);
11
17
  React.useEffect(() => {
@@ -14,6 +20,7 @@ function PGSGCanvas({ src, type = "pgsg", className, onReady }) {
14
20
  const viewer = new PGSGViewer({
15
21
  container: ref.current,
16
22
  source: { type, url: src },
23
+ colliderSource: colliderSrc,
17
24
  debug: true,
18
25
  viewerType: "three"
19
26
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/PGSGCanvas.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { PGSGViewer } from \"../viewer/pgsg-viewer\";\n\nexport type PGSGCanvasProps = {\n src: string;\n className?: string;\n onReady?: (viewer: PGSGViewer) => void;\n type?: \"pgsg\" | \"ply\";\n};\n\nexport function PGSGCanvas({ src, type = 'pgsg', className, onReady }: PGSGCanvasProps) {\n const ref = React.useRef<HTMLDivElement | null>(null);\n const viewRef = React.useRef<PGSGViewer | null>(null);\n\n React.useEffect(() => {\n if (!ref.current) return;\n\n if (viewRef.current) return;\n\n const viewer = new PGSGViewer({\n container: ref.current,\n source: { type: type, url: src },\n debug: true,\n viewerType: \"three\",\n });\n\n viewRef.current\n\n viewer.load()\n\n return () => {\n viewer.destroy();\n viewRef.current = null;\n };\n }, [src]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{ width: \"100%\", height: \"100%\" }}\n />\n );\n}\n"],"mappings":";;;;;AAEA,YAAY,WAAW;AAsCnB;AA3BG,SAAS,WAAW,EAAE,KAAK,OAAO,QAAQ,WAAW,QAAQ,GAAoB;AACtF,QAAM,MAAY,aAA8B,IAAI;AACpD,QAAM,UAAgB,aAA0B,IAAI;AAEpD,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,IAAI,QAAS;AAElB,QAAI,QAAQ,QAAS;AAErB,UAAM,SAAS,IAAI,WAAW;AAAA,MAC5B,WAAW,IAAI;AAAA,MACf,QAAQ,EAAE,MAAY,KAAK,IAAI;AAAA,MAC/B,OAAO;AAAA,MACP,YAAY;AAAA,IACd,CAAC;AAED,YAAQ;AAER,WAAO,KAAK;AAEZ,WAAO,MAAM;AACX,aAAO,QAAQ;AACf,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO;AAAA;AAAA,EACzC;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/react/PGSGCanvas.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { PGSGViewer } from \"../viewer/pgsg-viewer\";\n\nexport type PGSGCanvasProps = {\n src: string;\n className?: string;\n onReady?: (viewer: PGSGViewer) => void;\n type?: \"pgsg\" | \"ply\";\n colliderSrc?: string;\n};\n\nexport function PGSGCanvas({\n src,\n type = \"pgsg\",\n className,\n onReady,\n colliderSrc,\n}: PGSGCanvasProps) {\n const ref = React.useRef<HTMLDivElement | null>(null);\n const viewRef = React.useRef<PGSGViewer | null>(null);\n\n React.useEffect(() => {\n if (!ref.current) return;\n\n if (viewRef.current) return;\n\n const viewer = new PGSGViewer({\n container: ref.current,\n source: { type: type, url: src },\n colliderSource: colliderSrc,\n debug: true,\n viewerType: \"three\",\n });\n\n viewRef.current;\n\n viewer.load();\n\n return () => {\n viewer.destroy();\n viewRef.current = null;\n };\n }, [src]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{ width: \"100%\", height: \"100%\" }}\n />\n );\n}\n"],"mappings":";;;;;AAEA,YAAY,WAAW;AA8CnB;AAlCG,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AACF,GAAoB;AAClB,QAAM,MAAY,aAA8B,IAAI;AACpD,QAAM,UAAgB,aAA0B,IAAI;AAEpD,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,IAAI,QAAS;AAElB,QAAI,QAAQ,QAAS;AAErB,UAAM,SAAS,IAAI,WAAW;AAAA,MAC5B,WAAW,IAAI;AAAA,MACf,QAAQ,EAAE,MAAY,KAAK,IAAI;AAAA,MAC/B,gBAAgB;AAAA,MAChB,OAAO;AAAA,MACP,YAAY;AAAA,IACd,CAAC;AAED,YAAQ;AAER,WAAO,KAAK;AAEZ,WAAO,MAAM;AACX,aAAO,QAAQ;AACf,cAAQ,UAAU;AAAA,IACpB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO;AAAA;AAAA,EACzC;AAEJ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popaya/pgsg-viewer",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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 { 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(); // 🔑 CRITICAL\n private lastTime = performance.now();\n\n private colliders: THREE.Object3D[] = [];\n private groundY = 0;\n private readonly FLOOR_Y = -1.6;\n\n private splatPivot = new THREE.Object3D();\n private splatMesh?: THREE.Object3D;\n\n private splatPresets = [\n // P0: identity\n { r: [0, 0, 0], s: [1, 1, 1] },\n\n // P1: Z-up -> Y-up (common GS)\n { r: [-Math.PI / 2, 0, 0], s: [1, 1, 1] },\n\n // P2: Z-up -> Y-up + 90° roll (your screenshot strongly suggests this)\n { r: [-Math.PI / 2, 0, Math.PI / 2], s: [1, 1, 1] },\n\n // P3: Z-up -> Y-up + -90° roll\n { r: [-Math.PI / 2, 0, -Math.PI / 2], s: [1, 1, 1] },\n\n // P4: Z-up -> Y-up + flip forward\n { r: [-Math.PI / 2, Math.PI, 0], s: [1, 1, 1] },\n\n // P5: Z-up -> Y-up + 90° roll + flip forward\n { r: [-Math.PI / 2, Math.PI, Math.PI / 2], s: [1, 1, 1] },\n\n // P6: Z-up -> Y-up + handedness fix\n { r: [-Math.PI / 2, 0, 0], s: [1, 1, -1] },\n\n // P7: Z-up -> Y-up + 90° roll + handedness fix\n { r: [-Math.PI / 2, 0, Math.PI / 2], s: [1, 1, -1] },\n ] as const;\n\n private splatPresetIndex = 0;\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 /* ---------------- Spark Splats ---------------- */\n this.splats = new SparkSplatRenderer();\n const { mesh, bounds } = await this.splats.load(this.options.source);\n\n // mesh.rotation.set(0, Math.PI / 2, 0);\n this.splatPivot.clear();\n this.splatPivot.add(mesh);\n this.scene.add(this.splatPivot);\n\n // Snap splats to ground\n this.splatPivot.position.y -= bounds.min.y;\n // this.splatPivot.position.y += 0.01;\n this.splatPivot.updateMatrixWorld(true);\n this.groundY = 0;\n\n const ground = new THREE.Mesh(\n new THREE.PlaneGeometry(500, 500),\n new THREE.MeshBasicMaterial({ visible: false }),\n );\n ground.rotation.x = -Math.PI / 2;\n ground.position.y = this.FLOOR_Y;\n ground.updateMatrixWorld(true);\n\n this.scene.add(ground);\n this.colliders = [ground]; // important: reset, don’t stack\n\n // const movedBounds = {\n // min: bounds.min.clone().applyMatrix4(this.splatPivot.matrixWorld),\n // max: bounds.max.clone().applyMatrix4(this.splatPivot.matrixWorld),\n // };\n\n // // 🔑 THIS WAS MISSING\n // this.fitCameraToBounds(movedBounds);\n\n console.log(\"[PLY bounds]\", bounds.min, bounds.max);\n\n // this.addBoxCollider(\n // new THREE.Vector3(50, 0.1, 50),\n // new THREE.Vector3(0, 0, 0),\n // );\n this.addBoxCollider(\n new THREE.Vector3(0.2, 3, 10), // thickness, height, length\n new THREE.Vector3(2.5, 1.5, 0), // center\n );\n this.addBoxCollider(\n new THREE.Vector3(1.5, 0.8, 0.8),\n new THREE.Vector3(0, 0.4, -1),\n );\n\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 private initRenderer() {\n if (this.renderer) return; // 🔒 prevent double init\n\n this.renderer = new THREE.WebGLRenderer({\n antialias: this.options.renderer?.antialias ?? true,\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 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.error(\"[PGSG] 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 ground = new THREE.Mesh(\n new THREE.PlaneGeometry(500, 500),\n new THREE.MeshStandardMaterial({ color: 0x222222 }),\n );\n ground.rotation.x = -Math.PI / 2;\n ground.position.y = this.FLOOR_Y;\n ground.receiveShadow = true;\n ground.name = \"ground\";\n // this.scene.add(ground);\n\n this.colliders.push(ground);\n\n const light = new THREE.HemisphereLight(0xffffff, 0x222222, 1.0);\n this.scene.add(light);\n\n const axes = new THREE.AxesHelper(0.5);\n // this.scene.add(axes);\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 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 maxDim = Math.max(size.x, size.y, size.z);\n const fov = THREE.MathUtils.degToRad(this.camera.fov);\n const aspect = this.camera.aspect;\n\n // Fit by whichever constraint is tighter: vertical or horizontal FOV\n const fitHeightDistance = (maxDim * 0.5) / Math.tan(fov * 0.5);\n const fitWidthDistance = fitHeightDistance / aspect;\n const distance = Math.max(fitHeightDistance, fitWidthDistance) * 1.2;\n\n // Put camera in a stable diagonal direction (or use previous direction)\n const dir = new THREE.Vector3(1, 0.6, 1).normalize();\n\n this.orbitTarget.copy(center);\n this.camera.position.copy(center).addScaledVector(dir, distance);\n this.camera.lookAt(center);\n this.camera.updateProjectionMatrix();\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\n this.camera.position.y = this.FLOOR_Y + 1.6;\n // Start above scene so ray always hits\n // this.camera.position.set(\n // this.orbitTarget.x,\n // this.orbitTarget.y + 5,\n // this.orbitTarget.z,\n // );\n\n this.snapPlayerToGround();\n\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 private snapPlayerToGround() {\n const origin = this.camera.position.clone();\n origin.y = 50; // guaranteed above everything\n\n const ray = new THREE.Raycaster(\n origin,\n new THREE.Vector3(0, -1, 0),\n 0,\n 100,\n );\n\n const hits = ray.intersectObjects(this.colliders, true);\n if (!hits.length) return;\n\n const groundY = hits[0].point.y;\n this.camera.position.y = groundY + 1.6;\n }\n\n private addBoxCollider(\n size: THREE.Vector3,\n position: THREE.Vector3,\n rotation?: THREE.Euler,\n ) {\n const geo = new THREE.BoxGeometry(size.x, size.y, size.z);\n const mat = new THREE.MeshBasicMaterial({ visible: false });\n const box = new THREE.Mesh(geo, mat);\n\n box.position.copy(position);\n if (rotation) box.rotation.copy(rotation);\n\n box.updateMatrixWorld(true);\n this.scene.add(box);\n this.colliders.push(box);\n\n return box;\n }\n\n private applySplatPreset(i: number) {\n const p = this.splatPresets[i % this.splatPresets.length];\n this.splatPresetIndex = i % this.splatPresets.length;\n\n this.splatPivot.rotation.set(p.r[0], p.r[1], p.r[2]);\n this.splatPivot.scale.set(p.s[0], p.s[1], p.s[2]);\n this.splatPivot.updateMatrixWorld(true);\n\n console.log(\n `[SPLAT PRESET ${this.splatPresetIndex}] rot=(${p.r\n .map((x) => x.toFixed(3))\n .join(\",\")}) scale=(${p.s.join(\",\")})`,\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 // Match SparkJS doc defaults\n this.mesh.quaternion.set(1, 0, 0, 0);\n this.mesh.position.set(0, 0, 0);\n\n return {\n mesh: this.mesh,\n bounds: {\n min: new THREE.Vector3(0, 0, 0),\n max: new THREE.Vector3(0, 0, 0),\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\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 if (!this.onGround) {\n this.velocity.y -= this.gravity * dt;\n } else {\n this.velocity.y = 0; //Math.min(this.velocity.y, 0);\n }\n\n const nextPos = this.camera.position.clone();\n nextPos.addScaledVector(this.velocity, 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 -----\n const footY = camPos.y - this.eyeHeight;\n const origin = new THREE.Vector3(camPos.x, footY + 0.5, camPos.z);\n\n this.raycaster.set(origin, new THREE.Vector3(0, -1, 0));\n this.raycaster.far = 2.0;\n\n const hits = this.raycaster.intersectObjects(this.colliders, true);\n\n if (hits.length) {\n const groundY = hits[0].point.y; //+ this.radius;\n const targetY = groundY + this.eyeHeight;\n const epsilon = 0.02;\n\n if (camPos.y <= targetY + epsilon) {\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":";AACA,YAAYA,YAAW;;;ACDvB,SAAS,iBAAiB;AAC1B,YAAY,WAAW;AAIhB,IAAM,qBAAN,MAAyB;AAAA,EACtB;AAAA,EAER,MAAM,KAAK,QAAsB;AAC/B,QAAI,OAAO,SAAS,SAAS,OAAO,SAAS,QAAQ;AACnD,YAAM,IAAI,MAAM,2CAA2C;AAAA,IAC7D;AAQA,SAAK,OAAO,IAAI,UAAU;AAAA,MACxB,KAAK,OAAO;AAAA,IACd,CAAC;AAGD,SAAK,KAAK,WAAW,IAAI,GAAG,GAAG,GAAG,CAAC;AACnC,SAAK,KAAK,SAAS,IAAI,GAAG,GAAG,CAAC;AAE9B,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,QAAQ;AAAA,QACN,KAAK,IAAU,cAAQ,GAAG,GAAG,CAAC;AAAA,QAC9B,KAAK,IAAU,cAAQ,GAAG,GAAG,CAAC;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,WAAW,OAAoB;AAC7B,UAAM,IAAI,KAAK,IAAI;AAAA,EACrB;AAAA,EAEA,OAAO,IAAY;AAAA,EAEnB;AAAA,EAEA,QAAQ,OAAoB;AAC1B,UAAM,OAAO,KAAK,IAAI;AACtB,SAAK,KAAK,UAAU;AAAA,EACtB;AACF;;;AChDA,YAAYC,YAAW;AAehB,IAAM,wBAAN,MAA4B;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,MAAM;AAAA,EACN,QAAQ;AAAA,EAER,WAAW,IAAU,eAAQ;AAAA,EAC7B,WAAW;AAAA,EAEX,OAAO,oBAAI,IAAY;AAAA,EACvB,YAAY,IAAU,iBAAU;AAAA,EAExC,YAAY,MAA0B;AACpC,SAAK,MAAM,KAAK;AAChB,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,KAAK;AAEtB,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,UAAU,KAAK,WAAW;AAC/B,SAAK,YAAY,KAAK,aAAa;AACnC,SAAK,gBAAgB,KAAK,iBAAiB;AAC3C,SAAK,kBAAkB,KAAK,mBAAmB;AAG/C,UAAM,QAAQ,IAAU,aAAM,EAAE;AAAA,MAC9B,KAAK,OAAO;AAAA,MACZ;AAAA,IACF;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,MAAM,MAAM;AAEjB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,UAAU;AACR,SAAK,OAAO;AACZ,aAAS,gBAAgB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAMQ,OAAO;AAEb,SAAK,IAAI,iBAAiB,SAAS,KAAK,OAAO;AAE/C,WAAO,iBAAiB,aAAa,KAAK,WAAW;AACrD,WAAO,iBAAiB,WAAW,KAAK,SAAS;AACjD,WAAO,iBAAiB,SAAS,KAAK,OAAO;AAC7C,WAAO,iBAAiB,QAAQ,KAAK,MAAM;AAE3C,SAAK,IAAI,iBAAiB,eAAe,CAAC,MAAM,EAAE,eAAe,CAAC;AAAA,EACpE;AAAA,EAEQ,SAAS;AACf,SAAK,IAAI,oBAAoB,SAAS,KAAK,OAAO;AAClD,WAAO,oBAAoB,aAAa,KAAK,WAAW;AACxD,WAAO,oBAAoB,WAAW,KAAK,SAAS;AACpD,WAAO,oBAAoB,SAAS,KAAK,OAAO;AAChD,WAAO,oBAAoB,QAAQ,KAAK,MAAM;AAAA,EAChD;AAAA,EAEQ,UAAU,MAAM;AACtB,QAAI,SAAS,uBAAuB,KAAK,KAAK;AAC5C,WAAK,IAAI,mBAAmB;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,SAAS,MAAM;AACrB,aAAS,gBAAgB;AACzB,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEQ,cAAc,CAAC,MAAkB;AACvC,QAAI,SAAS,uBAAuB,KAAK,IAAK;AAE9C,SAAK,OAAO,EAAE,YAAY,KAAK;AAC/B,SAAK,SAAS,EAAE,YAAY,KAAK;AAEjC,SAAK,QAAc,iBAAU;AAAA,MAC3B,KAAK;AAAA,MACL,CAAC,KAAK,KAAK,IAAI;AAAA,MACf,KAAK,KAAK,IAAI;AAAA,IAChB;AAEA,SAAK,OAAO,WAAW;AAAA,MACrB,IAAU,aAAM,KAAK,OAAO,KAAK,KAAK,GAAG,KAAK;AAAA,IAChD;AAAA,EACF;AAAA,EAEQ,YAAY,CAAC,MAAqB;AACxC,SAAK,KAAK,IAAI,EAAE,IAAI,YAAY,CAAC;AAAA,EACnC;AAAA,EAEQ,UAAU,CAAC,MAAqB;AACtC,SAAK,KAAK,OAAO,EAAE,IAAI,YAAY,CAAC;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,IAAY;AACjB,QAAI,CAAC,OAAO,SAAS,KAAK,OAAO,SAAS,CAAC,EAAG;AAE9C,SAAK,KAAK,IAAI,IAAI,IAAI;AAGtB,UAAM,UAAU,IAAU,eAAQ;AAClC,SAAK,OAAO,kBAAkB,OAAO;AACrC,YAAQ,IAAI;AACZ,YAAQ,UAAU;AAElB,UAAM,QAAQ,IAAU,eAAQ,EAC7B,aAAa,SAAS,IAAU,eAAQ,GAAG,GAAG,CAAC,CAAC,EAChD,UAAU;AAEb,UAAM,OAAO,IAAU,eAAQ;AAC/B,QAAI,KAAK,KAAK,IAAI,GAAG,EAAG,MAAK,IAAI,OAAO;AACxC,QAAI,KAAK,KAAK,IAAI,GAAG,EAAG,MAAK,IAAI,OAAO;AACxC,QAAI,KAAK,KAAK,IAAI,GAAG,EAAG,MAAK,IAAI,KAAK;AACtC,QAAI,KAAK,KAAK,IAAI,GAAG,EAAG,MAAK,IAAI,KAAK;AAEtC,QAAI,KAAK,SAAS,IAAI,EAAG,MAAK,UAAU;AAExC,QAAI,KAAK,KAAK,OAAO,GAAG;AACtB,cAAQ,IAAI,WAAW,CAAC,GAAG,KAAK,IAAI,CAAC;AAAA,IACvC;AAEA,UAAM,QACJ,KAAK,aAAa,KAAK,KAAK,IAAI,OAAO,IAAI,KAAK,gBAAgB;AAElE,SAAK,SAAS,IAAI,KAAK,IAAI;AAC3B,SAAK,SAAS,IAAI,KAAK,IAAI;AAE3B,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK,SAAS,KAAK,KAAK,UAAU;AAAA,IACpC,OAAO;AACL,WAAK,SAAS,IAAI;AAAA,IACpB;AAEA,UAAM,UAAU,KAAK,OAAO,SAAS,MAAM;AAC3C,YAAQ,gBAAgB,KAAK,UAAU,EAAE;AAEzC,UAAM,WAAW,KAAK,2BAA2B,OAAO;AACxD,SAAK,OAAO,SAAS,KAAK,QAAQ;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA,EAMQ,2BAA2B,eAA8B;AAC/D,UAAM,SAAS,cAAc,MAAM;AAGnC,UAAM,QAAQ,OAAO,IAAI,KAAK;AAC9B,UAAM,SAAS,IAAU,eAAQ,OAAO,GAAG,QAAQ,KAAK,OAAO,CAAC;AAEhE,SAAK,UAAU,IAAI,QAAQ,IAAU,eAAQ,GAAG,IAAI,CAAC,CAAC;AACtD,SAAK,UAAU,MAAM;AAErB,UAAM,OAAO,KAAK,UAAU,iBAAiB,KAAK,WAAW,IAAI;AAEjE,QAAI,KAAK,QAAQ;AACf,YAAM,UAAU,KAAK,CAAC,EAAE,MAAM;AAC9B,YAAM,UAAU,UAAU,KAAK;AAC/B,YAAM,UAAU;AAEhB,UAAI,OAAO,KAAK,UAAU,SAAS;AACjC,eAAO,IAAI;AACX,aAAK,SAAS,IAAI;AAClB,aAAK,WAAW;AAAA,MAClB,OAAO;AACL,aAAK,WAAW;AAAA,MAClB;AAAA,IACF,OAAO;AACL,WAAK,WAAW;AAAA,IAClB;AAGA,UAAM,SAAS,OAAO,MAAM;AAC5B,WAAO,KAAK,KAAK,YAAY;AAE7B,UAAM,OAAO;AAAA,MACX,IAAU,eAAQ,GAAG,GAAG,CAAC;AAAA,MACzB,IAAU,eAAQ,IAAI,GAAG,CAAC;AAAA,MAC1B,IAAU,eAAQ,GAAG,GAAG,CAAC;AAAA,MACzB,IAAU,eAAQ,GAAG,GAAG,EAAE;AAAA,IAC5B;AAEA,eAAW,KAAK,MAAM;AACpB,WAAK,UAAU,IAAI,QAAQ,CAAC;AAC5B,WAAK,UAAU,MAAM,KAAK,SAAS;AAEnC,YAAM,WAAW,KAAK,UAAU,iBAAiB,KAAK,WAAW,IAAI;AACrE,UAAI,CAAC,SAAS,OAAQ;AAEtB,YAAM,UAAU,KAAK,SAAS,OAAO,SAAS,CAAC,EAAE;AACjD,UAAI,UAAU,EAAG,QAAO,gBAAgB,GAAG,CAAC,OAAO;AAAA,IACrD;AAEA,YAAQ,IAAI;AAAA,MACV,MAAM,OAAO,EAAE,QAAQ,CAAC;AAAA,MACxB,OAAO,MAAM,QAAQ,CAAC;AAAA,MACtB,WAAW,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,CAAC;AAAA,MACrC,UAAU,KAAK;AAAA,IACjB,CAAC;AAED,WAAO;AAAA,EACT;AACF;;;AC9OA,YAAYC,YAAW;AAWhB,IAAM,wBAAN,MAA4B;AAAA,EACzB;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,MAAM;AAAA,EACN,QAAQ;AAAA,EAER;AAAA,EACA;AAAA,EAEA,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EAER,UAAU;AAAA,EACV,WAAW;AAAA,EAEnB,YACE,QACA,KACA,MACA;AACA,SAAK,SAAS;AACd,SAAK,MAAM;AAEX,SAAK,SAAS,KAAK,OAAO,MAAM;AAChC,SAAK,WAAW,KAAK;AACrB,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,cAAc,KAAK,eAAe;AAEvC,SAAK,cAAc,KAAK,eAAe;AACvC,SAAK,YAAY,KAAK,aAAa;AAEnC,SAAK,eAAe;AACpB,SAAK,KAAK;AACV,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,UAAU;AACR,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAMQ,OAAO;AACb,SAAK,IAAI,iBAAiB,eAAe,CAAC,MAAM,EAAE,eAAe,CAAC;AAClE,SAAK,IAAI,iBAAiB,aAAa,KAAK,WAAW;AACvD,WAAO,iBAAiB,WAAW,KAAK,SAAS;AACjD,WAAO,iBAAiB,aAAa,KAAK,WAAW;AACrD,SAAK,IAAI,iBAAiB,SAAS,KAAK,SAAS,EAAE,SAAS,MAAM,CAAC;AAAA,EACrE;AAAA,EAEQ,SAAS;AACf,SAAK,IAAI,oBAAoB,aAAa,KAAK,WAAW;AAC1D,WAAO,oBAAoB,WAAW,KAAK,SAAS;AACpD,WAAO,oBAAoB,aAAa,KAAK,WAAW;AACxD,SAAK,IAAI,oBAAoB,SAAS,KAAK,OAAO;AAAA,EACpD;AAAA,EAEQ,iBAAiB;AACvB,UAAM,SAAS,KAAK,OAAO,SAAS,MAAM,EAAE,IAAI,KAAK,MAAM;AAC3D,SAAK,WAAW,OAAO,OAAO;AAE9B,UAAM,YAAY,IAAU,iBAAU,EAAE,eAAe,MAAM;AAC7D,SAAK,MAAM,UAAU;AACrB,SAAK,QAAQ,UAAU;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAc,CAAC,MAAkB;AACvC,QAAI,EAAE,WAAW,GAAG;AAElB,WAAK,WAAW;AAAA,IAClB,WAAW,EAAE,WAAW,KAAK,EAAE,WAAW,GAAG;AAE3C,WAAK,UAAU;AAAA,IACjB;AAEA,SAAK,QAAQ,EAAE;AACf,SAAK,QAAQ,EAAE;AAAA,EACjB;AAAA,EAEQ,YAAY,MAAM;AACxB,SAAK,WAAW;AAChB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEQ,cAAc,CAAC,MAAkB;AACvC,QAAI,CAAC,KAAK,YAAY,CAAC,KAAK,QAAS;AAErC,UAAM,KAAK,EAAE,UAAU,KAAK;AAC5B,UAAM,KAAK,EAAE,UAAU,KAAK;AAE5B,SAAK,QAAQ,EAAE;AACf,SAAK,QAAQ,EAAE;AAKf,QAAI,KAAK,UAAU;AACjB,WAAK,OAAO,KAAK,KAAK;AACtB,WAAK,SAAS,KAAK,KAAK;AAExB,WAAK,QAAc,iBAAU,MAAM,KAAK,OAAO,MAAM,KAAK,KAAK,IAAI;AAEnE,WAAK,aAAa;AAClB;AAAA,IACF;AAKA,QAAI,KAAK,SAAS;AAChB,YAAM,WAAW,KAAK,WAAW,KAAK;AAEtC,YAAM,QAAQ,IAAU,eAAQ;AAChC,YAAM,KAAK,IAAU,eAAQ;AAE7B,WAAK,OAAO,kBAAkB,EAAE;AAChC,YAAM,aAAa,KAAK,OAAO,IAAI,EAAE,EAAE,UAAU;AACjD,SAAG;AAAA,QACD;AAAA,QACA,KAAK,OAAO,kBAAkB,IAAU,eAAQ,CAAC;AAAA,MACnD,EAAE,UAAU;AAEZ,YAAM,YAAY,IAAU,eAAQ,EACjC,gBAAgB,OAAO,KAAK,QAAQ,EACpC,gBAAgB,IAAI,CAAC,KAAK,QAAQ;AAErC,WAAK,OAAO,IAAI,SAAS;AACzB,WAAK,OAAO,SAAS,IAAI,SAAS;AAAA,IAGpC;AAAA,EACF;AAAA,EAEQ,UAAU,CAAC,MAAkB;AACnC,MAAE,eAAe;AAEjB,UAAM,aAAa,KAAK,IAAI,KAAK,WAAW,EAAE,SAAS,GAAG;AAC1D,SAAK,YAAY;AAEjB,SAAK,WAAiB,iBAAU;AAAA,MAC9B,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAEA,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe;AACrB,UAAM,YAAY,IAAU,iBAAU,KAAK,UAAU,KAAK,OAAO,KAAK,GAAG;AAEzE,UAAM,MAAM,IAAU,eAAQ,EAC3B,iBAAiB,SAAS,EAC1B,IAAI,KAAK,MAAM;AAElB,SAAK,OAAO,SAAS,KAAK,GAAG;AAC7B,SAAK,OAAO,OAAO,KAAK,MAAM;AAAA,EAChC;AAAA,EAEA,UAAU,GAAkB;AAC1B,SAAK,OAAO,KAAK,CAAC;AAClB,SAAK,aAAa;AAAA,EACpB;AACF;;;AHzLO,IAAM,kBAAN,MAAsB;AAAA,EAiD3B,YAAoB,SAA4B;AAA5B;AAClB,SAAK,YAAY,QAAQ;AACzB,SAAK,UAAU;AACf,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,IAAI,MAAM,yCAAyC;AAAA,IAC3D;AAAA,EACF;AAAA,EAtDQ,QAAQ,IAAU,aAAM;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA,UAAU;AAAA,EAEV,cAAc,IAAU,eAAQ;AAAA;AAAA,EAChC,WAAW,YAAY,IAAI;AAAA,EAE3B,YAA8B,CAAC;AAAA,EAC/B,UAAU;AAAA,EACD,UAAU;AAAA,EAEnB,aAAa,IAAU,gBAAS;AAAA,EAChC;AAAA,EAEA,eAAe;AAAA;AAAA,IAErB,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAG7B,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAGxC,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAGlD,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,GAAG,CAAC,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAGnD,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAG9C,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,EAAE;AAAA;AAAA,IAGxD,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,EAAE;AAAA;AAAA,IAGzC,EAAE,GAAG,CAAC,CAAC,KAAK,KAAK,GAAG,GAAG,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,EAAE;AAAA,EACrD;AAAA,EAEQ,mBAAmB;AAAA,EAU3B,MAAM,OAAO;AACX,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,UAAU;AAGf,SAAK,SAAS,IAAI,mBAAmB;AACrC,UAAM,EAAE,MAAM,OAAO,IAAI,MAAM,KAAK,OAAO,KAAK,KAAK,QAAQ,MAAM;AAGnE,SAAK,WAAW,MAAM;AACtB,SAAK,WAAW,IAAI,IAAI;AACxB,SAAK,MAAM,IAAI,KAAK,UAAU;AAG9B,SAAK,WAAW,SAAS,KAAK,OAAO,IAAI;AAEzC,SAAK,WAAW,kBAAkB,IAAI;AACtC,SAAK,UAAU;AAEf,UAAM,SAAS,IAAU;AAAA,MACvB,IAAU,qBAAc,KAAK,GAAG;AAAA,MAChC,IAAU,yBAAkB,EAAE,SAAS,MAAM,CAAC;AAAA,IAChD;AACA,WAAO,SAAS,IAAI,CAAC,KAAK,KAAK;AAC/B,WAAO,SAAS,IAAI,KAAK;AACzB,WAAO,kBAAkB,IAAI;AAE7B,SAAK,MAAM,IAAI,MAAM;AACrB,SAAK,YAAY,CAAC,MAAM;AAUxB,YAAQ,IAAI,gBAAgB,OAAO,KAAK,OAAO,GAAG;AAMlD,SAAK;AAAA,MACH,IAAU,eAAQ,KAAK,GAAG,EAAE;AAAA;AAAA,MAC5B,IAAU,eAAQ,KAAK,KAAK,CAAC;AAAA;AAAA,IAC/B;AACA,SAAK;AAAA,MACH,IAAU,eAAQ,KAAK,KAAK,GAAG;AAAA,MAC/B,IAAU,eAAQ,GAAG,KAAK,EAAE;AAAA,IAC9B;AAEA,SAAK,cAAc;AAEnB,WAAO,iBAAiB,WAAW,KAAK,WAAW;AAAA,EACrD;AAAA,EAEA,QAAQ;AACN,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AACf,SAAK,SAAS,iBAAiB,CAAC,SAAS;AACvC,YAAM,MAAM,YAAY,IAAI;AAC5B,YAAM,SAAS,MAAM,KAAK,YAAY;AACtC,WAAK,WAAW;AAEhB,MAAC,KAAK,UAAkB,SAAS,KAAK;AAEtC,WAAK,SAAS,OAAO,KAAK,OAAO,KAAK,MAAM;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ;AACN,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,SAAS;AACP,QAAI,CAAC,KAAK,YAAY,CAAC,KAAK,OAAQ;AAEpC,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,UAAU,WAAW;AAChD,UAAM,IAAI,KAAK,IAAI,GAAG,KAAK,UAAU,YAAY;AAEjD,SAAK,SAAS,QAAQ,GAAG,CAAC;AAC1B,SAAK,OAAO,SAAS,IAAI;AACzB,SAAK,OAAO,uBAAuB;AAAA,EACrC;AAAA,EAEA,UAAU;AACR,SAAK,UAAU;AACf,SAAK,SAAS,iBAAiB,IAAI;AACnC,SAAK,UAAU,QAAQ;AACvB,SAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAEA,cAAc,MAAwB;AACpC,QAAI,SAAS,SAAS;AACpB,eAAS,gBAAgB;AAAA,IAC3B;AAEA,QAAI,SAAS,QAAQ;AAEnB,iBAAW,MAAM;AACf,YAAI,SAAS,uBAAuB,KAAK,SAAS,YAAY;AAC5D,eAAK,SAAS,WAAW,MAAM;AAC/B,eAAK,SAAS,WAAW,mBAAmB;AAAA,QAC9C;AAAA,MACF,GAAG,CAAC;AAAA,IACN;AAAA,EACF;AAAA,EAEQ,eAAe;AACrB,QAAI,KAAK,SAAU;AAEnB,SAAK,WAAW,IAAU,qBAAc;AAAA,MACtC,WAAW,KAAK,QAAQ,UAAU,aAAa;AAAA,MAC/C,OAAO;AAAA,MACP,iBAAiB;AAAA,IACnB,CAAC;AAED,SAAK,SAAS,cAAc,SAAU,CAAC;AACvC,SAAK,SAAS,mBAAyB;AAEvC,SAAK,SAAS;AAAA,MACZ,KAAK,UAAU;AAAA,MACf,KAAK,UAAU;AAAA,IACjB;AACA,SAAK,SAAS;AAAA,MACZ,KAAK,QAAQ,UAAU,cAAc,OAAO;AAAA,IAC9C;AAEA,SAAK,UAAU,YAAY,KAAK,SAAS,UAAU;AAEnD,SAAK,SAAS,WAAW,iBAAiB,oBAAoB,CAAC,MAAM;AACnE,QAAE,eAAe;AACjB,cAAQ,MAAM,2BAA2B;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA,EAEQ,YAAY;AAClB,SAAK,QAAQ,IAAU,aAAM;AAC7B,SAAK,MAAM,aAAa,IAAU,aAAM,OAAQ;AAEhD,UAAM,SAAS,IAAU;AAAA,MACvB,IAAU,qBAAc,KAAK,GAAG;AAAA,MAChC,IAAU,4BAAqB,EAAE,OAAO,QAAS,CAAC;AAAA,IACpD;AACA,WAAO,SAAS,IAAI,CAAC,KAAK,KAAK;AAC/B,WAAO,SAAS,IAAI,KAAK;AACzB,WAAO,gBAAgB;AACvB,WAAO,OAAO;AAGd,SAAK,UAAU,KAAK,MAAM;AAE1B,UAAM,QAAQ,IAAU,uBAAgB,UAAU,SAAU,CAAG;AAC/D,SAAK,MAAM,IAAI,KAAK;AAEpB,UAAM,OAAO,IAAU,kBAAW,GAAG;AAAA,EAEvC;AAAA,EAEQ,aAAa;AACnB,SAAK,SAAS,IAAU;AAAA,MACtB,KAAK,QAAQ,QAAQ,OAAO;AAAA,MAC5B,KAAK,UAAU,cAAc,KAAK,UAAU;AAAA,MAC5C,KAAK,QAAQ,QAAQ,QAAQ;AAAA,MAC7B,KAAK,QAAQ,QAAQ,OAAO;AAAA,IAC9B;AAEA,SAAK,OAAO,SAAS,IAAI,GAAG,KAAK,CAAC;AAClC,SAAK,OAAO,OAAO,GAAG,KAAK,CAAC;AAAA,EAC9B;AAAA,EAEQ,kBAAkB,QAGvB;AACD,UAAM,SAAS,OAAO,IAAI,MAAM,EAAE,IAAI,OAAO,GAAG,EAAE,eAAe,GAAG;AACpE,UAAM,OAAO,OAAO,IAAI,MAAM,EAAE,IAAI,OAAO,GAAG;AAE9C,UAAM,SAAS,KAAK,IAAI,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAC9C,UAAM,MAAY,iBAAU,SAAS,KAAK,OAAO,GAAG;AACpD,UAAM,SAAS,KAAK,OAAO;AAG3B,UAAM,oBAAqB,SAAS,MAAO,KAAK,IAAI,MAAM,GAAG;AAC7D,UAAM,mBAAmB,oBAAoB;AAC7C,UAAM,WAAW,KAAK,IAAI,mBAAmB,gBAAgB,IAAI;AAGjE,UAAM,MAAM,IAAU,eAAQ,GAAG,KAAK,CAAC,EAAE,UAAU;AAEnD,SAAK,YAAY,KAAK,MAAM;AAC5B,SAAK,OAAO,SAAS,KAAK,MAAM,EAAE,gBAAgB,KAAK,QAAQ;AAC/D,SAAK,OAAO,OAAO,MAAM;AACzB,SAAK,OAAO,uBAAuB;AAAA,EACrC;AAAA,EAEQ,cAAc,CAAC,MAAqB;AAC1C,QAAI,EAAE,QAAQ,IAAK;AAEnB,QAAI,KAAK,oBAAoB,uBAAuB;AAClD,WAAK,cAAc;AAAA,IACrB,OAAO;AACL,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEQ,eAAe;AACrB,SAAK,UAAU,QAAQ;AAEvB,SAAK,OAAO,SAAS,IAAI,KAAK,UAAU;AAQxC,SAAK,mBAAmB;AAExB,SAAK,WAAW,IAAI,sBAAsB;AAAA,MACxC,QAAQ,KAAK;AAAA,MACb,KAAK,KAAK,SAAS;AAAA,MACnB,WAAW,KAAK;AAAA,MAChB,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,eAAe;AAAA,MACf,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB;AACtB,SAAK,UAAU,QAAQ;AAEvB,UAAM,WAAW,KAAK,OAAO,SAAS,WAAW,KAAK,WAAW;AAEjE,SAAK,WAAW,IAAI;AAAA,MAClB,KAAK;AAAA,MACL,KAAK,SAAS;AAAA,MACd;AAAA,QACE,QAAQ,KAAK,YAAY,MAAM;AAAA,QAC/B,UAAU,KAAK,IAAI,UAAU,GAAG;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBAAqB;AAC3B,UAAM,SAAS,KAAK,OAAO,SAAS,MAAM;AAC1C,WAAO,IAAI;AAEX,UAAM,MAAM,IAAU;AAAA,MACpB;AAAA,MACA,IAAU,eAAQ,GAAG,IAAI,CAAC;AAAA,MAC1B;AAAA,MACA;AAAA,IACF;AAEA,UAAM,OAAO,IAAI,iBAAiB,KAAK,WAAW,IAAI;AACtD,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,UAAU,KAAK,CAAC,EAAE,MAAM;AAC9B,SAAK,OAAO,SAAS,IAAI,UAAU;AAAA,EACrC;AAAA,EAEQ,eACN,MACA,UACA,UACA;AACA,UAAM,MAAM,IAAU,mBAAY,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AACxD,UAAM,MAAM,IAAU,yBAAkB,EAAE,SAAS,MAAM,CAAC;AAC1D,UAAM,MAAM,IAAU,YAAK,KAAK,GAAG;AAEnC,QAAI,SAAS,KAAK,QAAQ;AAC1B,QAAI,SAAU,KAAI,SAAS,KAAK,QAAQ;AAExC,QAAI,kBAAkB,IAAI;AAC1B,SAAK,MAAM,IAAI,GAAG;AAClB,SAAK,UAAU,KAAK,GAAG;AAEvB,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAiB,GAAW;AAClC,UAAM,IAAI,KAAK,aAAa,IAAI,KAAK,aAAa,MAAM;AACxD,SAAK,mBAAmB,IAAI,KAAK,aAAa;AAE9C,SAAK,WAAW,SAAS,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACnD,SAAK,WAAW,MAAM,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAChD,SAAK,WAAW,kBAAkB,IAAI;AAEtC,YAAQ;AAAA,MACN,iBAAiB,KAAK,gBAAgB,UAAU,EAAE,EAC/C,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EACvB,KAAK,GAAG,CAAC,YAAY,EAAE,EAAE,KAAK,GAAG,CAAC;AAAA,IACvC;AAAA,EACF;AACF;","names":["THREE","THREE","THREE"]}