@mml-io/3d-web-client-core 0.16.0 → 0.18.0

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.
package/build/index.js CHANGED
@@ -235,6 +235,132 @@ var VirtualJoystick = class _VirtualJoystick {
235
235
  }
236
236
  };
237
237
 
238
+ // src/tweakpane/blades/cameraFolder.ts
239
+ var camValues = {
240
+ initialDistance: 3.3,
241
+ minDistance: 0.1,
242
+ maxDistance: 5,
243
+ initialFOV: 60,
244
+ maxFOV: 70,
245
+ minFOV: 60,
246
+ invertFOVMapping: false,
247
+ damping: 0.15,
248
+ dampingScale: 5e-3,
249
+ zoomScale: 0.088,
250
+ zoomDamping: 0.16
251
+ };
252
+ var camOptions = {
253
+ initialDistance: { min: 1, max: 5, step: 0.1 },
254
+ minDistance: { min: 0.1, max: 2, step: 0.1 },
255
+ maxDistance: { min: 5, max: 20, step: 0.5 },
256
+ initialFOV: { min: 60, max: 85, step: 1 },
257
+ maxFOV: { min: 50, max: 100, step: 1 },
258
+ minFOV: { min: 50, max: 100, step: 1 },
259
+ damping: { min: 0.01, max: 0.15, step: 0.01 },
260
+ dampingScale: { min: 1e-3, max: 0.02, step: 1e-3 },
261
+ zoomScale: { min: 5e-3, max: 0.3, step: 1e-3 },
262
+ zoomDamping: { min: 0, max: 2, step: 0.01 }
263
+ };
264
+ var CameraFolder = class {
265
+ constructor(parentFolder, expand = false) {
266
+ this.camData = {
267
+ distance: "0",
268
+ FoV: "0"
269
+ };
270
+ this.folder = parentFolder.addFolder({ title: "camera", expanded: expand });
271
+ this.folder.addBinding(this.camData, "distance", { readonly: true });
272
+ this.folder.addBinding(this.camData, "FoV", { readonly: true });
273
+ this.folder.addBinding(camValues, "initialDistance", camOptions.initialDistance);
274
+ this.folder.addBinding(camValues, "minDistance", camOptions.minDistance);
275
+ this.folder.addBinding(camValues, "maxDistance", camOptions.maxDistance);
276
+ this.folder.addBinding(camValues, "minFOV", camOptions.minFOV);
277
+ this.folder.addBinding(camValues, "maxFOV", camOptions.maxFOV);
278
+ this.folder.addBinding({ invertFOVMapping: camValues.invertFOVMapping }, "invertFOVMapping");
279
+ this.folder.addBinding(camValues, "damping", camOptions.damping);
280
+ this.folder.addBinding(camValues, "dampingScale", camOptions.dampingScale);
281
+ this.folder.addBinding(camValues, "zoomScale", camOptions.zoomScale);
282
+ this.folder.addBinding(camValues, "zoomDamping", camOptions.zoomDamping);
283
+ }
284
+ setupChangeEvent(cameraManager) {
285
+ this.folder.on("change", (e) => {
286
+ const target = e.target.key;
287
+ if (!target)
288
+ return;
289
+ switch (target) {
290
+ case "initialDistance": {
291
+ const value = e.value;
292
+ cameraManager.initialDistance = value;
293
+ cameraManager.distance = value;
294
+ cameraManager.targetDistance = value;
295
+ cameraManager.desiredDistance = value;
296
+ cameraManager.recomputeFoV();
297
+ break;
298
+ }
299
+ case "minDistance": {
300
+ const value = e.value;
301
+ cameraManager.minDistance = value;
302
+ cameraManager.distance = value;
303
+ cameraManager.targetDistance = value;
304
+ cameraManager.desiredDistance = value;
305
+ cameraManager.recomputeFoV();
306
+ break;
307
+ }
308
+ case "maxDistance": {
309
+ const value = e.value;
310
+ cameraManager.maxDistance = value;
311
+ cameraManager.distance = value;
312
+ cameraManager.targetDistance = value;
313
+ cameraManager.desiredDistance = value;
314
+ cameraManager.recomputeFoV();
315
+ break;
316
+ }
317
+ case "minFOV": {
318
+ const value = e.value;
319
+ cameraManager.minFOV = value;
320
+ cameraManager.recomputeFoV();
321
+ break;
322
+ }
323
+ case "maxFOV": {
324
+ const value = e.value;
325
+ cameraManager.maxFOV = value;
326
+ cameraManager.recomputeFoV();
327
+ break;
328
+ }
329
+ case "invertFOVMapping":
330
+ const boolValue = e.value;
331
+ cameraManager.invertFOVMapping = boolValue;
332
+ break;
333
+ case "damping": {
334
+ const value = e.value;
335
+ cameraManager.damping = value;
336
+ break;
337
+ }
338
+ case "dampingScale": {
339
+ const value = e.value;
340
+ cameraManager.dampingScale = value;
341
+ break;
342
+ }
343
+ case "zoomScale": {
344
+ const value = e.value;
345
+ cameraManager.zoomScale = value;
346
+ break;
347
+ }
348
+ case "zoomDamping": {
349
+ const value = e.value;
350
+ cameraManager.zoomDamping = value;
351
+ break;
352
+ }
353
+ default:
354
+ break;
355
+ }
356
+ });
357
+ }
358
+ update(cameraManager) {
359
+ this.camData.distance = cameraManager.distance.toFixed(2);
360
+ this.camData.FoV = cameraManager.fov.toFixed(2);
361
+ }
362
+ };
363
+
238
364
  // src/tweakpane/tweakPaneActivity.ts
239
365
  var isTweakpaneActive = false;
240
366
  function setTweakpaneActive(status) {
@@ -248,17 +374,21 @@ function getTweakpaneActive() {
248
374
  var CameraManager = class {
249
375
  constructor(targetElement, collisionsManager, initialPhi = Math.PI / 2, initialTheta = -Math.PI / 2) {
250
376
  this.collisionsManager = collisionsManager;
251
- this.initialDistance = 3.3;
252
- this.minDistance = 0.1;
253
- this.maxDistance = 8;
254
- this.initialFOV = 60;
377
+ this.initialDistance = camValues.initialDistance;
378
+ this.minDistance = camValues.minDistance;
379
+ this.maxDistance = camValues.maxDistance;
380
+ this.initialFOV = camValues.initialFOV;
381
+ this.maxFOV = camValues.maxFOV;
382
+ this.minFOV = camValues.minFOV;
383
+ this.damping = camValues.damping;
384
+ this.dampingScale = 0.01;
385
+ this.zoomScale = camValues.zoomScale;
386
+ this.zoomDamping = camValues.zoomDamping;
387
+ this.invertFOVMapping = camValues.invertFOVMapping;
255
388
  this.fov = this.initialFOV;
256
- this.minFOV = 85;
257
- this.maxFOV = 60;
258
389
  this.targetFOV = this.initialFOV;
259
390
  this.minPolarAngle = Math.PI * 0.25;
260
391
  this.maxPolarAngle = Math.PI * 0.95;
261
- this.dampingFactor = 0.091;
262
392
  this.targetDistance = this.initialDistance;
263
393
  this.distance = this.initialDistance;
264
394
  this.desiredDistance = this.initialDistance;
@@ -279,7 +409,7 @@ var CameraManager = class {
279
409
  this.targetPhi = initialPhi;
280
410
  this.theta = initialTheta;
281
411
  this.targetTheta = initialTheta;
282
- this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 300);
412
+ this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
283
413
  this.camera.position.set(0, 1.4, -this.initialDistance);
284
414
  this.rayCaster = new Raycaster();
285
415
  this.hasTouchControl = VirtualJoystick.checkForTouch();
@@ -287,7 +417,8 @@ var CameraManager = class {
287
417
  [targetElement, "mousedown", this.onMouseDown.bind(this)],
288
418
  [document, "mouseup", this.onMouseUp.bind(this)],
289
419
  [document, "mousemove", this.onMouseMove.bind(this)],
290
- [targetElement, "wheel", this.onMouseWheel.bind(this)]
420
+ [targetElement, "wheel", this.onMouseWheel.bind(this)],
421
+ [targetElement, "contextmenu", this.onContextMenu.bind(this)]
291
422
  ]);
292
423
  if (this.hasTouchControl) {
293
424
  this.eventHandlerCollection.add(targetElement, "touchstart", this.onTouchStart.bind(this), {
@@ -301,6 +432,9 @@ var CameraManager = class {
301
432
  });
302
433
  }
303
434
  }
435
+ setupTweakPane(tweakPane) {
436
+ tweakPane.setupCamPane(this);
437
+ }
304
438
  onTouchStart(evt) {
305
439
  Array.from(evt.touches).forEach((touch) => {
306
440
  this.dragging = true;
@@ -320,8 +454,8 @@ var CameraManager = class {
320
454
  this.lastTouchX = touch.clientX;
321
455
  this.lastTouchY = touch.clientY;
322
456
  if (this.targetTheta !== null && this.targetPhi !== null) {
323
- this.targetTheta += dx * 0.01;
324
- this.targetPhi -= dy * 0.01;
457
+ this.targetTheta += dx * this.dampingScale;
458
+ this.targetPhi -= dy * this.dampingScale;
325
459
  this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
326
460
  }
327
461
  }
@@ -334,24 +468,36 @@ var CameraManager = class {
334
468
  }
335
469
  }
336
470
  }
337
- onMouseDown() {
338
- this.dragging = true;
471
+ onMouseDown(event) {
472
+ if (event.button === 0 || event.button === 2) {
473
+ this.dragging = true;
474
+ document.body.style.cursor = "none";
475
+ }
339
476
  }
340
- onMouseUp(_event) {
341
- this.dragging = false;
477
+ onMouseUp(event) {
478
+ if (event.button === 0 || event.button === 2) {
479
+ this.dragging = false;
480
+ document.body.style.cursor = "default";
481
+ }
342
482
  }
343
483
  onMouseMove(event) {
344
- if (!this.dragging || getTweakpaneActive())
345
- return;
346
- if (this.targetTheta === null || this.targetPhi === null)
484
+ if (getTweakpaneActive()) {
347
485
  return;
348
- this.targetTheta += event.movementX * 0.01;
349
- this.targetPhi -= event.movementY * 0.01;
350
- this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
351
- event.preventDefault();
486
+ }
487
+ if (this.dragging) {
488
+ if (this.targetTheta === null || this.targetPhi === null)
489
+ return;
490
+ this.targetTheta += event.movementX * this.dampingScale;
491
+ this.targetPhi -= event.movementY * this.dampingScale;
492
+ this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
493
+ event.preventDefault();
494
+ }
352
495
  }
353
496
  onMouseWheel(event) {
354
- const scrollAmount = event.deltaY * 1e-3;
497
+ if (getTweakpaneActive()) {
498
+ return;
499
+ }
500
+ const scrollAmount = event.deltaY * this.zoomScale * 0.1;
355
501
  this.targetDistance += scrollAmount;
356
502
  this.targetDistance = Math.max(
357
503
  this.minDistance,
@@ -360,6 +506,9 @@ var CameraManager = class {
360
506
  this.desiredDistance = this.targetDistance;
361
507
  event.preventDefault();
362
508
  }
509
+ onContextMenu(event) {
510
+ event.preventDefault();
511
+ }
363
512
  setTarget(target) {
364
513
  if (!this.isLerping) {
365
514
  this.target.copy(target);
@@ -390,14 +539,7 @@ var CameraManager = class {
390
539
  this.theta = this.targetTheta;
391
540
  this.distance = this.targetDistance;
392
541
  this.desiredDistance = this.targetDistance;
393
- this.targetFOV = remap(
394
- this.targetDistance,
395
- this.minDistance,
396
- this.maxDistance,
397
- this.minFOV,
398
- this.maxFOV
399
- );
400
- this.fov = this.targetFOV;
542
+ this.recomputeFoV(true);
401
543
  }
402
544
  adjustCameraPosition() {
403
545
  const offsetDistance = 0.5;
@@ -412,7 +554,7 @@ var CameraManager = class {
412
554
  this.targetDistance = cameraToPlayerDistance - firstRaycastHit[0];
413
555
  this.distance = this.targetDistance;
414
556
  } else {
415
- this.targetDistance += (this.desiredDistance - this.targetDistance) * this.dampingFactor * 4;
557
+ this.targetDistance += (this.desiredDistance - this.targetDistance) * this.damping * 4;
416
558
  }
417
559
  }
418
560
  dispose() {
@@ -424,6 +566,18 @@ var CameraManager = class {
424
566
  updateAspect(aspect) {
425
567
  this.camera.aspect = aspect;
426
568
  }
569
+ recomputeFoV(immediately = false) {
570
+ this.targetFOV = remap(
571
+ this.targetDistance,
572
+ this.minDistance,
573
+ this.maxDistance,
574
+ this.invertFOVMapping ? this.minFOV : this.maxFOV,
575
+ this.invertFOVMapping ? this.maxFOV : this.minFOV
576
+ );
577
+ if (immediately) {
578
+ this.fov = this.targetFOV;
579
+ }
580
+ }
427
581
  update() {
428
582
  if (this.isLerping && this.lerpFactor < 1) {
429
583
  this.lerpFactor += 0.01 / this.lerpDuration;
@@ -433,20 +587,14 @@ var CameraManager = class {
433
587
  this.adjustCameraPosition();
434
588
  }
435
589
  if (this.phi !== null && this.targetPhi !== null && this.theta !== null && this.targetTheta !== null) {
436
- this.distance += (this.targetDistance - this.distance) * this.dampingFactor * 0.21;
437
- this.phi += (this.targetPhi - this.phi) * this.dampingFactor;
438
- this.theta += (this.targetTheta - this.theta) * this.dampingFactor;
590
+ this.distance += (this.targetDistance - this.distance) * this.damping * (0.21 + this.zoomDamping);
591
+ this.phi += (this.targetPhi - this.phi) * this.damping;
592
+ this.theta += (this.targetTheta - this.theta) * this.damping;
439
593
  const x = this.target.x + this.distance * Math.sin(this.phi) * Math.cos(this.theta);
440
594
  const y = this.target.y + this.distance * Math.cos(this.phi);
441
595
  const z = this.target.z + this.distance * Math.sin(this.phi) * Math.sin(this.theta);
442
- this.targetFOV = remap(
443
- this.targetDistance,
444
- this.minDistance,
445
- this.maxDistance,
446
- this.minFOV,
447
- this.maxFOV
448
- );
449
- this.fov += (this.targetFOV - this.fov) * this.dampingFactor;
596
+ this.recomputeFoV();
597
+ this.fov += (this.targetFOV - this.fov) * this.damping;
450
598
  this.camera.fov = this.fov;
451
599
  this.camera.updateProjectionMatrix();
452
600
  this.camera.position.set(x, y, z);
@@ -713,7 +861,7 @@ var CharacterMaterial = class extends MeshStandardMaterial {
713
861
  }
714
862
  update() {
715
863
  if (this.config.isLocal) {
716
- this.targetAlpha = this.config.cameraManager.targetDistance < 0.4 ? 0 : 1;
864
+ this.targetAlpha = this.config.cameraManager.distance < 0.4 ? 0 : 1;
717
865
  this.currentAlpha += ease(this.targetAlpha, this.currentAlpha, 0.07);
718
866
  if (this.currentAlpha > 0.999) {
719
867
  this.currentAlpha = 1;
@@ -748,6 +896,7 @@ var AnimationState = /* @__PURE__ */ ((AnimationState2) => {
748
896
  AnimationState2[AnimationState2["jumpToAir"] = 3] = "jumpToAir";
749
897
  AnimationState2[AnimationState2["air"] = 4] = "air";
750
898
  AnimationState2[AnimationState2["airToGround"] = 5] = "airToGround";
899
+ AnimationState2[AnimationState2["doubleJump"] = 6] = "doubleJump";
751
900
  return AnimationState2;
752
901
  })(AnimationState || {});
753
902
 
@@ -761,24 +910,35 @@ var _CharacterModel = class _CharacterModel {
761
910
  this.animations = {};
762
911
  this.animationMixer = null;
763
912
  this.currentAnimation = 0 /* idle */;
913
+ this.isPostDoubleJump = false;
764
914
  }
765
915
  async init() {
766
916
  await this.loadMainMesh();
767
917
  await this.setAnimationFromFile(
768
918
  this.config.animationConfig.idleAnimationFileUrl,
769
- 0 /* idle */
919
+ 0 /* idle */,
920
+ true
770
921
  );
771
922
  await this.setAnimationFromFile(
772
923
  this.config.animationConfig.jogAnimationFileUrl,
773
- 1 /* walking */
924
+ 1 /* walking */,
925
+ true
774
926
  );
775
927
  await this.setAnimationFromFile(
776
928
  this.config.animationConfig.sprintAnimationFileUrl,
777
- 2 /* running */
929
+ 2 /* running */,
930
+ true
778
931
  );
779
932
  await this.setAnimationFromFile(
780
933
  this.config.animationConfig.airAnimationFileUrl,
781
- 4 /* air */
934
+ 4 /* air */,
935
+ true
936
+ );
937
+ await this.setAnimationFromFile(
938
+ this.config.animationConfig.doubleJumpAnimationFileUrl,
939
+ 6 /* doubleJump */,
940
+ false,
941
+ 1.45
782
942
  );
783
943
  this.applyCustomMaterials();
784
944
  }
@@ -816,6 +976,13 @@ var _CharacterModel = class _CharacterModel {
816
976
  });
817
977
  }
818
978
  updateAnimation(targetAnimation) {
979
+ if (this.isPostDoubleJump) {
980
+ if (targetAnimation === 6 /* doubleJump */) {
981
+ targetAnimation = 4 /* air */;
982
+ } else {
983
+ this.isPostDoubleJump = false;
984
+ }
985
+ }
819
986
  if (this.currentAnimation !== targetAnimation) {
820
987
  this.transitionToAnimation(targetAnimation);
821
988
  }
@@ -906,16 +1073,21 @@ var _CharacterModel = class _CharacterModel {
906
1073
  });
907
1074
  return animationClip;
908
1075
  }
909
- async setAnimationFromFile(animationFileUrl, animationType) {
1076
+ async setAnimationFromFile(animationFileUrl, animationType, loop = true, playbackSpeed = 1) {
910
1077
  return new Promise(async (resolve, reject) => {
911
1078
  const animation = await this.config.characterModelLoader.load(animationFileUrl, "animation");
912
1079
  const cleanAnimation = this.cleanAnimationClips(this.mesh, animation);
913
1080
  if (typeof animation !== "undefined" && cleanAnimation instanceof AnimationClip) {
914
1081
  this.animations[animationType] = this.animationMixer.clipAction(cleanAnimation);
915
1082
  this.animations[animationType].stop();
1083
+ this.animations[animationType].timeScale = playbackSpeed;
916
1084
  if (animationType === 0 /* idle */) {
917
1085
  this.animations[animationType].play();
918
1086
  }
1087
+ if (!loop) {
1088
+ this.animations[animationType].setLoop(LoopRepeat, 1);
1089
+ this.animations[animationType].clampWhenFinished = true;
1090
+ }
919
1091
  resolve();
920
1092
  } else {
921
1093
  reject(`failed to load ${animationType} from ${animationFileUrl}`);
@@ -923,20 +1095,30 @@ var _CharacterModel = class _CharacterModel {
923
1095
  });
924
1096
  }
925
1097
  transitionToAnimation(targetAnimation, transitionDuration = 0.15) {
926
- if (!this.mesh)
1098
+ if (!this.mesh) {
927
1099
  return;
1100
+ }
928
1101
  const currentAction = this.animations[this.currentAnimation];
929
1102
  this.currentAnimation = targetAnimation;
930
1103
  const targetAction = this.animations[targetAnimation];
931
- if (!targetAction)
1104
+ if (!targetAction) {
932
1105
  return;
1106
+ }
933
1107
  if (currentAction) {
934
- currentAction.enabled = true;
935
1108
  currentAction.fadeOut(transitionDuration);
936
1109
  }
937
- if (!targetAction.isRunning())
1110
+ targetAction.reset();
1111
+ if (!targetAction.isRunning()) {
938
1112
  targetAction.play();
939
- targetAction.setLoop(LoopRepeat, Infinity);
1113
+ }
1114
+ if (targetAnimation === 6 /* doubleJump */) {
1115
+ targetAction.getMixer().addEventListener("finished", (_event) => {
1116
+ if (this.currentAnimation === 6 /* doubleJump */) {
1117
+ this.isPostDoubleJump = true;
1118
+ this.updateAnimation(6 /* doubleJump */);
1119
+ }
1120
+ });
1121
+ }
940
1122
  targetAction.enabled = true;
941
1123
  targetAction.fadeIn(transitionDuration);
942
1124
  }
@@ -1053,7 +1235,7 @@ import {
1053
1235
  } from "three";
1054
1236
 
1055
1237
  // src/character/CanvasText.ts
1056
- import { Texture as Texture2, LinearFilter, RGBAFormat, MeshBasicMaterial } from "three";
1238
+ import { Texture, LinearFilter, RGBAFormat, MeshBasicMaterial } from "three";
1057
1239
  function getTextAlignOffset(textAlign, width) {
1058
1240
  switch (textAlign) {
1059
1241
  case "center":
@@ -1154,7 +1336,7 @@ function CanvasText(message, options) {
1154
1336
  }
1155
1337
  function THREECanvasTextTexture(text, options) {
1156
1338
  const canvas2 = CanvasText(text, options);
1157
- const texture = new Texture2(canvas2);
1339
+ const texture = new Texture(canvas2);
1158
1340
  texture.minFilter = LinearFilter;
1159
1341
  texture.magFilter = LinearFilter;
1160
1342
  texture.format = RGBAFormat;
@@ -1348,15 +1530,189 @@ import { Euler as Euler2, Group as Group2, Quaternion as Quaternion5, Vector3 as
1348
1530
 
1349
1531
  // src/character/LocalController.ts
1350
1532
  import { Euler, Line3, Matrix4, Quaternion as Quaternion2, Ray, Raycaster as Raycaster2, Vector3 as Vector35 } from "three";
1533
+
1534
+ // src/tweakpane/blades/characterControlsFolder.ts
1535
+ var characterControllerValues = {
1536
+ gravity: 35.5,
1537
+ jumpForce: 18,
1538
+ doubleJumpForce: 17.7,
1539
+ coyoteJump: 120,
1540
+ airResistance: 0.5,
1541
+ groundResistance: 0,
1542
+ airControlModifier: 0.05,
1543
+ groundWalkControl: 0.75,
1544
+ groundRunControl: 1,
1545
+ baseControlMultiplier: 200,
1546
+ minimumSurfaceAngle: 0.905
1547
+ };
1548
+ var characterControllerOptions = {
1549
+ gravity: { min: 1, max: 100, step: 0.05 },
1550
+ jumpForce: { min: 1, max: 50, step: 0.05 },
1551
+ doubleJumpForce: { min: 1, max: 50, step: 0.05 },
1552
+ coyoteJump: { min: 60, max: 200, step: 1 },
1553
+ airResistance: { min: 0.01, max: 0.9, step: 0.01 },
1554
+ groundResistance: { min: -100, max: 0, step: 1 },
1555
+ airControlModifier: { min: 1e-3, max: 0.15, step: 0.01 },
1556
+ groundWalkControl: { min: 0.1, max: 1.5, step: 0.01 },
1557
+ groundRunControl: { min: 0.5, max: 2, step: 0.01 },
1558
+ baseControlMultiplier: { min: 150, max: 300, step: 1 },
1559
+ minimumSurfaceAngle: { min: 0.254, max: 1, step: 1e-3 }
1560
+ };
1561
+ var CharacterControlsFolder = class {
1562
+ constructor(parentFolder, expand = false) {
1563
+ this.characterData = {
1564
+ position: "(0, 0, 0)",
1565
+ onGround: "false",
1566
+ canJump: "false",
1567
+ canDoubleJump: "false",
1568
+ jumpCount: "0",
1569
+ coyoteTime: "false",
1570
+ coyoteJumped: "false"
1571
+ };
1572
+ this.folder = parentFolder.addFolder({ title: "character", expanded: expand });
1573
+ this.folder.addBinding(this.characterData, "position", { readonly: true });
1574
+ this.folder.addBinding(this.characterData, "onGround", { readonly: true });
1575
+ this.folder.addBinding(this.characterData, "canJump", { readonly: true });
1576
+ this.folder.addBinding(this.characterData, "canDoubleJump", { readonly: true });
1577
+ this.folder.addBinding(this.characterData, "jumpCount", { readonly: true });
1578
+ this.folder.addBinding(this.characterData, "coyoteTime", { readonly: true });
1579
+ this.folder.addBinding(this.characterData, "coyoteJumped", { readonly: true });
1580
+ this.folder.addBinding(
1581
+ characterControllerValues,
1582
+ "gravity",
1583
+ characterControllerOptions.gravity
1584
+ );
1585
+ this.folder.addBinding(
1586
+ characterControllerValues,
1587
+ "jumpForce",
1588
+ characterControllerOptions.jumpForce
1589
+ );
1590
+ this.folder.addBinding(
1591
+ characterControllerValues,
1592
+ "doubleJumpForce",
1593
+ characterControllerOptions.doubleJumpForce
1594
+ );
1595
+ this.folder.addBinding(
1596
+ characterControllerValues,
1597
+ "coyoteJump",
1598
+ characterControllerOptions.coyoteJump
1599
+ );
1600
+ this.folder.addBinding(
1601
+ characterControllerValues,
1602
+ "airResistance",
1603
+ characterControllerOptions.airResistance
1604
+ );
1605
+ this.folder.addBinding(
1606
+ characterControllerValues,
1607
+ "groundResistance",
1608
+ characterControllerOptions.groundResistance
1609
+ );
1610
+ this.folder.addBinding(
1611
+ characterControllerValues,
1612
+ "airControlModifier",
1613
+ characterControllerOptions.airControlModifier
1614
+ );
1615
+ this.folder.addBinding(
1616
+ characterControllerValues,
1617
+ "groundWalkControl",
1618
+ characterControllerOptions.groundWalkControl
1619
+ );
1620
+ this.folder.addBinding(
1621
+ characterControllerValues,
1622
+ "groundRunControl",
1623
+ characterControllerOptions.groundRunControl
1624
+ );
1625
+ this.folder.addBinding(
1626
+ characterControllerValues,
1627
+ "baseControlMultiplier",
1628
+ characterControllerOptions.baseControlMultiplier
1629
+ );
1630
+ this.folder.addBinding(
1631
+ characterControllerValues,
1632
+ "minimumSurfaceAngle",
1633
+ characterControllerOptions.minimumSurfaceAngle
1634
+ );
1635
+ }
1636
+ setupChangeEvent(localController) {
1637
+ this.folder.on("change", (e) => {
1638
+ const target = e.target.key;
1639
+ if (!target)
1640
+ return;
1641
+ switch (target) {
1642
+ case "gravity": {
1643
+ const value = e.value;
1644
+ localController.gravity = value * -1;
1645
+ break;
1646
+ }
1647
+ case "jumpForce": {
1648
+ const value = e.value;
1649
+ localController.jumpForce = value;
1650
+ break;
1651
+ }
1652
+ case "doubleJumpForce": {
1653
+ const value = e.value;
1654
+ localController.doubleJumpForce = value;
1655
+ break;
1656
+ }
1657
+ case "coyoteJump": {
1658
+ const value = e.value;
1659
+ localController.coyoteTimeThreshold = value;
1660
+ break;
1661
+ }
1662
+ case "airResistance": {
1663
+ const value = e.value;
1664
+ localController.airResistance = value;
1665
+ break;
1666
+ }
1667
+ case "groundResistance": {
1668
+ const value = e.value;
1669
+ localController.groundResistance = 0.99999999 + value * 1e-6;
1670
+ break;
1671
+ }
1672
+ case "airControlModifier": {
1673
+ const value = e.value;
1674
+ localController.airControlModifier = value;
1675
+ break;
1676
+ }
1677
+ case "groundWalkControl": {
1678
+ const value = e.value;
1679
+ localController.groundWalkControl = value;
1680
+ break;
1681
+ }
1682
+ case "groundRunControl": {
1683
+ const value = e.value;
1684
+ localController.groundRunControl = value;
1685
+ break;
1686
+ }
1687
+ case "baseControlMultiplier": {
1688
+ const value = e.value;
1689
+ localController.baseControl = value;
1690
+ break;
1691
+ }
1692
+ case "minimumSurfaceAngle": {
1693
+ const value = e.value;
1694
+ localController.minimumSurfaceAngle = value;
1695
+ break;
1696
+ }
1697
+ default:
1698
+ break;
1699
+ }
1700
+ });
1701
+ }
1702
+ update(localController) {
1703
+ const { x, y, z } = localController.latestPosition;
1704
+ this.characterData.position = `(${x.toFixed(2)}, ${y.toFixed(2)}, ${z.toFixed(2)})`;
1705
+ this.characterData.onGround = `${localController.characterOnGround}`;
1706
+ this.characterData.canJump = `${localController.canJump || localController.coyoteTime ? "true" : "false"}`;
1707
+ this.characterData.canDoubleJump = `${localController.canDoubleJump}`;
1708
+ this.characterData.jumpCount = `${localController.jumpCounter}`;
1709
+ this.characterData.coyoteTime = `${localController.coyoteTime}`;
1710
+ this.characterData.coyoteJumped = `${localController.coyoteJumped}`;
1711
+ }
1712
+ };
1713
+
1714
+ // src/character/LocalController.ts
1351
1715
  var downVector = new Vector35(0, -1, 0);
1352
- var airResistance = 0.5;
1353
- var groundResistance = 0.99999999;
1354
- var airControlModifier = 0.05;
1355
- var groundWalkControl = 0.75;
1356
- var groundRunControl = 1;
1357
- var baseControl = 200;
1358
- var collisionDetectionSteps = 15;
1359
- var minimumSurfaceAngle = 0.9;
1360
1716
  var LocalController = class {
1361
1717
  constructor(config) {
1362
1718
  this.config = config;
@@ -1364,12 +1720,26 @@ var LocalController = class {
1364
1720
  radius: 0.4,
1365
1721
  segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
1366
1722
  };
1367
- this.gravity = -42;
1368
- this.jumpForce = 20;
1369
- this.coyoteTimeThreshold = 70;
1370
- this.coyoteTime = false;
1723
+ this.gravity = -characterControllerValues.gravity;
1724
+ this.jumpForce = characterControllerValues.jumpForce;
1725
+ this.doubleJumpForce = characterControllerValues.doubleJumpForce;
1726
+ this.coyoteTimeThreshold = characterControllerValues.coyoteJump;
1371
1727
  this.canJump = true;
1728
+ this.canDoubleJump = true;
1729
+ this.coyoteJumped = false;
1730
+ this.doubleJumpUsed = false;
1731
+ this.jumpCounter = 0;
1732
+ this.airResistance = characterControllerValues.airResistance;
1733
+ this.groundResistance = 0.99999999 + characterControllerValues.groundResistance * 1e-7;
1734
+ this.airControlModifier = characterControllerValues.airControlModifier;
1735
+ this.groundWalkControl = characterControllerValues.groundWalkControl;
1736
+ this.groundRunControl = characterControllerValues.groundRunControl;
1737
+ this.baseControl = characterControllerValues.baseControlMultiplier;
1738
+ this.minimumSurfaceAngle = characterControllerValues.minimumSurfaceAngle;
1739
+ this.latestPosition = new Vector35();
1372
1740
  this.characterOnGround = false;
1741
+ this.coyoteTime = false;
1742
+ this.collisionDetectionSteps = 15;
1373
1743
  this.characterWasOnGround = false;
1374
1744
  this.characterAirborneSince = 0;
1375
1745
  this.currentHeight = 0;
@@ -1396,6 +1766,9 @@ var LocalController = class {
1396
1766
  this.surfaceTempVector5 = new Vector35();
1397
1767
  this.surfaceTempRay = new Ray();
1398
1768
  this.lastFrameSurfaceState = null;
1769
+ this.jumpPressed = false;
1770
+ // Tracks if the jump button is pressed
1771
+ this.jumpReleased = true;
1399
1772
  this.networkState = {
1400
1773
  id: this.config.id,
1401
1774
  position: { x: 0, y: 0, z: 0 },
@@ -1413,6 +1786,9 @@ var LocalController = class {
1413
1786
  this.jump = this.config.keyInputManager.jump;
1414
1787
  this.anyDirection = this.config.keyInputManager.anyDirection || ((_e = this.config.virtualJoystick) == null ? void 0 : _e.hasDirection) || false;
1415
1788
  this.conflictingDirections = this.config.keyInputManager.conflictingDirection;
1789
+ if (!this.jump) {
1790
+ this.jumpReleased = true;
1791
+ }
1416
1792
  }
1417
1793
  update() {
1418
1794
  this.updateControllerState();
@@ -1431,14 +1807,14 @@ var LocalController = class {
1431
1807
  if (this.anyDirection) {
1432
1808
  this.updateRotation();
1433
1809
  }
1434
- for (let i = 0; i < collisionDetectionSteps; i++) {
1810
+ for (let i = 0; i < this.collisionDetectionSteps; i++) {
1435
1811
  this.updatePosition(
1436
1812
  this.config.timeManager.deltaTime,
1437
- this.config.timeManager.deltaTime / collisionDetectionSteps,
1813
+ this.config.timeManager.deltaTime / this.collisionDetectionSteps,
1438
1814
  i
1439
1815
  );
1440
1816
  }
1441
- if (this.config.character.position.y < 0) {
1817
+ if (this.config.character.position.y < -100) {
1442
1818
  this.resetPosition();
1443
1819
  }
1444
1820
  this.updateNetworkState();
@@ -1448,6 +1824,9 @@ var LocalController = class {
1448
1824
  return 0 /* idle */;
1449
1825
  const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8;
1450
1826
  if (this.currentHeight > jumpHeight && !this.characterOnGround) {
1827
+ if (this.doubleJumpUsed) {
1828
+ return 6 /* doubleJump */;
1829
+ }
1451
1830
  return 4 /* air */;
1452
1831
  }
1453
1832
  if (this.conflictingDirections) {
@@ -1507,31 +1886,59 @@ var LocalController = class {
1507
1886
  const frameRotation = angularSpeed * this.config.timeManager.deltaTime;
1508
1887
  this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1509
1888
  }
1510
- applyControls(deltaTime) {
1511
- const resistance = this.characterOnGround ? groundResistance : airResistance;
1512
- const speedFactor = Math.pow(1 - resistance, deltaTime);
1513
- this.characterVelocity.multiplyScalar(speedFactor);
1514
- const acceleration = this.tempVector.set(0, 0, 0);
1889
+ processJump(currentAcceleration, deltaTime) {
1515
1890
  if (this.characterOnGround) {
1891
+ this.coyoteJumped = false;
1892
+ this.canDoubleJump = false;
1893
+ this.doubleJumpUsed = false;
1894
+ this.jumpCounter = 0;
1516
1895
  if (!this.jump) {
1896
+ this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
1517
1897
  this.canJump = true;
1898
+ this.jumpReleased = true;
1518
1899
  }
1519
- if (this.jump && this.canJump) {
1520
- acceleration.y += this.jumpForce / deltaTime;
1900
+ if (this.jump && this.canJump && this.jumpReleased) {
1901
+ currentAcceleration.y += this.jumpForce / deltaTime;
1521
1902
  this.canJump = false;
1903
+ this.jumpReleased = false;
1904
+ this.jumpCounter++;
1522
1905
  } else {
1523
- if (this.currentSurfaceAngle.y < minimumSurfaceAngle) {
1524
- acceleration.y += this.gravity;
1906
+ if (this.currentSurfaceAngle.y < this.minimumSurfaceAngle) {
1907
+ currentAcceleration.y += this.gravity;
1525
1908
  }
1526
1909
  }
1527
- } else if (this.jump && this.coyoteTime) {
1528
- acceleration.y += this.jumpForce / deltaTime;
1529
- this.canJump = false;
1530
1910
  } else {
1531
- acceleration.y += this.gravity;
1532
- this.canJump = false;
1911
+ if (this.jump && !this.coyoteJumped && this.coyoteTime) {
1912
+ this.coyoteJumped = true;
1913
+ currentAcceleration.y += this.jumpForce / deltaTime;
1914
+ this.canJump = false;
1915
+ this.jumpReleased = false;
1916
+ this.jumpCounter++;
1917
+ } else if (this.jump && this.canDoubleJump) {
1918
+ currentAcceleration.y += this.doubleJumpForce / deltaTime;
1919
+ this.doubleJumpUsed = true;
1920
+ this.jumpReleased = false;
1921
+ this.jumpCounter++;
1922
+ } else {
1923
+ currentAcceleration.y += this.gravity;
1924
+ this.canJump = false;
1925
+ }
1926
+ }
1927
+ if (!this.jump) {
1928
+ this.jumpReleased = true;
1929
+ if (!this.characterOnGround) {
1930
+ currentAcceleration.y += this.gravity;
1931
+ }
1533
1932
  }
1534
- const control = (this.characterOnGround ? this.run ? groundRunControl : groundWalkControl : airControlModifier) * baseControl;
1933
+ }
1934
+ applyControls(deltaTime) {
1935
+ const resistance = this.characterOnGround ? this.groundResistance : this.airResistance;
1936
+ const speedFactor = Math.pow(1 - resistance, deltaTime);
1937
+ this.characterVelocity.multiplyScalar(speedFactor);
1938
+ const acceleration = this.tempVector.set(0, 0, 0);
1939
+ this.canDoubleJump = !this.doubleJumpUsed && this.jumpReleased && this.jumpCounter === 1;
1940
+ this.processJump(acceleration, deltaTime);
1941
+ const control = (this.characterOnGround ? this.run ? this.groundRunControl : this.groundWalkControl : this.airControlModifier) * this.baseControl;
1535
1942
  const controlAcceleration = this.tempVector2.set(0, 0, 0);
1536
1943
  if (!this.conflictingDirections) {
1537
1944
  if (this.forward) {
@@ -1584,10 +1991,18 @@ var LocalController = class {
1584
1991
  this.config.character.position.copy(avatarSegment.start);
1585
1992
  const deltaCollisionPosition = avatarSegment.start.sub(positionBeforeCollisions);
1586
1993
  this.characterOnGround = deltaCollisionPosition.y > 0;
1994
+ if (this.characterOnGround) {
1995
+ this.doubleJumpUsed = false;
1996
+ this.jumpCounter = 0;
1997
+ }
1587
1998
  if (this.characterWasOnGround && !this.characterOnGround) {
1588
1999
  this.characterAirborneSince = Date.now();
1589
2000
  }
2001
+ if (!this.jump) {
2002
+ this.jumpReleased = true;
2003
+ }
1590
2004
  this.coyoteTime = this.characterVelocity.y < 0 && !this.characterOnGround && Date.now() - this.characterAirborneSince < this.coyoteTimeThreshold;
2005
+ this.latestPosition = this.config.character.position.clone();
1591
2006
  this.characterWasOnGround = this.characterOnGround;
1592
2007
  }
1593
2008
  getMovementFromSurfaces(userPosition, deltaTime) {
@@ -1672,6 +2087,9 @@ var LocalController = class {
1672
2087
  this.characterVelocity.y = 0;
1673
2088
  this.config.character.position.y = 3;
1674
2089
  this.characterOnGround = false;
2090
+ this.doubleJumpUsed = false;
2091
+ this.jumpReleased = true;
2092
+ this.jumpCounter = 0;
1675
2093
  }
1676
2094
  };
1677
2095
 
@@ -1743,7 +2161,6 @@ function decodeCharacterAndCamera(hash) {
1743
2161
  var CharacterManager = class {
1744
2162
  constructor(config) {
1745
2163
  this.config = config;
1746
- this.updateLocationHash = true;
1747
2164
  this.headTargetOffset = new Vector38(0, 1.3, 0);
1748
2165
  this.localClientId = 0;
1749
2166
  this.remoteCharacters = /* @__PURE__ */ new Map();
@@ -1793,6 +2210,9 @@ var CharacterManager = class {
1793
2210
  this.group.add(character);
1794
2211
  this.localCharacterSpawned = true;
1795
2212
  }
2213
+ setupTweakPane(tweakPane) {
2214
+ tweakPane.setupCharacterController(this.localController);
2215
+ }
1796
2216
  spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1797
2217
  const character = new Character({
1798
2218
  username,
@@ -1900,11 +2320,14 @@ var CharacterManager = class {
1900
2320
  this.remoteCharacterControllers.delete(id);
1901
2321
  }
1902
2322
  }
1903
- if (this.updateLocationHash && this.config.timeManager.frame % 60 === 0) {
1904
- window.location.hash = encodeCharacterAndCamera(
2323
+ if (this.config.updateURLLocation && this.config.timeManager.frame % 60 === 0 && document.hasFocus()) {
2324
+ const hash = encodeCharacterAndCamera(
1905
2325
  this.localCharacter,
1906
2326
  this.config.cameraManager.camera
1907
2327
  );
2328
+ const url = new URL(window.location.href);
2329
+ url.hash = hash;
2330
+ window.history.replaceState({}, "", url);
1908
2331
  }
1909
2332
  }
1910
2333
  }
@@ -2199,6 +2622,11 @@ var sunOptions = {
2199
2622
  sunIntensity: { min: 0, max: 10, step: 0.1 }
2200
2623
  };
2201
2624
  var envValues = {
2625
+ skyboxAzimuthalAngle: 0,
2626
+ skyboxPolarAngle: 0,
2627
+ envMapIntensity: 0.07,
2628
+ skyboxIntensity: 0.8,
2629
+ skyboxBlurriness: 0,
2202
2630
  ambientLight: {
2203
2631
  ambientLightIntensity: 0.27,
2204
2632
  ambientLightColor: { r: 1, g: 1, b: 1 }
@@ -2210,6 +2638,10 @@ var envValues = {
2210
2638
  }
2211
2639
  };
2212
2640
  var envOptions = {
2641
+ skyboxAzimuthalAngle: { min: 0, max: 360, step: 1 },
2642
+ skyboxPolarAngle: { min: 0, max: 360, step: 1 },
2643
+ skyboxIntensity: { min: 0, max: 1.3, step: 0.01 },
2644
+ skyboxBlurriness: { min: 0, max: 0.1, step: 1e-3 },
2213
2645
  ambientLight: {
2214
2646
  ambientLightIntensity: { min: 0, max: 1, step: 0.01 }
2215
2647
  },
@@ -2222,6 +2654,9 @@ var EnvironmentFolder = class {
2222
2654
  constructor(parentFolder, expand = false) {
2223
2655
  this.folder = parentFolder.addFolder({ title: "environment", expanded: expand });
2224
2656
  this.sun = this.folder.addFolder({ title: "sun", expanded: true });
2657
+ this.envMap = this.folder.addFolder({ title: "envMap", expanded: true });
2658
+ this.fog = this.folder.addFolder({ title: "fog", expanded: true });
2659
+ this.skybox = this.folder.addFolder({ title: "skybox", expanded: true });
2225
2660
  this.ambient = this.folder.addFolder({ title: "ambient", expanded: true });
2226
2661
  this.sun.addBinding(
2227
2662
  sunValues.sunPosition,
@@ -2237,7 +2672,12 @@ var EnvironmentFolder = class {
2237
2672
  this.sun.addBinding(sunValues, "sunColor", {
2238
2673
  color: { type: "float" }
2239
2674
  });
2240
- this.sunButton = this.sun.addButton({ title: "Set HDRI" });
2675
+ this.hdrButton = this.skybox.addButton({ title: "Set HDRI" });
2676
+ this.skybox.addBinding(envValues, "skyboxIntensity", envOptions.skyboxIntensity);
2677
+ this.skybox.addBinding(envValues, "skyboxBlurriness", envOptions.skyboxBlurriness);
2678
+ this.skybox.addBinding(envValues, "skyboxAzimuthalAngle", envOptions.skyboxAzimuthalAngle);
2679
+ this.skybox.addBinding(envValues, "skyboxPolarAngle", envOptions.skyboxPolarAngle);
2680
+ this.envMap.addBinding(envValues, "envMapIntensity", envOptions.skyboxIntensity);
2241
2681
  this.ambient.addBinding(
2242
2682
  envValues.ambientLight,
2243
2683
  "ambientLightIntensity",
@@ -2246,13 +2686,13 @@ var EnvironmentFolder = class {
2246
2686
  this.ambient.addBinding(envValues.ambientLight, "ambientLightColor", {
2247
2687
  color: { type: "float" }
2248
2688
  });
2249
- this.ambient.addBinding(envValues.fog, "fogNear", envOptions.fog.fogNear);
2250
- this.ambient.addBinding(envValues.fog, "fogFar", envOptions.fog.fogFar);
2251
- this.ambient.addBinding(envValues.fog, "fogColor", {
2689
+ this.fog.addBinding(envValues.fog, "fogNear", envOptions.fog.fogNear);
2690
+ this.fog.addBinding(envValues.fog, "fogFar", envOptions.fog.fogFar);
2691
+ this.fog.addBinding(envValues.fog, "fogColor", {
2252
2692
  color: { type: "float" }
2253
2693
  });
2254
2694
  }
2255
- setupChangeEvent(setHDR, setAmbientLight, setFog, sun) {
2695
+ setupChangeEvent(scene, setHDR, setSkyboxAzimuthalAngle, setSkyboxPolarAngle, setAmbientLight, setFog, sun) {
2256
2696
  this.sun.on("change", (e) => {
2257
2697
  const target = e.target.key;
2258
2698
  if (!target)
@@ -2287,9 +2727,43 @@ var EnvironmentFolder = class {
2287
2727
  break;
2288
2728
  }
2289
2729
  });
2290
- this.sunButton.on("click", () => {
2730
+ this.hdrButton.on("click", () => {
2291
2731
  setHDR();
2292
2732
  });
2733
+ this.envMap.on("change", (e) => {
2734
+ const target = e.target.key;
2735
+ if (!target)
2736
+ return;
2737
+ switch (target) {
2738
+ case "envMapIntensity":
2739
+ scene.environmentIntensity = e.value;
2740
+ break;
2741
+ }
2742
+ });
2743
+ this.skybox.on("change", (e) => {
2744
+ const target = e.target.key;
2745
+ if (!target)
2746
+ return;
2747
+ switch (target) {
2748
+ case "skyboxAzimuthalAngle": {
2749
+ const value = e.value;
2750
+ setSkyboxAzimuthalAngle(value);
2751
+ break;
2752
+ }
2753
+ case "skyboxPolarAngle": {
2754
+ const value = e.value;
2755
+ envValues.skyboxPolarAngle = value;
2756
+ setSkyboxPolarAngle(value);
2757
+ break;
2758
+ }
2759
+ case "skyboxIntensity":
2760
+ scene.backgroundIntensity = e.value;
2761
+ break;
2762
+ case "skyboxBlurriness":
2763
+ scene.backgroundBlurriness = e.value;
2764
+ break;
2765
+ }
2766
+ });
2293
2767
  this.ambient.on("change", (e) => {
2294
2768
  const target = e.target.key;
2295
2769
  if (!target)
@@ -2310,6 +2784,13 @@ var EnvironmentFolder = class {
2310
2784
  setAmbientLight();
2311
2785
  break;
2312
2786
  }
2787
+ }
2788
+ });
2789
+ this.fog.on("change", (e) => {
2790
+ const target = e.target.key;
2791
+ if (!target)
2792
+ return;
2793
+ switch (target) {
2313
2794
  case "fogNear": {
2314
2795
  envValues.fog.fogNear = e.value;
2315
2796
  setFog();
@@ -2330,8 +2811,6 @@ var EnvironmentFolder = class {
2330
2811
  setFog();
2331
2812
  break;
2332
2813
  }
2333
- default:
2334
- break;
2335
2814
  }
2336
2815
  });
2337
2816
  }
@@ -2340,7 +2819,7 @@ var EnvironmentFolder = class {
2340
2819
  // src/tweakpane/blades/postExtrasFolder.ts
2341
2820
  var extrasValues = {
2342
2821
  grain: 0.045,
2343
- bloom: 0.75
2822
+ bloom: 0.15
2344
2823
  };
2345
2824
  var extrasOptions = {
2346
2825
  grain: {
@@ -2379,16 +2858,12 @@ var PostExtrasFolder = class {
2379
2858
  var rendererValues = {
2380
2859
  shadowMap: 2,
2381
2860
  toneMapping: 5,
2382
- exposure: 1.7,
2383
- bgIntensity: 0.8,
2384
- bgBlurriness: 0
2861
+ exposure: 1.7
2385
2862
  };
2386
2863
  var rendererOptions = {
2387
2864
  shadowMap: { min: 0, max: 2, step: 1 },
2388
2865
  toneMapping: { min: 0, max: 5, step: 1 },
2389
- exposure: { min: 0, max: 3, step: 0.01 },
2390
- bgIntensity: { min: 0, max: 1.3, step: 0.01 },
2391
- bgBlurriness: { min: 0, max: 0.1, step: 1e-3 }
2866
+ exposure: { min: 0, max: 3, step: 0.01 }
2392
2867
  };
2393
2868
  var shadowMapTypes = {
2394
2869
  0: "BasicShadowMap",
@@ -2426,10 +2901,8 @@ var RendererFolder = class {
2426
2901
  this.folder.addBinding(rendererValues, "toneMapping", rendererOptions.toneMapping);
2427
2902
  this.folder.addBinding(monitoredValues, "toneMappingType", { readonly: true });
2428
2903
  this.folder.addBinding(rendererValues, "exposure", rendererOptions.exposure);
2429
- this.folder.addBinding(rendererValues, "bgIntensity", rendererOptions.bgIntensity);
2430
- this.folder.addBinding(rendererValues, "bgBlurriness", rendererOptions.bgBlurriness);
2431
2904
  }
2432
- setupChangeEvent(scene, renderer, toneMappingFolder, toneMappingPass) {
2905
+ setupChangeEvent(renderer, toneMappingFolder, toneMappingPass) {
2433
2906
  this.folder.on("change", (e) => {
2434
2907
  const target = e.target.key;
2435
2908
  if (!target)
@@ -2450,12 +2923,6 @@ var RendererFolder = class {
2450
2923
  case "exposure":
2451
2924
  renderer.toneMappingExposure = e.value;
2452
2925
  break;
2453
- case "bgIntensity":
2454
- scene.backgroundIntensity = e.value;
2455
- break;
2456
- case "bgBlurriness":
2457
- scene.backgroundBlurriness = e.value;
2458
- break;
2459
2926
  default:
2460
2927
  break;
2461
2928
  }
@@ -2544,7 +3011,7 @@ var n8ssaoValues = {
2544
3011
  halfRes: true,
2545
3012
  aoRadius: 5,
2546
3013
  distanceFalloff: 3,
2547
- intensity: 1,
3014
+ intensity: 1.5,
2548
3015
  color: { r: 0, g: 0, b: 0 },
2549
3016
  aoSamples: 16,
2550
3017
  denoiseSamples: 4,
@@ -2860,9 +3327,6 @@ var tweakPaneStyle = `
2860
3327
  --tp-label-foreground-color: hsla(0, 0%, 100%, 0.6);
2861
3328
  --tp-monitor-background-color: hsla(0, 0%, 0%, 0.3);
2862
3329
  --tp-monitor-foreground-color: hsla(0, 0%, 100%, 0.3);
2863
- -webkit-user-select: none;
2864
- -ms-user-select: none;
2865
- user-select: none;
2866
3330
  }
2867
3331
 
2868
3332
  .tp-brkv {
@@ -2931,20 +3395,20 @@ var TweakPane = class {
2931
3395
  this.composer = composer;
2932
3396
  this.saveVisibilityInLocalStorage = true;
2933
3397
  this.guiVisible = false;
2934
- const tweakPaneWrapper = document.createElement("div");
2935
- tweakPaneWrapper.style.position = "fixed";
2936
- tweakPaneWrapper.style.width = "400px";
2937
- tweakPaneWrapper.style.height = "100%";
2938
- tweakPaneWrapper.style.top = "0px";
2939
- tweakPaneWrapper.style.right = "calc(-50vw)";
2940
- tweakPaneWrapper.style.zIndex = "99";
2941
- tweakPaneWrapper.style.overflow = "auto";
2942
- tweakPaneWrapper.style.backgroundColor = "rgba(0, 0, 0, 0.66)";
2943
- tweakPaneWrapper.style.paddingLeft = "5px";
2944
- tweakPaneWrapper.style.boxShadow = "-7px 0px 12px rgba(0, 0, 0, 0.5)";
2945
- tweakPaneWrapper.style.transition = "right cubic-bezier(0.83, 0, 0.17, 1) 0.7s";
2946
- holderElement.appendChild(tweakPaneWrapper);
2947
- this.gui = new Pane({ container: tweakPaneWrapper });
3398
+ this.tweakPaneWrapper = document.createElement("div");
3399
+ this.tweakPaneWrapper.style.position = "fixed";
3400
+ this.tweakPaneWrapper.style.width = "400px";
3401
+ this.tweakPaneWrapper.style.height = "100%";
3402
+ this.tweakPaneWrapper.style.top = "0px";
3403
+ this.tweakPaneWrapper.style.right = "calc(-50vw)";
3404
+ this.tweakPaneWrapper.style.zIndex = "99";
3405
+ this.tweakPaneWrapper.style.overflow = "auto";
3406
+ this.tweakPaneWrapper.style.backgroundColor = "rgba(0, 0, 0, 0.66)";
3407
+ this.tweakPaneWrapper.style.paddingLeft = "5px";
3408
+ this.tweakPaneWrapper.style.boxShadow = "-7px 0px 12px rgba(0, 0, 0, 0.5)";
3409
+ this.tweakPaneWrapper.style.transition = "right cubic-bezier(0.83, 0, 0.17, 1) 0.7s";
3410
+ holderElement.appendChild(this.tweakPaneWrapper);
3411
+ this.gui = new Pane({ container: this.tweakPaneWrapper });
2948
3412
  this.gui.registerPlugin(EssentialsPlugin);
2949
3413
  if (this.saveVisibilityInLocalStorage) {
2950
3414
  const localStorageGuiVisible = localStorage.getItem("guiVisible");
@@ -2968,28 +3432,31 @@ var TweakPane = class {
2968
3432
  this.postExtrasFolder = new PostExtrasFolder(this.gui, false);
2969
3433
  this.character = new CharacterFolder(this.gui, false);
2970
3434
  this.environment = new EnvironmentFolder(this.gui, false);
3435
+ this.camera = new CameraFolder(this.gui, false);
3436
+ this.characterControls = new CharacterControlsFolder(this.gui, false);
2971
3437
  this.toneMappingFolder.folder.hidden = rendererValues.toneMapping === 5 ? false : true;
2972
3438
  this.export = this.gui.addFolder({ title: "import / export", expanded: false });
2973
- window.addEventListener("keydown", this.processKey.bind(this));
2974
- this.setupRenderPane = this.setupRenderPane.bind(this);
2975
- this.setupGUIListeners.bind(this)();
3439
+ this.setupGUIListeners();
3440
+ window.addEventListener("keydown", (e) => {
3441
+ this.processKey(e);
3442
+ });
2976
3443
  }
2977
3444
  setupGUIListeners() {
2978
3445
  const gui = this.gui;
2979
3446
  const paneElement = gui.containerElem_;
2980
3447
  paneElement.style.right = this.guiVisible ? "0px" : "-450px";
2981
3448
  this.gui.element.addEventListener("mouseenter", () => setTweakpaneActive(true));
3449
+ this.gui.element.addEventListener("mousemove", () => setTweakpaneActive(true));
2982
3450
  this.gui.element.addEventListener("mousedown", () => setTweakpaneActive(true));
2983
- this.gui.element.addEventListener("mouseup", () => setTweakpaneActive(false));
2984
3451
  this.gui.element.addEventListener("mouseleave", () => setTweakpaneActive(false));
3452
+ this.gui.element.addEventListener("mouseup", () => setTweakpaneActive(false));
2985
3453
  }
2986
3454
  processKey(e) {
2987
3455
  if (e.key === "p")
2988
3456
  this.toggleGUI();
2989
3457
  }
2990
- setupRenderPane(composer, normalPass, ppssaoEffect, ppssaoPass, n8aopass, toneMappingEffect, toneMappingPass, brightnessContrastSaturation, bloomEffect, gaussGrainEffect, hasLighting, sun, setHDR, setAmbientLight, setFog) {
3458
+ setupRenderPane(composer, normalPass, ppssaoEffect, ppssaoPass, n8aopass, toneMappingEffect, toneMappingPass, brightnessContrastSaturation, bloomEffect, gaussGrainEffect, hasLighting, sun, setHDR, setSkyboxAzimuthalAngle, setSkyboxPolarAngle, setAmbientLight, setFog) {
2991
3459
  this.rendererFolder.setupChangeEvent(
2992
- this.scene,
2993
3460
  this.renderer,
2994
3461
  this.toneMappingFolder.folder,
2995
3462
  toneMappingPass
@@ -2998,7 +3465,15 @@ var TweakPane = class {
2998
3465
  this.ssaoFolder.setupChangeEvent(composer, normalPass, ppssaoEffect, ppssaoPass, n8aopass);
2999
3466
  this.bcsFolder.setupChangeEvent(brightnessContrastSaturation);
3000
3467
  this.postExtrasFolder.setupChangeEvent(bloomEffect, gaussGrainEffect);
3001
- this.environment.setupChangeEvent(setHDR, setAmbientLight, setFog, sun);
3468
+ this.environment.setupChangeEvent(
3469
+ this.scene,
3470
+ setHDR,
3471
+ setSkyboxAzimuthalAngle,
3472
+ setSkyboxPolarAngle,
3473
+ setAmbientLight,
3474
+ setFog,
3475
+ sun
3476
+ );
3002
3477
  this.environment.folder.hidden = hasLighting === false || sun === null;
3003
3478
  const exportButton = this.export.addButton({ title: "export" });
3004
3479
  exportButton.on("click", () => {
@@ -3011,9 +3486,25 @@ var TweakPane = class {
3011
3486
  });
3012
3487
  });
3013
3488
  }
3489
+ dispose() {
3490
+ this.gui.dispose();
3491
+ this.tweakPaneWrapper.remove();
3492
+ }
3493
+ setupCamPane(cameraManager) {
3494
+ this.camera.setupChangeEvent(cameraManager);
3495
+ }
3496
+ setupCharacterController(localController) {
3497
+ this.characterControls.setupChangeEvent(localController);
3498
+ }
3014
3499
  updateStats(timeManager) {
3015
3500
  this.renderStatsFolder.update(this.renderer, this.composer, timeManager);
3016
3501
  }
3502
+ updateCameraData(cameraManager) {
3503
+ this.camera.update(cameraManager);
3504
+ }
3505
+ updateCharacterData(localController) {
3506
+ this.characterControls.update(localController);
3507
+ }
3017
3508
  formatDateForFilename() {
3018
3509
  const date = /* @__PURE__ */ new Date();
3019
3510
  const year = date.getFullYear();
@@ -3071,35 +3562,37 @@ var TweakPane = class {
3071
3562
  // src/rendering/composer.ts
3072
3563
  import { HDRJPGLoader } from "@monogrid/gainmap-js";
3073
3564
  import {
3565
+ BlendFunction as BlendFunction2,
3566
+ BloomEffect,
3567
+ EdgeDetectionMode,
3074
3568
  EffectComposer as EffectComposer2,
3075
- RenderPass,
3076
3569
  EffectPass as EffectPass2,
3077
3570
  FXAAEffect,
3571
+ NormalPass as NormalPass2,
3572
+ PredicationMode,
3573
+ RenderPass,
3078
3574
  ShaderPass,
3079
- BloomEffect,
3080
- SSAOEffect as SSAOEffect2,
3081
- BlendFunction as BlendFunction2,
3082
- TextureEffect,
3083
- ToneMappingEffect,
3084
3575
  SMAAEffect,
3085
3576
  SMAAPreset,
3086
- EdgeDetectionMode,
3087
- PredicationMode,
3088
- NormalPass as NormalPass2
3577
+ SSAOEffect as SSAOEffect2,
3578
+ TextureEffect,
3579
+ ToneMappingEffect
3089
3580
  } from "postprocessing";
3090
3581
  import {
3091
3582
  AmbientLight,
3092
3583
  Color as Color7,
3584
+ EquirectangularReflectionMapping,
3585
+ Euler as Euler3,
3093
3586
  Fog as Fog2,
3094
3587
  HalfFloatType as HalfFloatType2,
3095
3588
  LinearSRGBColorSpace,
3096
3589
  LoadingManager,
3590
+ MathUtils,
3097
3591
  PMREMGenerator,
3098
- SRGBColorSpace,
3099
3592
  Scene as Scene4,
3593
+ SRGBColorSpace,
3100
3594
  Vector2 as Vector27,
3101
- WebGLRenderer as WebGLRenderer4,
3102
- EquirectangularReflectionMapping
3595
+ WebGLRenderer as WebGLRenderer4
3103
3596
  } from "three";
3104
3597
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
3105
3598
 
@@ -4642,7 +5135,12 @@ var N8SSAOPass = class extends Pass {
4642
5135
 
4643
5136
  // src/rendering/composer.ts
4644
5137
  var Composer = class {
4645
- constructor(scene, camera, spawnSun = false) {
5138
+ constructor({
5139
+ scene,
5140
+ camera,
5141
+ spawnSun = false,
5142
+ environmentConfiguration
5143
+ }) {
4646
5144
  this.width = 1;
4647
5145
  this.height = 1;
4648
5146
  this.resolution = new Vector27(this.width, this.height);
@@ -4651,6 +5149,7 @@ var Composer = class {
4651
5149
  this.gaussGrainEffect = GaussGrainEffect;
4652
5150
  this.ambientLight = null;
4653
5151
  this.sun = null;
5152
+ var _a;
4654
5153
  this.scene = scene;
4655
5154
  this.postPostScene = new Scene4();
4656
5155
  this.camera = camera;
@@ -4666,7 +5165,9 @@ var Composer = class {
4666
5165
  this.renderer.shadowMap.type = rendererValues.shadowMap;
4667
5166
  this.renderer.toneMapping = rendererValues.toneMapping;
4668
5167
  this.renderer.toneMappingExposure = rendererValues.exposure;
4669
- this.setAmbientLight();
5168
+ this.environmentConfiguration = environmentConfiguration;
5169
+ this.updateSkyboxAndEnvValues();
5170
+ this.updateAmbientLightValues();
4670
5171
  this.setFog();
4671
5172
  this.effectComposer = new EffectComposer2(this.renderer, {
4672
5173
  frameBufferType: HalfFloatType2
@@ -4699,6 +5200,9 @@ var Composer = class {
4699
5200
  this.ppssaoPass = new EffectPass2(this.camera, this.ppssaoEffect, this.normalTextureEffect);
4700
5201
  this.ppssaoPass.enabled = ppssaoValues.enabled;
4701
5202
  this.fxaaEffect = new FXAAEffect();
5203
+ if ((_a = environmentConfiguration == null ? void 0 : environmentConfiguration.postProcessing) == null ? void 0 : _a.bloomIntensity) {
5204
+ extrasValues.bloom = environmentConfiguration.postProcessing.bloomIntensity;
5205
+ }
4702
5206
  this.bloomEffect = new BloomEffect({
4703
5207
  intensity: extrasValues.bloom
4704
5208
  });
@@ -4758,6 +5262,7 @@ var Composer = class {
4758
5262
  this.sun = new Sun();
4759
5263
  this.scene.add(this.sun);
4760
5264
  }
5265
+ this.updateSunValues();
4761
5266
  this.resizeListener = () => {
4762
5267
  this.fitContainer();
4763
5268
  };
@@ -4779,12 +5284,21 @@ var Composer = class {
4779
5284
  this.spawnSun,
4780
5285
  this.sun,
4781
5286
  this.setHDRIFromFile.bind(this),
5287
+ (azimuthalAngle) => {
5288
+ envValues.skyboxAzimuthalAngle = azimuthalAngle;
5289
+ this.updateSkyboxRotation();
5290
+ },
5291
+ (polarAngle) => {
5292
+ envValues.skyboxPolarAngle = polarAngle;
5293
+ this.updateSkyboxRotation();
5294
+ },
4782
5295
  this.setAmbientLight.bind(this),
4783
5296
  this.setFog.bind(this)
4784
5297
  );
4785
5298
  }
4786
5299
  dispose() {
4787
5300
  window.removeEventListener("resize", this.resizeListener);
5301
+ this.renderer.dispose();
4788
5302
  }
4789
5303
  fitContainer() {
4790
5304
  if (!this) {
@@ -4833,6 +5347,18 @@ var Composer = class {
4833
5347
  this.renderer.clearDepth();
4834
5348
  this.renderer.render(this.postPostScene, this.camera);
4835
5349
  }
5350
+ updateSkyboxRotation() {
5351
+ this.scene.backgroundRotation = new Euler3(
5352
+ MathUtils.degToRad(envValues.skyboxPolarAngle),
5353
+ MathUtils.degToRad(envValues.skyboxAzimuthalAngle),
5354
+ 0
5355
+ );
5356
+ this.scene.environmentRotation = new Euler3(
5357
+ MathUtils.degToRad(envValues.skyboxPolarAngle),
5358
+ MathUtils.degToRad(envValues.skyboxAzimuthalAngle),
5359
+ 0
5360
+ );
5361
+ }
4836
5362
  useHDRJPG(url, fromFile = false) {
4837
5363
  const pmremGenerator = new PMREMGenerator(this.renderer);
4838
5364
  const hdrJpg = new HDRJPGLoader(this.renderer).load(url, () => {
@@ -4843,8 +5369,21 @@ var Composer = class {
4843
5369
  if (envMap) {
4844
5370
  envMap.colorSpace = LinearSRGBColorSpace;
4845
5371
  envMap.needsUpdate = true;
5372
+ this.scene.environment = envMap;
5373
+ this.scene.environmentIntensity = envValues.envMapIntensity;
5374
+ this.scene.environmentRotation = new Euler3(
5375
+ MathUtils.degToRad(envValues.skyboxPolarAngle),
5376
+ MathUtils.degToRad(envValues.skyboxAzimuthalAngle),
5377
+ 0
5378
+ );
4846
5379
  this.scene.background = envMap;
4847
- this.scene.backgroundIntensity = rendererValues.bgIntensity;
5380
+ this.scene.backgroundIntensity = envValues.skyboxIntensity;
5381
+ this.scene.backgroundBlurriness = envValues.skyboxBlurriness;
5382
+ this.scene.backgroundRotation = new Euler3(
5383
+ MathUtils.degToRad(envValues.skyboxPolarAngle),
5384
+ MathUtils.degToRad(envValues.skyboxAzimuthalAngle),
5385
+ 0
5386
+ );
4848
5387
  this.isEnvHDRI = true;
4849
5388
  hdrJpgEquirectangularMap.dispose();
4850
5389
  pmremGenerator.dispose();
@@ -4853,8 +5392,9 @@ var Composer = class {
4853
5392
  });
4854
5393
  }
4855
5394
  useHDRI(url, fromFile = false) {
4856
- if (this.isEnvHDRI && fromFile === false || !this.renderer)
5395
+ if (this.isEnvHDRI && fromFile === false || !this.renderer) {
4857
5396
  return;
5397
+ }
4858
5398
  const pmremGenerator = new PMREMGenerator(this.renderer);
4859
5399
  new RGBELoader(new LoadingManager()).load(
4860
5400
  url,
@@ -4863,8 +5403,16 @@ var Composer = class {
4863
5403
  if (envMap) {
4864
5404
  envMap.colorSpace = LinearSRGBColorSpace;
4865
5405
  envMap.needsUpdate = true;
5406
+ this.scene.environment = envMap;
5407
+ this.scene.environmentIntensity = envValues.envMapIntensity;
5408
+ this.scene.environmentRotation = new Euler3(
5409
+ MathUtils.degToRad(envValues.skyboxPolarAngle),
5410
+ MathUtils.degToRad(envValues.skyboxAzimuthalAngle),
5411
+ 0
5412
+ );
4866
5413
  this.scene.background = envMap;
4867
- this.scene.backgroundIntensity = rendererValues.bgIntensity;
5414
+ this.scene.backgroundIntensity = envValues.skyboxIntensity;
5415
+ this.scene.backgroundBlurriness = envValues.skyboxBlurriness;
4868
5416
  this.isEnvHDRI = true;
4869
5417
  texture.dispose();
4870
5418
  pmremGenerator.dispose();
@@ -4931,6 +5479,51 @@ var Composer = class {
4931
5479
  );
4932
5480
  this.scene.add(this.ambientLight);
4933
5481
  }
5482
+ updateSunValues() {
5483
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
5484
+ if (typeof ((_b = (_a = this.environmentConfiguration) == null ? void 0 : _a.sun) == null ? void 0 : _b.intensity) === "number") {
5485
+ sunValues.sunIntensity = this.environmentConfiguration.sun.intensity;
5486
+ (_c = this.sun) == null ? void 0 : _c.setIntensity(this.environmentConfiguration.sun.intensity);
5487
+ }
5488
+ if (typeof ((_e = (_d = this.environmentConfiguration) == null ? void 0 : _d.sun) == null ? void 0 : _e.azimuthalAngle) === "number") {
5489
+ sunValues.sunPosition.sunAzimuthalAngle = this.environmentConfiguration.sun.azimuthalAngle;
5490
+ (_f = this.sun) == null ? void 0 : _f.setAzimuthalAngle(this.environmentConfiguration.sun.azimuthalAngle);
5491
+ }
5492
+ if (typeof ((_h = (_g = this.environmentConfiguration) == null ? void 0 : _g.sun) == null ? void 0 : _h.polarAngle) === "number") {
5493
+ sunValues.sunPosition.sunPolarAngle = this.environmentConfiguration.sun.polarAngle;
5494
+ (_i = this.sun) == null ? void 0 : _i.setPolarAngle(this.environmentConfiguration.sun.polarAngle);
5495
+ }
5496
+ }
5497
+ updateSkyboxAndEnvValues() {
5498
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
5499
+ if (typeof ((_b = (_a = this.environmentConfiguration) == null ? void 0 : _a.envMap) == null ? void 0 : _b.intensity) === "number") {
5500
+ envValues.envMapIntensity = (_c = this.environmentConfiguration) == null ? void 0 : _c.envMap.intensity;
5501
+ }
5502
+ this.scene.environmentIntensity = envValues.envMapIntensity;
5503
+ if (typeof ((_e = (_d = this.environmentConfiguration) == null ? void 0 : _d.skybox) == null ? void 0 : _e.intensity) === "number") {
5504
+ envValues.skyboxIntensity = (_f = this.environmentConfiguration) == null ? void 0 : _f.skybox.intensity;
5505
+ }
5506
+ this.scene.backgroundIntensity = envValues.skyboxIntensity;
5507
+ if (typeof ((_h = (_g = this.environmentConfiguration) == null ? void 0 : _g.skybox) == null ? void 0 : _h.blurriness) === "number") {
5508
+ envValues.skyboxBlurriness = (_i = this.environmentConfiguration) == null ? void 0 : _i.skybox.blurriness;
5509
+ }
5510
+ this.scene.backgroundBlurriness = envValues.skyboxBlurriness;
5511
+ if (typeof ((_k = (_j = this.environmentConfiguration) == null ? void 0 : _j.skybox) == null ? void 0 : _k.azimuthalAngle) === "number") {
5512
+ envValues.skyboxAzimuthalAngle = (_l = this.environmentConfiguration) == null ? void 0 : _l.skybox.azimuthalAngle;
5513
+ this.updateSkyboxRotation();
5514
+ }
5515
+ if (typeof ((_n = (_m = this.environmentConfiguration) == null ? void 0 : _m.skybox) == null ? void 0 : _n.polarAngle) === "number") {
5516
+ envValues.skyboxPolarAngle = (_o = this.environmentConfiguration) == null ? void 0 : _o.skybox.polarAngle;
5517
+ this.updateSkyboxRotation();
5518
+ }
5519
+ }
5520
+ updateAmbientLightValues() {
5521
+ var _a, _b;
5522
+ if (typeof ((_b = (_a = this.environmentConfiguration) == null ? void 0 : _a.ambientLight) == null ? void 0 : _b.intensity) === "number") {
5523
+ envValues.ambientLight.ambientLightIntensity = this.environmentConfiguration.ambientLight.intensity;
5524
+ }
5525
+ this.setAmbientLight();
5526
+ }
4934
5527
  };
4935
5528
 
4936
5529
  // src/time/TimeManager.ts
@@ -4988,7 +5581,7 @@ import {
4988
5581
  Box3,
4989
5582
  Color as Color8,
4990
5583
  DoubleSide,
4991
- Euler as Euler3,
5584
+ Euler as Euler4,
4992
5585
  Group as Group5,
4993
5586
  Line3 as Line32,
4994
5587
  Matrix4 as Matrix46,
@@ -4996,7 +5589,7 @@ import {
4996
5589
  MeshBasicMaterial as MeshBasicMaterial3,
4997
5590
  Quaternion as Quaternion6,
4998
5591
  Ray as Ray2,
4999
- Vector3 as Vector315
5592
+ Vector3 as Vector314
5000
5593
  } from "three";
5001
5594
  import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
5002
5595
  import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
@@ -5004,15 +5597,15 @@ import { MeshBVH, MeshBVHHelper } from "three-mesh-bvh";
5004
5597
  var CollisionsManager = class {
5005
5598
  constructor(scene) {
5006
5599
  this.debug = false;
5007
- this.tempVector = new Vector315();
5008
- this.tempVector2 = new Vector315();
5009
- this.tempVector3 = new Vector315();
5600
+ this.tempVector = new Vector314();
5601
+ this.tempVector2 = new Vector314();
5602
+ this.tempVector3 = new Vector314();
5010
5603
  this.tempQuaternion = new Quaternion6();
5011
5604
  this.tempRay = new Ray2();
5012
5605
  this.tempMatrix = new Matrix46();
5013
5606
  this.tempMatrix2 = new Matrix46();
5014
5607
  this.tempBox = new Box3();
5015
- this.tempEuler = new Euler3();
5608
+ this.tempEuler = new Euler4();
5016
5609
  this.tempSegment = new Line32();
5017
5610
  this.tempSegment2 = new Line32();
5018
5611
  this.collisionMeshState = /* @__PURE__ */ new Map();
@@ -5022,7 +5615,7 @@ var CollisionsManager = class {
5022
5615
  raycastFirst(ray) {
5023
5616
  let minimumDistance = null;
5024
5617
  let minimumHit = null;
5025
- let minimumNormal = new Vector315();
5618
+ let minimumNormal = new Vector314();
5026
5619
  for (const [, collisionMeshState] of this.collisionMeshState) {
5027
5620
  this.tempRay.copy(ray).applyMatrix4(this.tempMatrix.copy(collisionMeshState.matrix).invert());
5028
5621
  const hit = collisionMeshState.meshBVH.raycastFirst(this.tempRay, DoubleSide);
@@ -5163,7 +5756,7 @@ var CollisionsManager = class {
5163
5756
  const realDistance = intersectionSegment.distance();
5164
5757
  if (realDistance < capsuleRadius) {
5165
5758
  if (!collisionPosition) {
5166
- collisionPosition = new Vector315().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
5759
+ collisionPosition = new Vector314().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
5167
5760
  }
5168
5761
  const ratio = realDistance / modelReferenceDistance;
5169
5762
  const realDepth = capsuleRadius - realDistance;
@@ -5218,13 +5811,13 @@ var CollisionsManager = class {
5218
5811
  // src/ground-plane/GroundPlane.ts
5219
5812
  import {
5220
5813
  CanvasTexture,
5221
- CircleGeometry as CircleGeometry2,
5222
5814
  FrontSide as FrontSide2,
5223
5815
  Group as Group6,
5224
5816
  LinearMipMapLinearFilter,
5225
5817
  Mesh as Mesh6,
5226
5818
  MeshStandardMaterial as MeshStandardMaterial3,
5227
5819
  NearestFilter as NearestFilter2,
5820
+ PlaneGeometry as PlaneGeometry2,
5228
5821
  RepeatWrapping as RepeatWrapping2
5229
5822
  } from "three";
5230
5823
  var canvas = document.createElement("canvas");
@@ -5241,7 +5834,7 @@ var GroundPlane = class extends Group6 {
5241
5834
  super();
5242
5835
  this.floorSize = 210;
5243
5836
  this.floorTexture = null;
5244
- this.floorGeometry = new CircleGeometry2(this.floorSize, this.floorSize);
5837
+ this.floorGeometry = new PlaneGeometry2(this.floorSize, this.floorSize, 1, 1);
5245
5838
  this.floorMesh = null;
5246
5839
  this.floorMaterial = new MeshStandardMaterial3({
5247
5840
  color: 16777215,
@@ -5270,6 +5863,7 @@ var LoadingScreen = class {
5270
5863
  constructor(loadingProgressManager) {
5271
5864
  this.loadingProgressManager = loadingProgressManager;
5272
5865
  this.hasCompleted = false;
5866
+ this.disposed = false;
5273
5867
  this.element = document.createElement("div");
5274
5868
  this.element.style.position = "absolute";
5275
5869
  this.element.style.top = "0";
@@ -5404,10 +5998,47 @@ var LoadingScreen = class {
5404
5998
  this.loadingProgressManager.addProgressCallback(this.loadingCallback);
5405
5999
  }
5406
6000
  dispose() {
6001
+ if (this.disposed) {
6002
+ return;
6003
+ }
6004
+ this.disposed = true;
5407
6005
  this.loadingProgressManager.removeProgressCallback(this.loadingCallback);
5408
6006
  this.element.remove();
5409
6007
  }
5410
6008
  };
6009
+
6010
+ // src/error-screen/ErrorScreen.ts
6011
+ var ErrorScreen = class {
6012
+ constructor(title, message) {
6013
+ this.element = document.createElement("div");
6014
+ this.element.style.position = "absolute";
6015
+ this.element.style.top = "0";
6016
+ this.element.style.left = "0";
6017
+ this.element.style.display = "flex";
6018
+ this.element.style.alignItems = "center";
6019
+ this.element.style.justifyContent = "center";
6020
+ this.element.style.flexDirection = "column";
6021
+ this.element.style.width = "100%";
6022
+ this.element.style.height = "100%";
6023
+ this.element.style.background = "linear-gradient(45deg, #111111 0%, #444444 100%)";
6024
+ this.element.style.color = "white";
6025
+ this.titleBannerText = document.createElement("div");
6026
+ this.titleBannerText.textContent = title;
6027
+ this.titleBannerText.style.fontSize = "40px";
6028
+ this.titleBannerText.style.fontWeight = "bold";
6029
+ this.titleBannerText.style.fontFamily = "sans-serif";
6030
+ this.element.append(this.titleBannerText);
6031
+ this.messageText = document.createElement("div");
6032
+ this.messageText.style.textAlign = "center";
6033
+ this.messageText.style.fontFamily = "sans-serif";
6034
+ this.messageText.style.fontWeight = "bold";
6035
+ this.messageText.textContent = message;
6036
+ this.element.append(this.messageText);
6037
+ }
6038
+ dispose() {
6039
+ this.element.remove();
6040
+ }
6041
+ };
5411
6042
  export {
5412
6043
  AnimationState,
5413
6044
  CameraManager,
@@ -5415,6 +6046,7 @@ export {
5415
6046
  CharacterModelLoader,
5416
6047
  CollisionsManager,
5417
6048
  Composer,
6049
+ ErrorScreen,
5418
6050
  GroundPlane,
5419
6051
  KeyInputManager,
5420
6052
  LoadingScreen,