@mml-io/3d-web-client-core 0.15.0 → 0.16.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
@@ -83,8 +83,9 @@ var EventHandlerCollection = class _EventHandlerCollection {
83
83
  };
84
84
 
85
85
  // src/input/VirtualJoystick.ts
86
- var _VirtualJoystick = class _VirtualJoystick {
87
- constructor(attrs) {
86
+ var VirtualJoystick = class _VirtualJoystick {
87
+ constructor(holderElement, attrs) {
88
+ this.holderElement = holderElement;
88
89
  this.left = false;
89
90
  this.right = false;
90
91
  this.up = false;
@@ -107,7 +108,23 @@ var _VirtualJoystick = class _VirtualJoystick {
107
108
  this.width = attrs.width || this.radius * 2 + this.inner_radius * 2;
108
109
  this.height = attrs.height || this.radius * 2 + this.inner_radius * 2;
109
110
  this.mouse_support = this.checkTouch() || attrs.mouse_support === true;
110
- this.initializeJoystick();
111
+ this.div = document.createElement("div");
112
+ const divStyle = this.div.style;
113
+ divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none";
114
+ divStyle.position = "fixed";
115
+ if (this.anchor === "left") {
116
+ divStyle.left = `${this.x}px`;
117
+ } else {
118
+ divStyle.right = `${this.x}px`;
119
+ }
120
+ divStyle.bottom = `${this.y}px`;
121
+ divStyle.width = `${this.width}px`;
122
+ divStyle.height = `${this.height}px`;
123
+ divStyle.zIndex = "10000";
124
+ divStyle.overflow = "hidden";
125
+ this.holderElement.appendChild(this.div);
126
+ this.setupBaseAndControl();
127
+ this.bindEvents();
111
128
  }
112
129
  static checkForTouch() {
113
130
  try {
@@ -117,38 +134,9 @@ var _VirtualJoystick = class _VirtualJoystick {
117
134
  return false;
118
135
  }
119
136
  }
120
- static isTouchOnJoystick(touch) {
121
- if (!_VirtualJoystick.JOYSTICK_DIV) {
122
- return false;
123
- }
124
- const divRect = _VirtualJoystick.JOYSTICK_DIV.getBoundingClientRect();
125
- return touch.clientX >= divRect.left && touch.clientX <= divRect.right && touch.clientY >= divRect.top && touch.clientY <= divRect.bottom;
126
- }
127
137
  checkTouch() {
128
138
  return _VirtualJoystick.checkForTouch();
129
139
  }
130
- initializeJoystick() {
131
- if (!_VirtualJoystick.JOYSTICK_DIV) {
132
- this.div = document.createElement("div");
133
- const divStyle = this.div.style;
134
- divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none";
135
- divStyle.position = "fixed";
136
- if (this.anchor === "left") {
137
- divStyle.left = `${this.x}px`;
138
- } else {
139
- divStyle.right = `${this.x}px`;
140
- }
141
- divStyle.bottom = `${this.y}px`;
142
- divStyle.width = `${this.width}px`;
143
- divStyle.height = `${this.height}px`;
144
- divStyle.zIndex = "10000";
145
- divStyle.overflow = "hidden";
146
- document.body.appendChild(this.div);
147
- _VirtualJoystick.JOYSTICK_DIV = this.div;
148
- }
149
- this.setupBaseAndControl();
150
- this.bindEvents();
151
- }
152
140
  setupBaseAndControl() {
153
141
  this.base = document.createElement("span");
154
142
  let divStyle = this.base.style;
@@ -188,6 +176,7 @@ var _VirtualJoystick = class _VirtualJoystick {
188
176
  }
189
177
  handleTouchStart(evt) {
190
178
  evt.preventDefault();
179
+ evt.stopPropagation();
191
180
  if (evt.touches) {
192
181
  const touch = evt.touches[0];
193
182
  this.updateControlAndDirection(touch);
@@ -195,6 +184,7 @@ var _VirtualJoystick = class _VirtualJoystick {
195
184
  }
196
185
  handleTouchMove(evt) {
197
186
  evt.preventDefault();
187
+ evt.stopPropagation();
198
188
  if (evt.touches.length > 0) {
199
189
  const touch = evt.touches[0];
200
190
  this.updateControlAndDirection(touch);
@@ -202,11 +192,13 @@ var _VirtualJoystick = class _VirtualJoystick {
202
192
  }
203
193
  handleMouseDown(evt) {
204
194
  evt.preventDefault();
195
+ evt.stopPropagation();
205
196
  this.updateControlAndDirection(evt);
206
197
  }
207
198
  handleMouseMove(evt) {
208
199
  if (evt.buttons === 1) {
209
200
  evt.preventDefault();
201
+ evt.stopPropagation();
210
202
  this.updateControlAndDirection(evt);
211
203
  }
212
204
  }
@@ -242,8 +234,6 @@ var _VirtualJoystick = class _VirtualJoystick {
242
234
  return dx > 0 && Math.abs(dy) <= 2 * Math.abs(dx);
243
235
  }
244
236
  };
245
- _VirtualJoystick.JOYSTICK_DIV = null;
246
- var VirtualJoystick = _VirtualJoystick;
247
237
 
248
238
  // src/tweakpane/tweakPaneActivity.ts
249
239
  var isTweakpaneActive = false;
@@ -289,7 +279,7 @@ var CameraManager = class {
289
279
  this.targetPhi = initialPhi;
290
280
  this.theta = initialTheta;
291
281
  this.targetTheta = initialTheta;
292
- this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
282
+ this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 300);
293
283
  this.camera.position.set(0, 1.4, -this.initialDistance);
294
284
  this.rayCaster = new Raycaster();
295
285
  this.hasTouchControl = VirtualJoystick.checkForTouch();
@@ -313,11 +303,9 @@ var CameraManager = class {
313
303
  }
314
304
  onTouchStart(evt) {
315
305
  Array.from(evt.touches).forEach((touch) => {
316
- if (!VirtualJoystick.isTouchOnJoystick(touch)) {
317
- this.dragging = true;
318
- this.lastTouchX = touch.clientX;
319
- this.lastTouchY = touch.clientY;
320
- }
306
+ this.dragging = true;
307
+ this.lastTouchX = touch.clientX;
308
+ this.lastTouchY = touch.clientY;
321
309
  });
322
310
  }
323
311
  onTouchMove(evt) {
@@ -325,7 +313,7 @@ var CameraManager = class {
325
313
  return;
326
314
  }
327
315
  evt.preventDefault();
328
- const touch = Array.from(evt.touches).find((t) => !VirtualJoystick.isTouchOnJoystick(t));
316
+ const touch = Array.from(evt.touches).find((t) => true);
329
317
  if (touch) {
330
318
  const dx = touch.clientX - this.lastTouchX;
331
319
  const dy = touch.clientY - this.lastTouchY;
@@ -340,9 +328,7 @@ var CameraManager = class {
340
328
  }
341
329
  onTouchEnd(evt) {
342
330
  if (this.dragging) {
343
- const touchEnded = Array.from(evt.changedTouches).some(
344
- (t) => !VirtualJoystick.isTouchOnJoystick(t)
345
- );
331
+ const touchEnded = Array.from(evt.changedTouches).some((t) => true);
346
332
  if (touchEnded) {
347
333
  this.dragging = false;
348
334
  }
@@ -478,9 +464,9 @@ import { Color as Color3, Group, Vector3 as Vector34 } from "three";
478
464
  // src/character/CharacterModel.ts
479
465
  import {
480
466
  MMLCharacter,
481
- ModelLoader,
482
467
  parseMMLDescription
483
468
  } from "@mml-io/3d-web-avatar";
469
+ import { ModelLoader } from "@mml-io/model-loader";
484
470
  import {
485
471
  AnimationClip,
486
472
  AnimationMixer,
@@ -634,13 +620,9 @@ var CharacterFolder = class {
634
620
 
635
621
  // src/character/CharacterMaterial.ts
636
622
  var CharacterMaterial = class extends MeshStandardMaterial {
637
- constructor(isLocal, cameraManager, characterId, originalMaterial, colorOverride) {
623
+ constructor(config) {
638
624
  super();
639
- this.isLocal = isLocal;
640
- this.cameraManager = cameraManager;
641
- this.characterId = characterId;
642
- this.originalMaterial = originalMaterial;
643
- this.colorOverride = colorOverride;
625
+ this.config = config;
644
626
  this.uniforms = {
645
627
  discardAll: { value: 1 },
646
628
  diffuseColor: { value: new Color() },
@@ -649,12 +631,12 @@ var CharacterMaterial = class extends MeshStandardMaterial {
649
631
  this.colorsCube216 = [];
650
632
  this.targetAlpha = 1;
651
633
  this.currentAlpha = 1;
652
- this.copy(this.originalMaterial);
634
+ this.copy(this.config.originalMaterial);
653
635
  this.generateColorCube();
654
- this.color = this.colorOverride || this.colorsCube216[this.characterId];
636
+ this.color = this.config.colorOverride || this.colorsCube216[this.config.characterId];
655
637
  this.envMapIntensity = characterValues.envMapIntensity;
656
638
  this.transparent = true;
657
- this.side = this.originalMaterial.side;
639
+ this.side = this.config.originalMaterial.side;
658
640
  this.onBeforeCompile = (shader) => {
659
641
  this.uniforms = UniformsUtils.clone(shader.uniforms);
660
642
  this.uniforms.nearClip = { value: 0.01 };
@@ -690,7 +672,7 @@ var CharacterMaterial = class extends MeshStandardMaterial {
690
672
  );
691
673
  shader.fragmentShader = injectBefore(
692
674
  shader.fragmentShader,
693
- "#include <output_fragment>",
675
+ "#include <dithering_fragment>",
694
676
  /* glsl */
695
677
  `
696
678
  if (discardAll == 1) {
@@ -730,16 +712,16 @@ var CharacterMaterial = class extends MeshStandardMaterial {
730
712
  }
731
713
  }
732
714
  update() {
733
- if (this.isLocal) {
734
- this.targetAlpha = this.cameraManager.targetDistance < 0.4 ? 0 : 1;
715
+ if (this.config.isLocal) {
716
+ this.targetAlpha = this.config.cameraManager.targetDistance < 0.4 ? 0 : 1;
735
717
  this.currentAlpha += ease(this.targetAlpha, this.currentAlpha, 0.07);
736
718
  if (this.currentAlpha > 0.999) {
737
719
  this.currentAlpha = 1;
738
- this.cameraManager.minPolarAngle = Math.PI * 0.25;
720
+ this.config.cameraManager.minPolarAngle = Math.PI * 0.25;
739
721
  }
740
722
  if (this.currentAlpha < 1e-3) {
741
723
  this.currentAlpha = 0;
742
- this.cameraManager.minPolarAngle = Math.PI * 0.35;
724
+ this.config.cameraManager.minPolarAngle = Math.PI * 0.35;
743
725
  }
744
726
  this.uniforms.discardAll.value = this.currentAlpha === 0 ? 1 : 0;
745
727
  if (this.currentAlpha !== this.opacity) {
@@ -770,14 +752,9 @@ var AnimationState = /* @__PURE__ */ ((AnimationState2) => {
770
752
  })(AnimationState || {});
771
753
 
772
754
  // src/character/CharacterModel.ts
773
- var CharacterModel = class {
774
- constructor(characterDescription, animationConfig, characterModelLoader, cameraManager, characterId, isLocal) {
775
- this.characterDescription = characterDescription;
776
- this.animationConfig = animationConfig;
777
- this.characterModelLoader = characterModelLoader;
778
- this.cameraManager = cameraManager;
779
- this.characterId = characterId;
780
- this.isLocal = isLocal;
755
+ var _CharacterModel = class _CharacterModel {
756
+ constructor(config) {
757
+ this.config = config;
781
758
  this.mesh = null;
782
759
  this.headBone = null;
783
760
  this.materials = /* @__PURE__ */ new Map();
@@ -787,40 +764,51 @@ var CharacterModel = class {
787
764
  }
788
765
  async init() {
789
766
  await this.loadMainMesh();
790
- await this.setAnimationFromFile(this.animationConfig.idleAnimationFileUrl, 0 /* idle */);
791
767
  await this.setAnimationFromFile(
792
- this.animationConfig.jogAnimationFileUrl,
768
+ this.config.animationConfig.idleAnimationFileUrl,
769
+ 0 /* idle */
770
+ );
771
+ await this.setAnimationFromFile(
772
+ this.config.animationConfig.jogAnimationFileUrl,
793
773
  1 /* walking */
794
774
  );
795
775
  await this.setAnimationFromFile(
796
- this.animationConfig.sprintAnimationFileUrl,
776
+ this.config.animationConfig.sprintAnimationFileUrl,
797
777
  2 /* running */
798
778
  );
799
- await this.setAnimationFromFile(this.animationConfig.airAnimationFileUrl, 4 /* air */);
779
+ await this.setAnimationFromFile(
780
+ this.config.animationConfig.airAnimationFileUrl,
781
+ 4 /* air */
782
+ );
800
783
  this.applyCustomMaterials();
801
784
  }
802
785
  applyCustomMaterials() {
803
786
  if (!this.mesh)
804
787
  return;
805
788
  this.mesh.traverse((child) => {
789
+ if (child.isBone) {
790
+ if (child.name === "head") {
791
+ this.headBone = child;
792
+ }
793
+ }
806
794
  if (child.isMesh || child.isSkinnedMesh) {
807
795
  const asMesh = child;
808
796
  const originalMaterial = asMesh.material;
809
797
  if (this.materials.has(originalMaterial.name)) {
810
798
  asMesh.material = this.materials.get(originalMaterial.name);
811
799
  } else {
812
- const material = originalMaterial.name === "body_replaceable_color" ? new CharacterMaterial(
813
- this.isLocal,
814
- this.cameraManager,
815
- this.characterId,
800
+ const material = originalMaterial.name === "body_replaceable_color" ? new CharacterMaterial({
801
+ isLocal: this.config.isLocal,
802
+ cameraManager: this.config.cameraManager,
803
+ characterId: this.config.characterId,
816
804
  originalMaterial
817
- ) : new CharacterMaterial(
818
- this.isLocal,
819
- this.cameraManager,
820
- this.characterId,
805
+ }) : new CharacterMaterial({
806
+ isLocal: this.config.isLocal,
807
+ cameraManager: this.config.cameraManager,
808
+ characterId: this.config.characterId,
821
809
  originalMaterial,
822
- originalMaterial.color
823
- );
810
+ colorOverride: originalMaterial.color
811
+ });
824
812
  this.materials.set(originalMaterial.name, material);
825
813
  asMesh.material = material;
826
814
  }
@@ -847,7 +835,7 @@ var CharacterModel = class {
847
835
  var _a, _b;
848
836
  if (((_a = mmlCharacterDescription.base) == null ? void 0 : _a.url.length) === 0) {
849
837
  throw new Error(
850
- "ERROR: An MML Character Description was provided but it's not a valid <m-character> string, or a valid URL"
838
+ "ERROR: An MML Character Description was provided, but it's not a valid <m-character> string, or a valid URL"
851
839
  );
852
840
  }
853
841
  let mergedCharacter = null;
@@ -855,27 +843,30 @@ var CharacterModel = class {
855
843
  const characterBase = ((_b = mmlCharacterDescription.base) == null ? void 0 : _b.url) || null;
856
844
  if (characterBase) {
857
845
  this.mmlCharacterDescription = mmlCharacterDescription;
858
- const mmlCharacter = new MMLCharacter(new ModelLoader());
846
+ const mmlCharacter = new MMLCharacter(_CharacterModel.ModelLoader);
859
847
  mergedCharacter = await mmlCharacter.mergeBodyParts(
860
848
  characterBase,
861
849
  mmlCharacterDescription.parts
862
850
  );
863
851
  if (mergedCharacter) {
864
- return mergedCharacter.children[0].children[0];
852
+ return mergedCharacter;
865
853
  }
866
854
  }
867
855
  }
868
856
  }
869
857
  async loadCharacterFromDescription() {
870
- if (this.characterDescription.meshFileUrl) {
871
- return await this.characterModelLoader.load(this.characterDescription.meshFileUrl, "model") || null;
858
+ if (this.config.characterDescription.meshFileUrl) {
859
+ return await this.config.characterModelLoader.load(
860
+ this.config.characterDescription.meshFileUrl,
861
+ "model"
862
+ ) || null;
872
863
  }
873
864
  let mmlCharacterSource;
874
- if (this.characterDescription.mmlCharacterUrl) {
875
- const res = await fetch(this.characterDescription.mmlCharacterUrl);
865
+ if (this.config.characterDescription.mmlCharacterUrl) {
866
+ const res = await fetch(this.config.characterDescription.mmlCharacterUrl);
876
867
  mmlCharacterSource = await res.text();
877
- } else if (this.characterDescription.mmlCharacterString) {
878
- mmlCharacterSource = this.characterDescription.mmlCharacterString;
868
+ } else if (this.config.characterDescription.mmlCharacterString) {
869
+ mmlCharacterSource = this.config.characterDescription.mmlCharacterString;
879
870
  } else {
880
871
  throw new Error(
881
872
  "ERROR: No Character Description was provided. Specify one of meshFileUrl, mmlCharacterUrl or mmlCharacterString"
@@ -917,7 +908,7 @@ var CharacterModel = class {
917
908
  }
918
909
  async setAnimationFromFile(animationFileUrl, animationType) {
919
910
  return new Promise(async (resolve, reject) => {
920
- const animation = await this.characterModelLoader.load(animationFileUrl, "animation");
911
+ const animation = await this.config.characterModelLoader.load(animationFileUrl, "animation");
921
912
  const cleanAnimation = this.cleanAnimationClips(this.mesh, animation);
922
913
  if (typeof animation !== "undefined" && cleanAnimation instanceof AnimationClip) {
923
914
  this.animations[animationType] = this.animationMixer.clipAction(cleanAnimation);
@@ -956,6 +947,8 @@ var CharacterModel = class {
956
947
  }
957
948
  }
958
949
  };
950
+ _CharacterModel.ModelLoader = new ModelLoader();
951
+ var CharacterModel = _CharacterModel;
959
952
 
960
953
  // src/character/CharacterSpeakingIndicator.ts
961
954
  import {
@@ -1031,7 +1024,7 @@ var CharacterSpeakingIndicator = class {
1031
1024
  this.scene.add(this.mesh);
1032
1025
  }
1033
1026
  setBillboarding(position, camera) {
1034
- this.mesh.position.set(position.x, position.y - 0.15, position.z);
1027
+ this.mesh.position.set(position.x, position.y, position.z);
1035
1028
  this.mesh.lookAt(camera.position);
1036
1029
  }
1037
1030
  setTime(value) {
@@ -1116,27 +1109,27 @@ function CanvasText(message, options) {
1116
1109
  const padding = options.paddingPx || 0;
1117
1110
  const font = options.font || "Arial";
1118
1111
  const fontString = (options.bold ? "bold " : "") + fontsize + "px " + font;
1119
- const canvas = document.createElement("canvas");
1120
- const ct = canvas.getContext("2d");
1112
+ const canvas2 = document.createElement("canvas");
1113
+ const ct = canvas2.getContext("2d");
1121
1114
  const textAlign = options.alignment ?? "left";
1122
1115
  if (options.dimensions) {
1123
- canvas.width = options.dimensions.width;
1124
- canvas.height = options.dimensions.height;
1125
- ct.clearRect(0, 0, canvas.width, canvas.height);
1116
+ canvas2.width = options.dimensions.width;
1117
+ canvas2.height = options.dimensions.height;
1118
+ ct.clearRect(0, 0, canvas2.width, canvas2.height);
1126
1119
  ct.font = fontString;
1127
1120
  ct.textAlign = textAlign;
1128
1121
  ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1129
1122
  ct.lineWidth = 0;
1130
- ct.fillRect(0, 0, canvas.width, canvas.height);
1123
+ ct.fillRect(0, 0, canvas2.width, canvas2.height);
1131
1124
  ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1132
1125
  ct.font = fontString;
1133
1126
  printAtWordWrap(
1134
1127
  ct,
1135
1128
  message,
1136
- getTextAlignOffset(textAlign, canvas.width),
1129
+ getTextAlignOffset(textAlign, canvas2.width),
1137
1130
  fontsize,
1138
1131
  fontsize,
1139
- canvas.width,
1132
+ canvas2.width,
1140
1133
  padding,
1141
1134
  textAlign
1142
1135
  );
@@ -1145,28 +1138,28 @@ function CanvasText(message, options) {
1145
1138
  const metrics = ct.measureText(message);
1146
1139
  const textWidth = metrics.width;
1147
1140
  const textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
1148
- canvas.width = textWidth + padding * 2;
1149
- canvas.height = textHeight + padding;
1150
- ct.clearRect(0, 0, canvas.width, canvas.height);
1141
+ canvas2.width = textWidth + padding * 2;
1142
+ canvas2.height = textHeight + padding;
1143
+ ct.clearRect(0, 0, canvas2.width, canvas2.height);
1151
1144
  ct.font = fontString;
1152
1145
  ct.textAlign = textAlign;
1153
1146
  ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1154
1147
  ct.lineWidth = 0;
1155
- ct.fillRect(0, 0, canvas.width, canvas.height);
1148
+ ct.fillRect(0, 0, canvas2.width, canvas2.height);
1156
1149
  ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1157
1150
  ct.font = fontString;
1158
1151
  ct.fillText(message, padding + getTextAlignOffset(textAlign, textWidth), textHeight);
1159
1152
  }
1160
- return canvas;
1153
+ return canvas2;
1161
1154
  }
1162
1155
  function THREECanvasTextTexture(text, options) {
1163
- const canvas = CanvasText(text, options);
1164
- const texture = new Texture2(canvas);
1156
+ const canvas2 = CanvasText(text, options);
1157
+ const texture = new Texture2(canvas2);
1165
1158
  texture.minFilter = LinearFilter;
1166
1159
  texture.magFilter = LinearFilter;
1167
1160
  texture.format = RGBAFormat;
1168
1161
  texture.needsUpdate = true;
1169
- return { texture, width: canvas.width, height: canvas.height };
1162
+ return { texture, width: canvas2.width, height: canvas2.height };
1170
1163
  }
1171
1164
 
1172
1165
  // src/character/CharacterTooltip.ts
@@ -1175,20 +1168,19 @@ var defaultLabelColor = new Color2(0);
1175
1168
  var defaultFontColor = new Color2(16777215);
1176
1169
  var defaultLabelAlignment = "center" /* center */;
1177
1170
  var defaultLabelFontSize = 8;
1178
- var defaultLabelPadding = 0;
1171
+ var defaultLabelPadding = 8;
1179
1172
  var defaultLabelWidth = 0.25;
1180
1173
  var defaultLabelHeight = 0.1;
1181
1174
  var defaultLabelCastShadows = true;
1182
1175
  var tooltipGeometry = new PlaneGeometry(1, 1, 1, 1);
1183
1176
  var CharacterTooltip = class extends Mesh3 {
1184
- constructor() {
1177
+ constructor(configArg) {
1185
1178
  super(tooltipGeometry);
1186
1179
  this.visibleOpacity = 0.85;
1187
1180
  this.targetOpacity = 0;
1188
1181
  this.fadingSpeed = 0.02;
1189
1182
  this.secondsToFadeOut = 10;
1190
- this.props = {
1191
- content: "",
1183
+ this.config = {
1192
1184
  alignment: defaultLabelAlignment,
1193
1185
  width: defaultLabelWidth,
1194
1186
  height: defaultLabelHeight,
@@ -1196,7 +1188,8 @@ var CharacterTooltip = class extends Mesh3 {
1196
1188
  padding: defaultLabelPadding,
1197
1189
  color: defaultLabelColor,
1198
1190
  fontColor: defaultFontColor,
1199
- castShadows: defaultLabelCastShadows
1191
+ castShadows: defaultLabelCastShadows,
1192
+ ...configArg
1200
1193
  };
1201
1194
  this.tooltipMaterial = new MeshBasicMaterial2({
1202
1195
  map: null,
@@ -1217,25 +1210,21 @@ var CharacterTooltip = class extends Mesh3 {
1217
1210
  }
1218
1211
  const { texture, width, height } = THREECanvasTextTexture(content, {
1219
1212
  bold: true,
1220
- fontSize: this.props.fontSize * fontScale,
1221
- paddingPx: this.props.padding,
1213
+ fontSize: this.config.fontSize * fontScale,
1214
+ paddingPx: this.config.padding,
1222
1215
  textColorRGB255A1: {
1223
- r: this.props.fontColor.r * 255,
1224
- g: this.props.fontColor.g * 255,
1225
- b: this.props.fontColor.b * 255,
1216
+ r: this.config.fontColor.r * 255,
1217
+ g: this.config.fontColor.g * 255,
1218
+ b: this.config.fontColor.b * 255,
1226
1219
  a: 1
1227
1220
  },
1228
1221
  backgroundColorRGB255A1: {
1229
- r: this.props.color.r * 255,
1230
- g: this.props.color.g * 255,
1231
- b: this.props.color.b * 255,
1222
+ r: this.config.color.r * 255,
1223
+ g: this.config.color.g * 255,
1224
+ b: this.config.color.b * 255,
1232
1225
  a: 1
1233
1226
  },
1234
- dimensions: {
1235
- width: this.props.width * (100 * fontScale),
1236
- height: this.props.height * (100 * fontScale)
1237
- },
1238
- alignment: this.props.alignment
1227
+ alignment: this.config.alignment
1239
1228
  });
1240
1229
  this.tooltipMaterial.map = texture;
1241
1230
  this.tooltipMaterial.map.magFilter = LinearFilter2;
@@ -1246,7 +1235,8 @@ var CharacterTooltip = class extends Mesh3 {
1246
1235
  this.position.y = 1.4;
1247
1236
  }
1248
1237
  setText(text, temporary = false) {
1249
- this.redrawText(text);
1238
+ const sanitizedText = text.replace(/(\r\n|\n|\r)/gm, "");
1239
+ this.redrawText(sanitizedText);
1250
1240
  this.visible = true;
1251
1241
  this.targetOpacity = this.visibleOpacity;
1252
1242
  if (temporary) {
@@ -1287,39 +1277,43 @@ var CharacterTooltip = class extends Mesh3 {
1287
1277
 
1288
1278
  // src/character/Character.ts
1289
1279
  var Character = class extends Group {
1290
- constructor(characterDescription, animationConfig, characterModelLoader, characterId, modelLoadedCallback, cameraManager, composer, isLocal) {
1280
+ constructor(config) {
1291
1281
  super();
1292
- this.characterDescription = characterDescription;
1293
- this.animationConfig = animationConfig;
1294
- this.characterModelLoader = characterModelLoader;
1295
- this.characterId = characterId;
1296
- this.modelLoadedCallback = modelLoadedCallback;
1297
- this.cameraManager = cameraManager;
1298
- this.composer = composer;
1299
- this.isLocal = isLocal;
1282
+ this.config = config;
1300
1283
  this.model = null;
1301
1284
  this.color = new Color3();
1302
- this.tooltip = null;
1303
1285
  this.speakingIndicator = null;
1304
1286
  this.tooltip = new CharacterTooltip();
1287
+ this.tooltip.setText(this.config.username, this.config.isLocal);
1305
1288
  this.add(this.tooltip);
1289
+ this.load().then(() => {
1290
+ this.config.modelLoadedCallback();
1291
+ });
1292
+ }
1293
+ updateCharacter(username, characterDescription) {
1294
+ this.config.username = username;
1295
+ this.config.characterDescription = characterDescription;
1306
1296
  this.load();
1297
+ this.tooltip.setText(username, this.config.isLocal);
1307
1298
  }
1308
1299
  async load() {
1309
- this.model = new CharacterModel(
1310
- this.characterDescription,
1311
- this.animationConfig,
1312
- this.characterModelLoader,
1313
- this.cameraManager,
1314
- this.characterId,
1315
- this.isLocal
1316
- );
1300
+ const previousModel = this.model;
1301
+ this.model = new CharacterModel({
1302
+ characterDescription: this.config.characterDescription,
1303
+ animationConfig: this.config.animationConfig,
1304
+ characterModelLoader: this.config.characterModelLoader,
1305
+ cameraManager: this.config.cameraManager,
1306
+ characterId: this.config.characterId,
1307
+ isLocal: this.config.isLocal
1308
+ });
1317
1309
  await this.model.init();
1310
+ if (previousModel && previousModel.mesh) {
1311
+ this.remove(previousModel.mesh);
1312
+ }
1318
1313
  this.add(this.model.mesh);
1319
1314
  if (this.speakingIndicator === null) {
1320
- this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1315
+ this.speakingIndicator = new CharacterSpeakingIndicator(this.config.composer.postPostScene);
1321
1316
  }
1322
- this.modelLoadedCallback();
1323
1317
  }
1324
1318
  updateAnimation(targetAnimation) {
1325
1319
  var _a;
@@ -1330,14 +1324,14 @@ var Character = class extends Group {
1330
1324
  if (!this.model)
1331
1325
  return;
1332
1326
  if (this.tooltip) {
1333
- this.tooltip.update(this.cameraManager.camera);
1327
+ this.tooltip.update(this.config.cameraManager.camera);
1334
1328
  }
1335
1329
  if (this.speakingIndicator) {
1336
1330
  this.speakingIndicator.setTime(time);
1337
1331
  if (this.model.mesh && this.model.headBone) {
1338
1332
  this.speakingIndicator.setBillboarding(
1339
1333
  (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
1340
- this.cameraManager.camera
1334
+ this.config.cameraManager.camera
1341
1335
  );
1342
1336
  }
1343
1337
  }
@@ -1364,13 +1358,8 @@ var baseControl = 200;
1364
1358
  var collisionDetectionSteps = 15;
1365
1359
  var minimumSurfaceAngle = 0.9;
1366
1360
  var LocalController = class {
1367
- constructor(character, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
1368
- this.character = character;
1369
- this.id = id;
1370
- this.collisionsManager = collisionsManager;
1371
- this.keyInputManager = keyInputManager;
1372
- this.cameraManager = cameraManager;
1373
- this.timeManager = timeManager;
1361
+ constructor(config) {
1362
+ this.config = config;
1374
1363
  this.capsuleInfo = {
1375
1364
  radius: 0.4,
1376
1365
  segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
@@ -1408,53 +1397,54 @@ var LocalController = class {
1408
1397
  this.surfaceTempRay = new Ray();
1409
1398
  this.lastFrameSurfaceState = null;
1410
1399
  this.networkState = {
1411
- id: this.id,
1400
+ id: this.config.id,
1412
1401
  position: { x: 0, y: 0, z: 0 },
1413
1402
  rotation: { quaternionY: 0, quaternionW: 1 },
1414
1403
  state: 0 /* idle */
1415
1404
  };
1416
1405
  }
1417
1406
  updateControllerState() {
1418
- this.forward = this.keyInputManager.forward;
1419
- this.backward = this.keyInputManager.backward;
1420
- this.left = this.keyInputManager.left;
1421
- this.right = this.keyInputManager.right;
1422
- this.run = this.keyInputManager.run;
1423
- this.jump = this.keyInputManager.jump;
1424
- this.anyDirection = this.keyInputManager.anyDirection;
1425
- this.conflictingDirections = this.keyInputManager.conflictingDirection;
1407
+ var _a, _b, _c, _d, _e;
1408
+ this.forward = this.config.keyInputManager.forward || ((_a = this.config.virtualJoystick) == null ? void 0 : _a.up) || false;
1409
+ this.backward = this.config.keyInputManager.backward || ((_b = this.config.virtualJoystick) == null ? void 0 : _b.down) || false;
1410
+ this.left = this.config.keyInputManager.left || ((_c = this.config.virtualJoystick) == null ? void 0 : _c.left) || false;
1411
+ this.right = this.config.keyInputManager.right || ((_d = this.config.virtualJoystick) == null ? void 0 : _d.right) || false;
1412
+ this.run = this.config.keyInputManager.run;
1413
+ this.jump = this.config.keyInputManager.jump;
1414
+ this.anyDirection = this.config.keyInputManager.anyDirection || ((_e = this.config.virtualJoystick) == null ? void 0 : _e.hasDirection) || false;
1415
+ this.conflictingDirections = this.config.keyInputManager.conflictingDirection;
1426
1416
  }
1427
1417
  update() {
1428
1418
  this.updateControllerState();
1429
- this.rayCaster.set(this.character.position, this.vectorDown);
1430
- const firstRaycastHit = this.collisionsManager.raycastFirst(this.rayCaster.ray);
1419
+ this.rayCaster.set(this.config.character.position, this.vectorDown);
1420
+ const firstRaycastHit = this.config.collisionsManager.raycastFirst(this.rayCaster.ray);
1431
1421
  if (firstRaycastHit !== null) {
1432
1422
  this.currentHeight = firstRaycastHit[0];
1433
1423
  this.currentSurfaceAngle.copy(firstRaycastHit[1]);
1434
1424
  }
1435
1425
  if (this.anyDirection || !this.characterOnGround) {
1436
1426
  const targetAnimation = this.getTargetAnimation();
1437
- this.character.updateAnimation(targetAnimation);
1427
+ this.config.character.updateAnimation(targetAnimation);
1438
1428
  } else {
1439
- this.character.updateAnimation(0 /* idle */);
1429
+ this.config.character.updateAnimation(0 /* idle */);
1440
1430
  }
1441
1431
  if (this.anyDirection) {
1442
1432
  this.updateRotation();
1443
1433
  }
1444
1434
  for (let i = 0; i < collisionDetectionSteps; i++) {
1445
1435
  this.updatePosition(
1446
- this.timeManager.deltaTime,
1447
- this.timeManager.deltaTime / collisionDetectionSteps,
1436
+ this.config.timeManager.deltaTime,
1437
+ this.config.timeManager.deltaTime / collisionDetectionSteps,
1448
1438
  i
1449
1439
  );
1450
1440
  }
1451
- if (this.character.position.y < 0) {
1441
+ if (this.config.character.position.y < 0) {
1452
1442
  this.resetPosition();
1453
1443
  }
1454
1444
  this.updateNetworkState();
1455
1445
  }
1456
1446
  getTargetAnimation() {
1457
- if (!this.character)
1447
+ if (!this.config.character)
1458
1448
  return 0 /* idle */;
1459
1449
  const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8;
1460
1450
  if (this.currentHeight > jumpHeight && !this.characterOnGround) {
@@ -1487,22 +1477,22 @@ var LocalController = class {
1487
1477
  }
1488
1478
  }
1489
1479
  updateAzimuthalAngle() {
1490
- const camToModelDistance = this.cameraManager.camera.position.distanceTo(
1491
- this.character.position
1480
+ const camToModelDistance = this.config.cameraManager.camera.position.distanceTo(
1481
+ this.config.character.position
1492
1482
  );
1493
1483
  const isCameraFirstPerson = camToModelDistance < 2;
1494
1484
  if (isCameraFirstPerson) {
1495
- const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.cameraManager.camera.quaternion);
1485
+ const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.config.cameraManager.camera.quaternion);
1496
1486
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1497
1487
  } else {
1498
1488
  this.azimuthalAngle = Math.atan2(
1499
- this.cameraManager.camera.position.x - this.character.position.x,
1500
- this.cameraManager.camera.position.z - this.character.position.z
1489
+ this.config.cameraManager.camera.position.x - this.config.character.position.x,
1490
+ this.config.cameraManager.camera.position.z - this.config.character.position.z
1501
1491
  );
1502
1492
  }
1503
1493
  }
1504
1494
  computeAngularDifference(rotationQuaternion) {
1505
- return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion)));
1495
+ return 2 * Math.acos(Math.abs(this.config.character.quaternion.dot(rotationQuaternion)));
1506
1496
  }
1507
1497
  updateRotation() {
1508
1498
  this.updateRotationOffset();
@@ -1514,8 +1504,8 @@ var LocalController = class {
1514
1504
  const angularDifference = this.computeAngularDifference(rotationQuaternion);
1515
1505
  const desiredTime = 0.07;
1516
1506
  const angularSpeed = angularDifference / desiredTime;
1517
- const frameRotation = angularSpeed * this.timeManager.deltaTime;
1518
- this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1507
+ const frameRotation = angularSpeed * this.config.timeManager.deltaTime;
1508
+ this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1519
1509
  }
1520
1510
  applyControls(deltaTime) {
1521
1511
  const resistance = this.characterOnGround ? groundResistance : airResistance;
@@ -1567,31 +1557,31 @@ var LocalController = class {
1567
1557
  }
1568
1558
  acceleration.add(controlAcceleration);
1569
1559
  this.characterVelocity.addScaledVector(acceleration, deltaTime);
1570
- this.character.position.addScaledVector(this.characterVelocity, deltaTime);
1560
+ this.config.character.position.addScaledVector(this.characterVelocity, deltaTime);
1571
1561
  }
1572
1562
  updatePosition(deltaTime, stepDeltaTime, iter) {
1573
1563
  this.applyControls(stepDeltaTime);
1574
1564
  if (iter === 0) {
1575
- const lastMovement = this.getMovementFromSurfaces(this.character.position, deltaTime);
1565
+ const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime);
1576
1566
  if (lastMovement) {
1577
- this.character.position.add(lastMovement.position);
1578
- const asQuaternion = this.tempQuaternion.setFromEuler(this.character.rotation);
1567
+ this.config.character.position.add(lastMovement.position);
1568
+ const asQuaternion = this.tempQuaternion.setFromEuler(this.config.character.rotation);
1579
1569
  const lastMovementEuler = this.tempEuler.setFromQuaternion(lastMovement.rotation);
1580
1570
  lastMovementEuler.x = 0;
1581
1571
  lastMovementEuler.z = 0;
1582
1572
  lastMovement.rotation.setFromEuler(lastMovementEuler);
1583
1573
  asQuaternion.multiply(lastMovement.rotation);
1584
- this.character.rotation.setFromQuaternion(asQuaternion);
1574
+ this.config.character.rotation.setFromQuaternion(asQuaternion);
1585
1575
  }
1586
1576
  }
1587
- this.character.updateMatrixWorld();
1577
+ this.config.character.updateMatrixWorld();
1588
1578
  const avatarSegment = this.tempSegment;
1589
1579
  avatarSegment.copy(this.capsuleInfo.segment);
1590
- avatarSegment.start.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
1591
- avatarSegment.end.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
1580
+ avatarSegment.start.applyMatrix4(this.config.character.matrixWorld).applyMatrix4(this.tempMatrix);
1581
+ avatarSegment.end.applyMatrix4(this.config.character.matrixWorld).applyMatrix4(this.tempMatrix);
1592
1582
  const positionBeforeCollisions = this.tempVector.copy(avatarSegment.start);
1593
- this.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1594
- this.character.position.copy(avatarSegment.start);
1583
+ this.config.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1584
+ this.config.character.position.copy(avatarSegment.start);
1595
1585
  const deltaCollisionPosition = avatarSegment.start.sub(positionBeforeCollisions);
1596
1586
  this.characterOnGround = deltaCollisionPosition.y > 0;
1597
1587
  if (this.characterWasOnGround && !this.characterOnGround) {
@@ -1636,7 +1626,7 @@ var LocalController = class {
1636
1626
  }
1637
1627
  newPosition.setY(newPosition.y + 0.05);
1638
1628
  const ray = this.surfaceTempRay.set(newPosition, downVector);
1639
- const hit = this.collisionsManager.raycastFirst(ray);
1629
+ const hit = this.config.collisionsManager.raycastFirst(ray);
1640
1630
  if (hit && hit[0] < 0.8) {
1641
1631
  const currentCollisionMeshState = hit[2];
1642
1632
  this.lastFrameSurfaceState = [
@@ -1655,53 +1645,72 @@ var LocalController = class {
1655
1645
  return lastMovement;
1656
1646
  }
1657
1647
  updateNetworkState() {
1658
- const characterQuaternion = this.character.getWorldQuaternion(this.tempQuaternion);
1648
+ const characterQuaternion = this.config.character.getWorldQuaternion(this.tempQuaternion);
1649
+ const cameraQuaternion = new Quaternion2();
1650
+ this.config.cameraManager.camera.getWorldQuaternion(cameraQuaternion);
1659
1651
  this.networkState = {
1660
- id: this.id,
1652
+ id: this.config.id,
1661
1653
  position: {
1662
- x: this.character.position.x,
1663
- y: this.character.position.y,
1664
- z: this.character.position.z
1654
+ x: this.config.character.position.x,
1655
+ y: this.config.character.position.y,
1656
+ z: this.config.character.position.z
1665
1657
  },
1666
1658
  rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
1667
- state: this.character.getCurrentAnimation()
1659
+ camPosition: {
1660
+ x: this.config.cameraManager.camera.position.x,
1661
+ y: this.config.cameraManager.camera.position.y,
1662
+ z: this.config.cameraManager.camera.position.z
1663
+ },
1664
+ camQuaternion: {
1665
+ y: cameraQuaternion.y,
1666
+ w: cameraQuaternion.w
1667
+ },
1668
+ state: this.config.character.getCurrentAnimation()
1668
1669
  };
1669
1670
  }
1670
1671
  resetPosition() {
1671
1672
  this.characterVelocity.y = 0;
1672
- this.character.position.y = 3;
1673
+ this.config.character.position.y = 3;
1673
1674
  this.characterOnGround = false;
1674
1675
  }
1675
1676
  };
1676
1677
 
1677
1678
  // src/character/RemoteController.ts
1678
1679
  import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
1680
+ var tempQuaternion = new Quaternion3();
1679
1681
  var RemoteController = class {
1680
- constructor(character, id) {
1681
- this.character = character;
1682
- this.id = id;
1682
+ constructor(config) {
1683
+ this.config = config;
1683
1684
  this.currentAnimation = 0 /* idle */;
1684
1685
  this.networkState = {
1685
- id: this.id,
1686
- position: { x: 0, y: 0, z: 0 },
1687
- rotation: { quaternionY: 0, quaternionW: 1 },
1686
+ id: this.config.id,
1687
+ position: {
1688
+ x: this.config.character.position.x,
1689
+ y: this.config.character.position.y,
1690
+ z: this.config.character.position.z
1691
+ },
1692
+ rotation: {
1693
+ quaternionY: tempQuaternion.setFromEuler(this.config.character.rotation).y,
1694
+ quaternionW: 1
1695
+ },
1688
1696
  state: this.currentAnimation
1689
1697
  };
1690
1698
  }
1691
1699
  update(clientUpdate, time, deltaTime) {
1692
- if (!this.character)
1700
+ if (!this.config.character) {
1693
1701
  return;
1702
+ }
1694
1703
  this.updateFromNetwork(clientUpdate);
1695
- this.character.update(time, deltaTime);
1704
+ this.config.character.update(time, deltaTime);
1696
1705
  }
1697
1706
  updateFromNetwork(clientUpdate) {
1698
1707
  const { position, rotation, state } = clientUpdate;
1699
- this.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1708
+ this.config.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1700
1709
  const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1701
- this.character.quaternion.slerp(rotationQuaternion, 0.6);
1710
+ this.config.character.quaternion.slerp(rotationQuaternion, 0.6);
1702
1711
  if (state !== this.currentAnimation) {
1703
1712
  this.currentAnimation = state;
1704
- this.character.updateAnimation(state);
1713
+ this.config.character.updateAnimation(state);
1705
1714
  }
1706
1715
  }
1707
1716
  };
@@ -1732,20 +1741,11 @@ function decodeCharacterAndCamera(hash) {
1732
1741
 
1733
1742
  // src/character/CharacterManager.ts
1734
1743
  var CharacterManager = class {
1735
- constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, keyInputManager, clientStates, sendUpdate, animationConfig, characterDescription) {
1736
- this.composer = composer;
1737
- this.characterModelLoader = characterModelLoader;
1738
- this.collisionsManager = collisionsManager;
1739
- this.cameraManager = cameraManager;
1740
- this.timeManager = timeManager;
1741
- this.keyInputManager = keyInputManager;
1742
- this.clientStates = clientStates;
1743
- this.sendUpdate = sendUpdate;
1744
- this.animationConfig = animationConfig;
1745
- this.characterDescription = characterDescription;
1744
+ constructor(config) {
1745
+ this.config = config;
1746
1746
  this.updateLocationHash = true;
1747
1747
  this.headTargetOffset = new Vector38(0, 1.3, 0);
1748
- this.id = 0;
1748
+ this.localClientId = 0;
1749
1749
  this.remoteCharacters = /* @__PURE__ */ new Map();
1750
1750
  this.remoteCharacterControllers = /* @__PURE__ */ new Map();
1751
1751
  this.localCharacterSpawned = false;
@@ -1753,21 +1753,21 @@ var CharacterManager = class {
1753
1753
  this.speakingCharacters = /* @__PURE__ */ new Map();
1754
1754
  this.group = new Group2();
1755
1755
  }
1756
- spawnLocalCharacter(characterDescription, id, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1757
- var _a;
1758
- const character = new Character(
1756
+ spawnLocalCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1757
+ const character = new Character({
1758
+ username,
1759
1759
  characterDescription,
1760
- this.animationConfig,
1761
- this.characterModelLoader,
1762
- id,
1763
- () => {
1760
+ animationConfig: this.config.animationConfig,
1761
+ characterModelLoader: this.config.characterModelLoader,
1762
+ characterId: id,
1763
+ modelLoadedCallback: () => {
1764
1764
  },
1765
- this.cameraManager,
1766
- this.composer,
1767
- true
1768
- );
1765
+ cameraManager: this.config.cameraManager,
1766
+ composer: this.config.composer,
1767
+ isLocal: true
1768
+ });
1769
1769
  const quaternion = new Quaternion5().setFromEuler(character.rotation);
1770
- this.sendUpdate({
1770
+ this.config.sendUpdate({
1771
1771
  id,
1772
1772
  position: {
1773
1773
  x: spawnPosition.x,
@@ -1777,41 +1777,40 @@ var CharacterManager = class {
1777
1777
  rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
1778
1778
  state: 0 /* idle */
1779
1779
  });
1780
- this.id = id;
1780
+ this.localClientId = id;
1781
1781
  this.localCharacter = character;
1782
- this.localController = new LocalController(
1783
- this.localCharacter,
1784
- this.id,
1785
- this.collisionsManager,
1786
- this.keyInputManager,
1787
- this.cameraManager,
1788
- this.timeManager
1789
- );
1782
+ this.localController = new LocalController({
1783
+ character: this.localCharacter,
1784
+ id: this.localClientId,
1785
+ collisionsManager: this.config.collisionsManager,
1786
+ keyInputManager: this.config.keyInputManager,
1787
+ virtualJoystick: this.config.virtualJoystick,
1788
+ cameraManager: this.config.cameraManager,
1789
+ timeManager: this.config.timeManager
1790
+ });
1790
1791
  this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1791
1792
  this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1792
- (_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`, true);
1793
1793
  this.group.add(character);
1794
1794
  this.localCharacterSpawned = true;
1795
1795
  }
1796
- spawnRemoteCharacter(characterDescription, id, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1797
- var _a;
1798
- const character = new Character(
1796
+ spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1797
+ const character = new Character({
1798
+ username,
1799
1799
  characterDescription,
1800
- this.animationConfig,
1801
- this.characterModelLoader,
1802
- id,
1803
- () => {
1800
+ animationConfig: this.config.animationConfig,
1801
+ characterModelLoader: this.config.characterModelLoader,
1802
+ characterId: id,
1803
+ modelLoadedCallback: () => {
1804
1804
  },
1805
- this.cameraManager,
1806
- this.composer,
1807
- false
1808
- );
1805
+ cameraManager: this.config.cameraManager,
1806
+ composer: this.config.composer,
1807
+ isLocal: false
1808
+ });
1809
1809
  this.remoteCharacters.set(id, character);
1810
- const remoteController = new RemoteController(character, id);
1811
- remoteController.character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1812
- remoteController.character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1810
+ character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1811
+ character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1812
+ const remoteController = new RemoteController({ character, id });
1813
1813
  this.remoteCharacterControllers.set(id, remoteController);
1814
- (_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`);
1815
1814
  this.group.add(character);
1816
1815
  }
1817
1816
  getLocalCharacterPositionAndRotation() {
@@ -1840,50 +1839,71 @@ var CharacterManager = class {
1840
1839
  setSpeakingCharacter(id, value) {
1841
1840
  this.speakingCharacters.set(id, value);
1842
1841
  }
1842
+ respawnIfPresent(id) {
1843
+ const characterInfo = this.config.characterResolve(id);
1844
+ if (this.localCharacter && this.localClientId == id) {
1845
+ this.localCharacter.updateCharacter(
1846
+ characterInfo.username,
1847
+ characterInfo.characterDescription
1848
+ );
1849
+ }
1850
+ const remoteCharacter = this.remoteCharacters.get(id);
1851
+ if (remoteCharacter) {
1852
+ remoteCharacter.updateCharacter(characterInfo.username, characterInfo.characterDescription);
1853
+ }
1854
+ }
1843
1855
  update() {
1844
1856
  var _a, _b, _c;
1845
1857
  if (this.localCharacter) {
1846
- this.localCharacter.update(this.timeManager.time, this.timeManager.deltaTime);
1847
- if (this.speakingCharacters.has(this.id)) {
1848
- (_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(this.speakingCharacters.get(this.id));
1858
+ this.localCharacter.update(this.config.timeManager.time, this.config.timeManager.deltaTime);
1859
+ if (this.speakingCharacters.has(this.localClientId)) {
1860
+ (_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(
1861
+ this.speakingCharacters.get(this.localClientId)
1862
+ );
1849
1863
  }
1850
1864
  this.localController.update();
1851
- if (this.timeManager.frame % 2 === 0) {
1852
- this.sendUpdate(this.localController.networkState);
1865
+ if (this.config.timeManager.frame % 2 === 0) {
1866
+ this.config.sendUpdate(this.localController.networkState);
1853
1867
  }
1854
1868
  const targetOffset = new Vector38();
1855
1869
  targetOffset.add(this.headTargetOffset).applyQuaternion(this.localCharacter.quaternion).add(this.localCharacter.position);
1856
- this.cameraManager.setTarget(targetOffset);
1857
- for (const [id, update] of this.clientStates) {
1870
+ this.config.cameraManager.setTarget(targetOffset);
1871
+ for (const [id, update] of this.config.remoteUserStates) {
1858
1872
  if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
1859
1873
  const character = this.remoteCharacters.get(id);
1860
1874
  (_b = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _b.setSpeaking(this.speakingCharacters.get(id));
1861
1875
  }
1862
1876
  const { position } = update;
1863
1877
  if (!this.remoteCharacters.has(id) && this.localCharacterSpawned === true) {
1878
+ const characterInfo = this.config.characterResolve(id);
1864
1879
  this.spawnRemoteCharacter(
1865
- this.characterDescription,
1866
1880
  id,
1881
+ characterInfo.username,
1882
+ characterInfo.characterDescription,
1867
1883
  new Vector38(position.x, position.y, position.z)
1868
1884
  );
1869
1885
  }
1870
1886
  const characterController = this.remoteCharacterControllers.get(id);
1871
1887
  if (characterController) {
1872
- characterController.update(update, this.timeManager.time, this.timeManager.deltaTime);
1888
+ characterController.update(
1889
+ update,
1890
+ this.config.timeManager.time,
1891
+ this.config.timeManager.deltaTime
1892
+ );
1873
1893
  }
1874
1894
  }
1875
1895
  for (const [id, character] of this.remoteCharacters) {
1876
- if (!this.clientStates.has(id)) {
1896
+ if (!this.config.remoteUserStates.has(id)) {
1877
1897
  (_c = character.speakingIndicator) == null ? void 0 : _c.dispose();
1878
1898
  this.group.remove(character);
1879
1899
  this.remoteCharacters.delete(id);
1880
1900
  this.remoteCharacterControllers.delete(id);
1881
1901
  }
1882
1902
  }
1883
- if (this.updateLocationHash && this.timeManager.frame % 60 === 0) {
1903
+ if (this.updateLocationHash && this.config.timeManager.frame % 60 === 0) {
1884
1904
  window.location.hash = encodeCharacterAndCamera(
1885
1905
  this.localCharacter,
1886
- this.cameraManager.camera
1906
+ this.config.cameraManager.camera
1887
1907
  );
1888
1908
  }
1889
1909
  }
@@ -1891,32 +1911,7 @@ var CharacterManager = class {
1891
1911
  };
1892
1912
 
1893
1913
  // src/character/CharacterModelLoader.ts
1894
- import { LoadingManager } from "three";
1895
- import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
1896
- var CachedGLTFLoader = class extends ThreeGLTFLoader {
1897
- constructor(manager, debug = false) {
1898
- super(manager);
1899
- this.debug = debug;
1900
- this.blobCache = /* @__PURE__ */ new Map();
1901
- }
1902
- setBlobUrl(originalUrl, blobUrl) {
1903
- this.blobCache.set(originalUrl, blobUrl);
1904
- }
1905
- getBlobUrl(originalUrl) {
1906
- return this.blobCache.get(originalUrl);
1907
- }
1908
- load(url, onLoad, onProgress, onError) {
1909
- const blobUrl = this.getBlobUrl(url);
1910
- if (blobUrl) {
1911
- if (this.debug === true) {
1912
- console.log(`Loading cached ${url.split("/").pop()}`);
1913
- }
1914
- super.load(blobUrl, onLoad, onProgress, onError);
1915
- } else {
1916
- super.load(url, onLoad, onProgress, onError);
1917
- }
1918
- }
1919
- };
1914
+ import { ModelLoader as ModelLoader2 } from "@mml-io/model-loader";
1920
1915
  var LRUCache = class {
1921
1916
  constructor(maxSize = 100) {
1922
1917
  this.maxSize = maxSize;
@@ -1941,16 +1936,13 @@ var LRUCache = class {
1941
1936
  var CharacterModelLoader = class {
1942
1937
  constructor(maxCacheSize = 100, debug = false) {
1943
1938
  this.debug = debug;
1939
+ this.modelLoader = new ModelLoader2();
1944
1940
  this.ongoingLoads = /* @__PURE__ */ new Map();
1945
- this.loadingManager = new LoadingManager();
1946
- this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug);
1947
1941
  this.modelCache = new LRUCache(maxCacheSize);
1948
1942
  }
1949
1943
  async load(fileUrl, fileType) {
1950
1944
  const cachedModel = this.modelCache.get(fileUrl);
1951
1945
  if (cachedModel) {
1952
- const blobURL = URL.createObjectURL(cachedModel.blob);
1953
- this.gltfLoader.setBlobUrl(fileUrl, blobURL);
1954
1946
  return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
1955
1947
  } else {
1956
1948
  if (this.debug === true) {
@@ -1978,26 +1970,21 @@ var CharacterModelLoader = class {
1978
1970
  }
1979
1971
  async loadFromUrl(url, fileType, extension) {
1980
1972
  if (["gltf", "glb"].includes(extension)) {
1981
- return new Promise((resolve, reject) => {
1982
- this.gltfLoader.load(
1973
+ return new Promise(async (resolve, reject) => {
1974
+ const modelLoadResult = await this.modelLoader.load(
1983
1975
  url,
1984
- (object) => {
1985
- if (fileType === "model") {
1986
- resolve(object.scene);
1987
- } else if (fileType === "animation") {
1988
- resolve(object.animations[0]);
1989
- } else {
1990
- const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
1991
- console.error(error);
1992
- reject(error);
1993
- }
1994
- },
1995
- void 0,
1996
- (error) => {
1997
- console.error(`Error loading GL(B|TF) from ${url}: ${error}`);
1998
- reject(error);
1976
+ (loaded, total) => {
1999
1977
  }
2000
1978
  );
1979
+ if (fileType === "model") {
1980
+ resolve(modelLoadResult.group);
1981
+ } else if (fileType === "animation") {
1982
+ resolve(modelLoadResult.animations[0]);
1983
+ } else {
1984
+ const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
1985
+ console.error(error);
1986
+ reject(error);
1987
+ }
2001
1988
  });
2002
1989
  } else {
2003
1990
  console.error(`Error: can't recognize ${url} extension: ${extension}`);
@@ -2011,17 +1998,9 @@ var KeyInputManager = class {
2011
1998
  this.shouldCaptureKeyPress = shouldCaptureKeyPress;
2012
1999
  this.keys = /* @__PURE__ */ new Map();
2013
2000
  this.eventHandlerCollection = new EventHandlerCollection();
2014
- this.directionJoystick = null;
2015
2001
  this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
2016
2002
  this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
2017
2003
  this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this));
2018
- this.directionJoystick = new VirtualJoystick({
2019
- radius: 70,
2020
- inner_radius: 20,
2021
- x: 70,
2022
- y: 0,
2023
- mouse_support: false
2024
- });
2025
2004
  }
2026
2005
  handleUnfocus(_event) {
2027
2006
  this.keys.clear();
@@ -2045,19 +2024,19 @@ var KeyInputManager = class {
2045
2024
  return this.keys.get(key) || false;
2046
2025
  }
2047
2026
  isMovementKeyPressed() {
2048
- return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key)) || this.directionJoystick.hasDirection;
2027
+ return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
2049
2028
  }
2050
2029
  get forward() {
2051
- return this.isKeyPressed("w" /* W */) || this.directionJoystick.up;
2030
+ return this.isKeyPressed("w" /* W */);
2052
2031
  }
2053
2032
  get backward() {
2054
- return this.isKeyPressed("s" /* S */) || this.directionJoystick.down;
2033
+ return this.isKeyPressed("s" /* S */);
2055
2034
  }
2056
2035
  get left() {
2057
- return this.isKeyPressed("a" /* A */) || this.directionJoystick.left;
2036
+ return this.isKeyPressed("a" /* A */);
2058
2037
  }
2059
2038
  get right() {
2060
- return this.isKeyPressed("d" /* D */) || this.directionJoystick.right;
2039
+ return this.isKeyPressed("d" /* D */);
2061
2040
  }
2062
2041
  get run() {
2063
2042
  return this.isKeyPressed("shift" /* SHIFT */);
@@ -2085,40 +2064,35 @@ import {
2085
2064
  } from "mml-web";
2086
2065
  import { Group as Group3 } from "three";
2087
2066
  var MMLCompositionScene = class {
2088
- constructor(targetElement, renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation) {
2089
- this.renderer = renderer;
2090
- this.scene = scene;
2091
- this.camera = camera;
2092
- this.audioListener = audioListener;
2093
- this.collisionsManager = collisionsManager;
2094
- this.getUserPositionAndRotation = getUserPositionAndRotation;
2067
+ constructor(config) {
2068
+ this.config = config;
2095
2069
  this.chatProbes = /* @__PURE__ */ new Set();
2096
2070
  this.group = new Group3();
2097
- this.promptManager = PromptManager.init(targetElement);
2071
+ this.promptManager = PromptManager.init(this.config.targetElement);
2098
2072
  const { interactionListener, interactionManager } = InteractionManager.init(
2099
- targetElement,
2100
- this.camera,
2101
- this.scene
2073
+ this.config.targetElement,
2074
+ this.config.camera,
2075
+ this.config.scene
2102
2076
  );
2103
2077
  this.interactionManager = interactionManager;
2104
2078
  this.interactionListener = interactionListener;
2105
2079
  this.loadingProgressManager = new LoadingProgressManager();
2106
2080
  this.mmlScene = {
2107
- getAudioListener: () => this.audioListener,
2108
- getRenderer: () => this.renderer,
2109
- getThreeScene: () => this.scene,
2081
+ getAudioListener: () => this.config.audioListener,
2082
+ getRenderer: () => this.config.renderer,
2083
+ getThreeScene: () => this.config.scene,
2110
2084
  getRootContainer: () => this.group,
2111
- getCamera: () => this.camera,
2085
+ getCamera: () => this.config.camera,
2112
2086
  addCollider: (object, mElement) => {
2113
- this.collisionsManager.addMeshesGroup(object, mElement);
2087
+ this.config.collisionsManager.addMeshesGroup(object, mElement);
2114
2088
  },
2115
2089
  updateCollider: (object) => {
2116
- this.collisionsManager.updateMeshesGroup(object);
2090
+ this.config.collisionsManager.updateMeshesGroup(object);
2117
2091
  },
2118
2092
  removeCollider: (object) => {
2119
- this.collisionsManager.removeMeshesGroup(object);
2093
+ this.config.collisionsManager.removeMeshesGroup(object);
2120
2094
  },
2121
- getUserPositionAndRotation: this.getUserPositionAndRotation,
2095
+ getUserPositionAndRotation: this.config.getUserPositionAndRotation,
2122
2096
  addInteraction: (interaction) => {
2123
2097
  this.interactionListener.addInteraction(interaction);
2124
2098
  },
@@ -2143,7 +2117,7 @@ var MMLCompositionScene = class {
2143
2117
  return this.loadingProgressManager;
2144
2118
  }
2145
2119
  };
2146
- this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
2120
+ this.clickTrigger = MMLClickTrigger.init(this.config.targetElement, this.mmlScene);
2147
2121
  }
2148
2122
  onChatMessage(message) {
2149
2123
  for (const chatProbe of this.chatProbes) {
@@ -2163,8 +2137,8 @@ import { Pane } from "tweakpane";
2163
2137
 
2164
2138
  // src/tweakpane/blades/bcsFolder.ts
2165
2139
  var bcsValues = {
2166
- brightness: 0,
2167
- contrast: 1,
2140
+ brightness: 0.06,
2141
+ contrast: 1.2,
2168
2142
  saturation: 1
2169
2143
  };
2170
2144
  var bcsOptions = {
@@ -2211,10 +2185,10 @@ var BrightnessContrastSaturationFolder = class {
2211
2185
  // src/tweakpane/blades/environmentFolder.ts
2212
2186
  var sunValues = {
2213
2187
  sunPosition: {
2214
- sunAzimuthalAngle: 214.5,
2215
- sunPolarAngle: -41.5
2188
+ sunAzimuthalAngle: 219,
2189
+ sunPolarAngle: -37
2216
2190
  },
2217
- sunIntensity: 1,
2191
+ sunIntensity: 3.7,
2218
2192
  sunColor: { r: 1, g: 1, b: 1 }
2219
2193
  };
2220
2194
  var sunOptions = {
@@ -2222,17 +2196,17 @@ var sunOptions = {
2222
2196
  sunAzimuthalAngle: { min: 0, max: 360, step: 1 },
2223
2197
  sunPolarAngle: { min: -90, max: 90, step: 1 }
2224
2198
  },
2225
- sunIntensity: { min: 0, max: 3, step: 0.05 }
2199
+ sunIntensity: { min: 0, max: 10, step: 0.1 }
2226
2200
  };
2227
2201
  var envValues = {
2228
2202
  ambientLight: {
2229
- ambientLightIntensity: 0.05,
2203
+ ambientLightIntensity: 0.27,
2230
2204
  ambientLightColor: { r: 1, g: 1, b: 1 }
2231
2205
  },
2232
2206
  fog: {
2233
- fogNear: 30,
2234
- fogFar: 210,
2235
- fogColor: { r: 0.42, g: 0.48, b: 0.59 }
2207
+ fogNear: 21,
2208
+ fogFar: 180,
2209
+ fogColor: { r: 0.7, g: 0.7, b: 0.7 }
2236
2210
  }
2237
2211
  };
2238
2212
  var envOptions = {
@@ -2365,15 +2339,15 @@ var EnvironmentFolder = class {
2365
2339
 
2366
2340
  // src/tweakpane/blades/postExtrasFolder.ts
2367
2341
  var extrasValues = {
2368
- grain: 0.055,
2369
- bloom: 3
2342
+ grain: 0.045,
2343
+ bloom: 0.75
2370
2344
  };
2371
2345
  var extrasOptions = {
2372
2346
  grain: {
2373
2347
  amount: { min: 0, max: 0.2, step: 2e-3 }
2374
2348
  },
2375
2349
  bloom: {
2376
- amount: { min: 0, max: 5, step: 0.05 }
2350
+ amount: { min: 0, max: 50, step: 0.05 }
2377
2351
  }
2378
2352
  };
2379
2353
  var PostExtrasFolder = class {
@@ -2405,8 +2379,8 @@ var PostExtrasFolder = class {
2405
2379
  var rendererValues = {
2406
2380
  shadowMap: 2,
2407
2381
  toneMapping: 5,
2408
- exposure: 1,
2409
- bgIntensity: 1,
2382
+ exposure: 1.7,
2383
+ bgIntensity: 0.8,
2410
2384
  bgBlurriness: 0
2411
2385
  };
2412
2386
  var rendererOptions = {
@@ -2438,6 +2412,8 @@ var setShadowMapType = (value) => {
2438
2412
  };
2439
2413
  var setToneMappingType = (value) => {
2440
2414
  monitoredValues.toneMappingType = toneMappingTypes[value];
2415
+ rendererValues.toneMapping = value;
2416
+ console.log(rendererValues.toneMapping);
2441
2417
  };
2442
2418
  var RendererFolder = class {
2443
2419
  constructor(parentFolder, expand = false) {
@@ -2460,13 +2436,13 @@ var RendererFolder = class {
2460
2436
  return;
2461
2437
  switch (target) {
2462
2438
  case "shadowMap": {
2463
- const value = e.value;
2464
- renderer.shadowMap.type = value;
2465
- setShadowMapType(value);
2439
+ const value2 = e.value;
2440
+ renderer.shadowMap.type = value2;
2441
+ setShadowMapType(value2);
2466
2442
  break;
2467
2443
  }
2468
2444
  case "toneMapping":
2469
- renderer.toneMapping = e.value;
2445
+ const value = e.value;
2470
2446
  toneMappingFolder.hidden = e.value !== 5;
2471
2447
  toneMappingPass.enabled = e.value === 5 ? true : false;
2472
2448
  setToneMappingType(e.value);
@@ -2538,10 +2514,10 @@ var ppssaoValues = {
2538
2514
  samples: 30,
2539
2515
  rings: 11,
2540
2516
  luminanceInfluence: 0.7,
2541
- radius: 0.03,
2542
- intensity: 2.5,
2543
- bias: 0.05,
2544
- fade: 0.03,
2517
+ radius: 0.045,
2518
+ intensity: 3.14,
2519
+ bias: 0.01,
2520
+ fade: 0.06,
2545
2521
  resolutionScale: 0.5,
2546
2522
  color: { r: 0, g: 0, b: 0 },
2547
2523
  worldDistanceThreshold: 30,
@@ -2742,6 +2718,10 @@ var SSAOFolder = class {
2742
2718
  case "enabled":
2743
2719
  if (e.value === true) {
2744
2720
  composer.addPass(n8aopass, this.postProcessingSSAOIndex + 2);
2721
+ composer.passes[this.postProcessingSSAOIndex + 2].setSize(
2722
+ window.innerWidth,
2723
+ window.innerHeight
2724
+ );
2745
2725
  } else {
2746
2726
  composer.removePass(n8aopass);
2747
2727
  }
@@ -2784,7 +2764,7 @@ var SSAOFolder = class {
2784
2764
 
2785
2765
  // src/tweakpane/blades/toneMappingFolder.ts
2786
2766
  var toneMappingValues = {
2787
- mode: 2,
2767
+ mode: 7,
2788
2768
  resolution: 512,
2789
2769
  whitePoint: 32,
2790
2770
  middleGrey: 21,
@@ -2793,20 +2773,24 @@ var toneMappingValues = {
2793
2773
  adaptationRate: 2
2794
2774
  };
2795
2775
  var toneMappingOptions = {
2796
- mode: { min: 0, max: 4, step: 1 },
2776
+ mode: { min: 0, max: 8, step: 1 },
2797
2777
  resolution: { min: 64, max: 512, step: 64 },
2798
2778
  whitePoint: { min: 0, max: 32, step: 0.01 },
2799
2779
  middleGrey: { min: 0, max: 32, step: 0.01 },
2800
2780
  minLuminance: { min: 0, max: 32, step: 1e-3 },
2801
- averageLuminance: { min: 1e-3, max: 0.2, step: 1e-3 },
2781
+ averageLuminance: { min: 1e-3, max: 2, step: 1e-3 },
2802
2782
  adaptationRate: { min: 0.1, max: 2, step: 0.1 }
2803
2783
  };
2804
2784
  var customToneMappingTypes = {
2805
- 0: "REINHARD",
2806
- 1: "REINHARD2",
2807
- 2: "REINHARD2_ADAPTIVE",
2808
- 3: "OPTIMIZED_CINEON",
2809
- 4: "ACES_FILMIC"
2785
+ 0: "LINEAR",
2786
+ 1: "REINHARD",
2787
+ 2: "REINHARD2",
2788
+ 3: "REINHARD2_ADAPTIVE",
2789
+ 4: "UNCHARTED2",
2790
+ 5: "OPTIMIZED_CINEON",
2791
+ 6: "ACES_FILMIC",
2792
+ 7: "AGX",
2793
+ 8: "NEUTRAL"
2810
2794
  };
2811
2795
  var customToneMappingBlade = {
2812
2796
  customToneMappingType: customToneMappingTypes[toneMappingValues.mode]
@@ -2829,13 +2813,13 @@ var ToneMappingFolder = class {
2829
2813
  "minLuminance",
2830
2814
  toneMappingOptions.minLuminance
2831
2815
  );
2832
- this.minLuminance.hidden = toneMappingValues.mode === 2 ? true : false;
2816
+ this.minLuminance.hidden = false;
2833
2817
  this.avgLuminance = this.folder.addBinding(
2834
2818
  toneMappingValues,
2835
2819
  "averageLuminance",
2836
2820
  toneMappingOptions.averageLuminance
2837
2821
  );
2838
- this.avgLuminance.hidden = toneMappingValues.mode === 2 ? true : false;
2822
+ this.avgLuminance.hidden = false;
2839
2823
  this.folder.addBinding(toneMappingValues, "adaptationRate", toneMappingOptions.adaptationRate);
2840
2824
  }
2841
2825
  setupChangeEvent(toneMappingEffect) {
@@ -2844,8 +2828,6 @@ var ToneMappingFolder = class {
2844
2828
  if (!target)
2845
2829
  return;
2846
2830
  if (target === "mode") {
2847
- this.minLuminance.hidden = toneMappingValues.mode === 2 ? true : false;
2848
- this.avgLuminance.hidden = toneMappingValues.mode === 2 ? true : false;
2849
2831
  setCustomToneMappingType(e.value);
2850
2832
  }
2851
2833
  toneMappingEffect[target] = e.value;
@@ -2942,16 +2924,26 @@ var tweakPaneStyle = `
2942
2924
 
2943
2925
  // src/tweakpane/TweakPane.ts
2944
2926
  var TweakPane = class {
2945
- constructor(renderer, scene, composer) {
2927
+ constructor(holderElement, renderer, scene, composer) {
2928
+ this.holderElement = holderElement;
2946
2929
  this.renderer = renderer;
2947
2930
  this.scene = scene;
2948
2931
  this.composer = composer;
2949
2932
  this.saveVisibilityInLocalStorage = true;
2950
2933
  this.guiVisible = false;
2951
- const appWrapper = document.getElementById("app");
2952
2934
  const tweakPaneWrapper = document.createElement("div");
2953
- tweakPaneWrapper.id = "tweakpane-panel";
2954
- appWrapper.appendChild(tweakPaneWrapper);
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);
2955
2947
  this.gui = new Pane({ container: tweakPaneWrapper });
2956
2948
  this.gui.registerPlugin(EssentialsPlugin);
2957
2949
  if (this.saveVisibilityInLocalStorage) {
@@ -3077,6 +3069,7 @@ var TweakPane = class {
3077
3069
  };
3078
3070
 
3079
3071
  // src/rendering/composer.ts
3072
+ import { HDRJPGLoader } from "@monogrid/gainmap-js";
3080
3073
  import {
3081
3074
  EffectComposer as EffectComposer2,
3082
3075
  RenderPass,
@@ -3100,12 +3093,13 @@ import {
3100
3093
  Fog as Fog2,
3101
3094
  HalfFloatType as HalfFloatType2,
3102
3095
  LinearSRGBColorSpace,
3103
- LoadingManager as LoadingManager2,
3096
+ LoadingManager,
3104
3097
  PMREMGenerator,
3105
3098
  SRGBColorSpace,
3106
3099
  Scene as Scene4,
3107
3100
  Vector2 as Vector27,
3108
- WebGLRenderer as WebGLRenderer4
3101
+ WebGLRenderer as WebGLRenderer4,
3102
+ EquirectangularReflectionMapping
3109
3103
  } from "three";
3110
3104
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
3111
3105
 
@@ -3135,9 +3129,9 @@ var Sun = class extends Group4 {
3135
3129
  if (this.debug === true) {
3136
3130
  this.camHelper = new CameraHelper(this.shadowCamera);
3137
3131
  }
3138
- this.directionalLight = new DirectionalLight(16777215, 0.5);
3132
+ this.directionalLight = new DirectionalLight(16777215);
3139
3133
  this.directionalLight.intensity = sunValues.sunIntensity;
3140
- this.directionalLight.shadow.normalBias = 0.01;
3134
+ this.directionalLight.shadow.normalBias = 0.1;
3141
3135
  this.directionalLight.shadow.radius = 0.02;
3142
3136
  this.directionalLight.shadow.camera = this.shadowCamera;
3143
3137
  this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
@@ -4663,9 +4657,7 @@ var Composer = class {
4663
4657
  this.spawnSun = spawnSun;
4664
4658
  this.renderer = new WebGLRenderer4({
4665
4659
  powerPreference: "high-performance",
4666
- antialias: false,
4667
- stencil: false,
4668
- depth: false
4660
+ antialias: false
4669
4661
  });
4670
4662
  this.renderer.outputColorSpace = SRGBColorSpace;
4671
4663
  this.renderer.info.autoReset = false;
@@ -4746,6 +4738,8 @@ var Composer = class {
4746
4738
  this.bcs.uniforms.contrast.value = bcsValues.contrast;
4747
4739
  this.bcs.uniforms.saturation.value = bcsValues.saturation;
4748
4740
  this.gaussGrainPass = new ShaderPass(this.gaussGrainEffect, "tDiffuse");
4741
+ this.gaussGrainEffect.uniforms.amount.value = extrasValues.grain;
4742
+ this.gaussGrainEffect.uniforms.alpha.value = 1;
4749
4743
  this.smaaPass = new EffectPass2(this.camera, this.smaaEffect);
4750
4744
  this.effectComposer.addPass(this.renderPass);
4751
4745
  if (ppssaoValues.enabled) {
@@ -4756,7 +4750,6 @@ var Composer = class {
4756
4750
  this.effectComposer.addPass(this.n8aopass);
4757
4751
  }
4758
4752
  this.effectComposer.addPass(this.fxaaPass);
4759
- this.effectComposer.addPass(this.smaaPass);
4760
4753
  this.effectComposer.addPass(this.bloomPass);
4761
4754
  this.effectComposer.addPass(this.toneMappingPass);
4762
4755
  this.effectComposer.addPass(this.bcsPass);
@@ -4829,22 +4822,41 @@ var Composer = class {
4829
4822
  this.bloomPass.setSize(this.width, this.height);
4830
4823
  this.toneMappingPass.setSize(this.width, this.height);
4831
4824
  this.gaussGrainPass.setSize(this.width, this.height);
4825
+ this.gaussGrainEffect.uniforms.resolution.value = new Vector27(this.width, this.height);
4832
4826
  this.renderer.setSize(this.width, this.height);
4833
4827
  }
4834
4828
  render(timeManager) {
4835
4829
  this.renderer.info.reset();
4836
4830
  this.normalPass.texture.needsUpdate = true;
4837
- this.gaussGrainEffect.uniforms.resolution.value = this.resolution;
4838
4831
  this.gaussGrainEffect.uniforms.time.value = timeManager.time;
4839
- this.gaussGrainEffect.uniforms.alpha.value = 1;
4840
4832
  this.effectComposer.render();
4833
+ this.renderer.clearDepth();
4841
4834
  this.renderer.render(this.postPostScene, this.camera);
4842
4835
  }
4836
+ useHDRJPG(url, fromFile = false) {
4837
+ const pmremGenerator = new PMREMGenerator(this.renderer);
4838
+ const hdrJpg = new HDRJPGLoader(this.renderer).load(url, () => {
4839
+ const hdrJpgEquirectangularMap = hdrJpg.renderTarget.texture;
4840
+ hdrJpgEquirectangularMap.mapping = EquirectangularReflectionMapping;
4841
+ hdrJpgEquirectangularMap.needsUpdate = true;
4842
+ const envMap = pmremGenerator.fromEquirectangular(hdrJpgEquirectangularMap).texture;
4843
+ if (envMap) {
4844
+ envMap.colorSpace = LinearSRGBColorSpace;
4845
+ envMap.needsUpdate = true;
4846
+ this.scene.background = envMap;
4847
+ this.scene.backgroundIntensity = rendererValues.bgIntensity;
4848
+ this.isEnvHDRI = true;
4849
+ hdrJpgEquirectangularMap.dispose();
4850
+ pmremGenerator.dispose();
4851
+ }
4852
+ hdrJpg.dispose();
4853
+ });
4854
+ }
4843
4855
  useHDRI(url, fromFile = false) {
4844
4856
  if (this.isEnvHDRI && fromFile === false || !this.renderer)
4845
4857
  return;
4846
4858
  const pmremGenerator = new PMREMGenerator(this.renderer);
4847
- new RGBELoader(new LoadingManager2()).load(
4859
+ new RGBELoader(new LoadingManager()).load(
4848
4860
  url,
4849
4861
  (texture) => {
4850
4862
  const envMap = pmremGenerator.fromEquirectangular(texture).texture;
@@ -4870,7 +4882,7 @@ var Composer = class {
4870
4882
  return;
4871
4883
  const fileInput = document.createElement("input");
4872
4884
  fileInput.type = "file";
4873
- fileInput.accept = ".hdr";
4885
+ fileInput.accept = ".hdr,.jpg";
4874
4886
  fileInput.addEventListener("change", () => {
4875
4887
  var _a;
4876
4888
  const file = (_a = fileInput.files) == null ? void 0 : _a[0];
@@ -4878,9 +4890,16 @@ var Composer = class {
4878
4890
  console.log("no file");
4879
4891
  return;
4880
4892
  }
4893
+ const extension = file.name.split(".").pop();
4881
4894
  const fileURL = URL.createObjectURL(file);
4882
4895
  if (fileURL) {
4883
- this.useHDRI(fileURL, true);
4896
+ if (extension === "hdr") {
4897
+ this.useHDRI(fileURL, true);
4898
+ } else if (extension === "jpg") {
4899
+ this.useHDRJPG(fileURL);
4900
+ } else {
4901
+ console.error(`Unrecognized extension for HDR file ${file.name}`);
4902
+ }
4884
4903
  URL.revokeObjectURL(fileURL);
4885
4904
  document.body.removeChild(fileInput);
4886
4905
  }
@@ -4977,7 +4996,7 @@ import {
4977
4996
  MeshBasicMaterial as MeshBasicMaterial3,
4978
4997
  Quaternion as Quaternion6,
4979
4998
  Ray as Ray2,
4980
- Vector3 as Vector314
4999
+ Vector3 as Vector315
4981
5000
  } from "three";
4982
5001
  import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
4983
5002
  import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
@@ -4985,9 +5004,9 @@ import { MeshBVH, MeshBVHHelper } from "three-mesh-bvh";
4985
5004
  var CollisionsManager = class {
4986
5005
  constructor(scene) {
4987
5006
  this.debug = false;
4988
- this.tempVector = new Vector314();
4989
- this.tempVector2 = new Vector314();
4990
- this.tempVector3 = new Vector314();
5007
+ this.tempVector = new Vector315();
5008
+ this.tempVector2 = new Vector315();
5009
+ this.tempVector3 = new Vector315();
4991
5010
  this.tempQuaternion = new Quaternion6();
4992
5011
  this.tempRay = new Ray2();
4993
5012
  this.tempMatrix = new Matrix46();
@@ -5003,7 +5022,7 @@ var CollisionsManager = class {
5003
5022
  raycastFirst(ray) {
5004
5023
  let minimumDistance = null;
5005
5024
  let minimumHit = null;
5006
- let minimumNormal = new Vector314();
5025
+ let minimumNormal = new Vector315();
5007
5026
  for (const [, collisionMeshState] of this.collisionMeshState) {
5008
5027
  this.tempRay.copy(ray).applyMatrix4(this.tempMatrix.copy(collisionMeshState.matrix).invert());
5009
5028
  const hit = collisionMeshState.meshBVH.raycastFirst(this.tempRay, DoubleSide);
@@ -5144,7 +5163,7 @@ var CollisionsManager = class {
5144
5163
  const realDistance = intersectionSegment.distance();
5145
5164
  if (realDistance < capsuleRadius) {
5146
5165
  if (!collisionPosition) {
5147
- collisionPosition = new Vector314().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
5166
+ collisionPosition = new Vector315().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
5148
5167
  }
5149
5168
  const ratio = realDistance / modelReferenceDistance;
5150
5169
  const realDepth = capsuleRadius - realDistance;
@@ -5195,6 +5214,200 @@ var CollisionsManager = class {
5195
5214
  this.collisionTrigger.setCurrentCollisions(reportedCollidingElements);
5196
5215
  }
5197
5216
  };
5217
+
5218
+ // src/ground-plane/GroundPlane.ts
5219
+ import {
5220
+ CanvasTexture,
5221
+ CircleGeometry as CircleGeometry2,
5222
+ FrontSide as FrontSide2,
5223
+ Group as Group6,
5224
+ LinearMipMapLinearFilter,
5225
+ Mesh as Mesh6,
5226
+ MeshStandardMaterial as MeshStandardMaterial3,
5227
+ NearestFilter as NearestFilter2,
5228
+ RepeatWrapping as RepeatWrapping2
5229
+ } from "three";
5230
+ var canvas = document.createElement("canvas");
5231
+ canvas.width = 2;
5232
+ canvas.height = 2;
5233
+ var ctx = canvas.getContext("2d");
5234
+ ctx.fillStyle = "#e0e0e0";
5235
+ ctx.fillRect(0, 0, 2, 2);
5236
+ ctx.fillStyle = "#606060";
5237
+ ctx.fillRect(0, 0, 1, 1);
5238
+ ctx.fillRect(1, 1, 1, 1);
5239
+ var GroundPlane = class extends Group6 {
5240
+ constructor() {
5241
+ super();
5242
+ this.floorSize = 210;
5243
+ this.floorTexture = null;
5244
+ this.floorGeometry = new CircleGeometry2(this.floorSize, this.floorSize);
5245
+ this.floorMesh = null;
5246
+ this.floorMaterial = new MeshStandardMaterial3({
5247
+ color: 16777215,
5248
+ side: FrontSide2,
5249
+ metalness: 0.05,
5250
+ roughness: 0.95
5251
+ });
5252
+ this.floorMesh = new Mesh6(this.floorGeometry, this.floorMaterial);
5253
+ this.floorMesh.receiveShadow = true;
5254
+ this.floorMesh.rotation.x = Math.PI * -0.5;
5255
+ this.add(this.floorMesh);
5256
+ this.floorTexture = new CanvasTexture(canvas);
5257
+ this.floorTexture.wrapS = RepeatWrapping2;
5258
+ this.floorTexture.wrapT = RepeatWrapping2;
5259
+ this.floorTexture.magFilter = NearestFilter2;
5260
+ this.floorTexture.minFilter = LinearMipMapLinearFilter;
5261
+ this.floorTexture.repeat.set(this.floorSize / 1.5, this.floorSize / 1.5);
5262
+ this.floorMaterial.map = this.floorTexture;
5263
+ this.floorMaterial.needsUpdate = true;
5264
+ }
5265
+ };
5266
+
5267
+ // src/loading-screen/LoadingScreen.ts
5268
+ import { LoadingProgressManager as LoadingProgressManager2 } from "mml-web";
5269
+ var LoadingScreen = class {
5270
+ constructor(loadingProgressManager) {
5271
+ this.loadingProgressManager = loadingProgressManager;
5272
+ this.hasCompleted = false;
5273
+ this.element = document.createElement("div");
5274
+ this.element.style.position = "absolute";
5275
+ this.element.style.top = "0";
5276
+ this.element.style.left = "0";
5277
+ this.element.style.width = "100%";
5278
+ this.element.style.height = "100%";
5279
+ this.element.style.background = "linear-gradient(45deg, #28284B 0%, #303056 100%)";
5280
+ this.element.style.color = "white";
5281
+ this.element.addEventListener("click", (event) => {
5282
+ event.stopPropagation();
5283
+ });
5284
+ this.element.addEventListener("mousedown", (event) => {
5285
+ event.stopPropagation();
5286
+ });
5287
+ this.element.addEventListener("mousemove", (event) => {
5288
+ event.stopPropagation();
5289
+ });
5290
+ this.element.addEventListener("mouseup", (event) => {
5291
+ event.stopPropagation();
5292
+ });
5293
+ this.loadingBannerText = document.createElement("div");
5294
+ this.loadingBannerText.textContent = "Loading...";
5295
+ this.loadingBannerText.style.position = "absolute";
5296
+ this.loadingBannerText.style.display = "flex";
5297
+ this.loadingBannerText.style.top = "0";
5298
+ this.loadingBannerText.style.left = "0";
5299
+ this.loadingBannerText.style.width = "100%";
5300
+ this.loadingBannerText.style.height = "100%";
5301
+ this.loadingBannerText.style.color = "white";
5302
+ this.loadingBannerText.style.fontSize = "80px";
5303
+ this.loadingBannerText.style.fontWeight = "bold";
5304
+ this.loadingBannerText.style.fontFamily = "sans-serif";
5305
+ this.loadingBannerText.style.alignItems = "center";
5306
+ this.loadingBannerText.style.justifyContent = "center";
5307
+ this.element.append(this.loadingBannerText);
5308
+ this.progressDebugViewHolder = document.createElement("div");
5309
+ this.progressDebugViewHolder.style.display = "flex";
5310
+ this.progressDebugViewHolder.style.position = "absolute";
5311
+ this.progressDebugViewHolder.style.maxHeight = "calc(100% - 74px)";
5312
+ this.progressDebugViewHolder.style.left = "0";
5313
+ this.progressDebugViewHolder.style.bottom = "74px";
5314
+ this.progressDebugViewHolder.style.width = "100%";
5315
+ this.progressDebugViewHolder.style.justifyContent = "center";
5316
+ this.element.append(this.progressDebugViewHolder);
5317
+ this.progressDebugView = document.createElement("div");
5318
+ this.progressDebugView.style.backgroundColor = "rgba(128, 128, 128, 0.25)";
5319
+ this.progressDebugView.style.border = "1px solid black";
5320
+ this.progressDebugView.style.maxWidth = "100%";
5321
+ this.progressDebugView.style.overflow = "auto";
5322
+ this.progressDebugViewHolder.append(this.progressDebugView);
5323
+ this.debugCheckbox = document.createElement("input");
5324
+ this.debugCheckbox.type = "checkbox";
5325
+ this.debugCheckbox.checked = false;
5326
+ this.debugCheckbox.addEventListener("change", () => {
5327
+ this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
5328
+ if (this.hasCompleted) {
5329
+ this.dispose();
5330
+ }
5331
+ });
5332
+ this.debugLabel = document.createElement("label");
5333
+ this.debugLabel.textContent = "Debug loading";
5334
+ this.debugLabel.style.fontFamily = "sans-serif";
5335
+ this.debugLabel.style.padding = "5px";
5336
+ this.debugLabel.style.display = "inline-block";
5337
+ this.debugLabel.style.userSelect = "none";
5338
+ this.debugLabel.append(this.debugCheckbox);
5339
+ this.progressDebugView.append(this.debugLabel);
5340
+ this.progressDebugElement = document.createElement("pre");
5341
+ this.progressDebugElement.style.margin = "0";
5342
+ this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
5343
+ this.progressDebugView.append(this.progressDebugElement);
5344
+ this.progressBarHolder = document.createElement("div");
5345
+ this.progressBarHolder.style.display = "flex";
5346
+ this.progressBarHolder.style.alignItems = "center";
5347
+ this.progressBarHolder.style.justifyContent = "center";
5348
+ this.progressBarHolder.style.position = "absolute";
5349
+ this.progressBarHolder.style.bottom = "20px";
5350
+ this.progressBarHolder.style.left = "0";
5351
+ this.progressBarHolder.style.width = "100%";
5352
+ this.element.append(this.progressBarHolder);
5353
+ this.progressBarBackground = document.createElement("div");
5354
+ this.progressBarBackground.style.position = "relative";
5355
+ this.progressBarBackground.style.width = "500px";
5356
+ this.progressBarBackground.style.maxWidth = "80%";
5357
+ this.progressBarBackground.style.backgroundColor = "gray";
5358
+ this.progressBarBackground.style.height = "50px";
5359
+ this.progressBarBackground.style.lineHeight = "50px";
5360
+ this.progressBarBackground.style.borderRadius = "25px";
5361
+ this.progressBarBackground.style.border = "2px solid white";
5362
+ this.progressBarBackground.style.overflow = "hidden";
5363
+ this.progressBarHolder.append(this.progressBarBackground);
5364
+ this.progressBar = document.createElement("div");
5365
+ this.progressBar.style.position = "absolute";
5366
+ this.progressBar.style.top = "0";
5367
+ this.progressBar.style.left = "0";
5368
+ this.progressBar.style.width = "0";
5369
+ this.progressBar.style.height = "100%";
5370
+ this.progressBar.style.backgroundColor = "#0050a4";
5371
+ this.progressBarBackground.append(this.progressBar);
5372
+ this.loadingStatusText = document.createElement("div");
5373
+ this.loadingStatusText.style.position = "absolute";
5374
+ this.loadingStatusText.style.top = "0";
5375
+ this.loadingStatusText.style.left = "0";
5376
+ this.loadingStatusText.style.width = "100%";
5377
+ this.loadingStatusText.style.height = "100%";
5378
+ this.loadingStatusText.style.color = "white";
5379
+ this.loadingStatusText.style.textAlign = "center";
5380
+ this.loadingStatusText.style.verticalAlign = "middle";
5381
+ this.loadingStatusText.style.fontFamily = "sans-serif";
5382
+ this.loadingStatusText.style.fontWeight = "bold";
5383
+ this.loadingStatusText.textContent = "Loading...";
5384
+ this.progressBarBackground.append(this.loadingStatusText);
5385
+ this.loadingCallback = () => {
5386
+ const [loadingRatio, completedLoading] = this.loadingProgressManager.toRatio();
5387
+ if (completedLoading) {
5388
+ if (!this.hasCompleted) {
5389
+ this.hasCompleted = true;
5390
+ if (!this.debugCheckbox.checked) {
5391
+ this.dispose();
5392
+ }
5393
+ }
5394
+ this.loadingStatusText.textContent = "Completed";
5395
+ this.progressBar.style.width = "100%";
5396
+ } else {
5397
+ this.loadingStatusText.textContent = `Loading... ${(loadingRatio * 100).toFixed(2)}%`;
5398
+ this.progressBar.style.width = `${loadingRatio * 100}%`;
5399
+ }
5400
+ this.progressDebugElement.textContent = LoadingProgressManager2.LoadingProgressSummaryToString(
5401
+ this.loadingProgressManager.toSummary()
5402
+ );
5403
+ };
5404
+ this.loadingProgressManager.addProgressCallback(this.loadingCallback);
5405
+ }
5406
+ dispose() {
5407
+ this.loadingProgressManager.removeProgressCallback(this.loadingCallback);
5408
+ this.element.remove();
5409
+ }
5410
+ };
5198
5411
  export {
5199
5412
  AnimationState,
5200
5413
  CameraManager,
@@ -5202,11 +5415,14 @@ export {
5202
5415
  CharacterModelLoader,
5203
5416
  CollisionsManager,
5204
5417
  Composer,
5418
+ GroundPlane,
5205
5419
  KeyInputManager,
5420
+ LoadingScreen,
5206
5421
  MMLCompositionScene,
5207
5422
  Sun,
5208
5423
  TimeManager,
5209
5424
  TweakPane,
5425
+ VirtualJoystick,
5210
5426
  clamp,
5211
5427
  decodeCharacterAndCamera,
5212
5428
  ease,