@mml-io/3d-web-client-core 0.0.0-experimental-8e179c2-20240414 → 0.0.0-experimental-b2c739e-20240426

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;
@@ -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 };
@@ -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,16 +764,22 @@ 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() {
@@ -809,18 +792,18 @@ var CharacterModel = class {
809
792
  if (this.materials.has(originalMaterial.name)) {
810
793
  asMesh.material = this.materials.get(originalMaterial.name);
811
794
  } else {
812
- const material = originalMaterial.name === "body_replaceable_color" ? new CharacterMaterial(
813
- this.isLocal,
814
- this.cameraManager,
815
- this.characterId,
795
+ const material = originalMaterial.name === "body_replaceable_color" ? new CharacterMaterial({
796
+ isLocal: this.config.isLocal,
797
+ cameraManager: this.config.cameraManager,
798
+ characterId: this.config.characterId,
816
799
  originalMaterial
817
- ) : new CharacterMaterial(
818
- this.isLocal,
819
- this.cameraManager,
820
- this.characterId,
800
+ }) : new CharacterMaterial({
801
+ isLocal: this.config.isLocal,
802
+ cameraManager: this.config.cameraManager,
803
+ characterId: this.config.characterId,
821
804
  originalMaterial,
822
- originalMaterial.color
823
- );
805
+ colorOverride: originalMaterial.color
806
+ });
824
807
  this.materials.set(originalMaterial.name, material);
825
808
  asMesh.material = material;
826
809
  }
@@ -847,7 +830,7 @@ var CharacterModel = class {
847
830
  var _a, _b;
848
831
  if (((_a = mmlCharacterDescription.base) == null ? void 0 : _a.url.length) === 0) {
849
832
  throw new Error(
850
- "ERROR: An MML Character Description was provided but it's not a valid <m-character> string, or a valid URL"
833
+ "ERROR: An MML Character Description was provided, but it's not a valid <m-character> string, or a valid URL"
851
834
  );
852
835
  }
853
836
  let mergedCharacter = null;
@@ -855,27 +838,30 @@ var CharacterModel = class {
855
838
  const characterBase = ((_b = mmlCharacterDescription.base) == null ? void 0 : _b.url) || null;
856
839
  if (characterBase) {
857
840
  this.mmlCharacterDescription = mmlCharacterDescription;
858
- const mmlCharacter = new MMLCharacter(new ModelLoader());
841
+ const mmlCharacter = new MMLCharacter(_CharacterModel.ModelLoader);
859
842
  mergedCharacter = await mmlCharacter.mergeBodyParts(
860
843
  characterBase,
861
844
  mmlCharacterDescription.parts
862
845
  );
863
846
  if (mergedCharacter) {
864
- return mergedCharacter.children[0].children[0];
847
+ return mergedCharacter;
865
848
  }
866
849
  }
867
850
  }
868
851
  }
869
852
  async loadCharacterFromDescription() {
870
- if (this.characterDescription.meshFileUrl) {
871
- return await this.characterModelLoader.load(this.characterDescription.meshFileUrl, "model") || null;
853
+ if (this.config.characterDescription.meshFileUrl) {
854
+ return await this.config.characterModelLoader.load(
855
+ this.config.characterDescription.meshFileUrl,
856
+ "model"
857
+ ) || null;
872
858
  }
873
859
  let mmlCharacterSource;
874
- if (this.characterDescription.mmlCharacterUrl) {
875
- const res = await fetch(this.characterDescription.mmlCharacterUrl);
860
+ if (this.config.characterDescription.mmlCharacterUrl) {
861
+ const res = await fetch(this.config.characterDescription.mmlCharacterUrl);
876
862
  mmlCharacterSource = await res.text();
877
- } else if (this.characterDescription.mmlCharacterString) {
878
- mmlCharacterSource = this.characterDescription.mmlCharacterString;
863
+ } else if (this.config.characterDescription.mmlCharacterString) {
864
+ mmlCharacterSource = this.config.characterDescription.mmlCharacterString;
879
865
  } else {
880
866
  throw new Error(
881
867
  "ERROR: No Character Description was provided. Specify one of meshFileUrl, mmlCharacterUrl or mmlCharacterString"
@@ -917,7 +903,7 @@ var CharacterModel = class {
917
903
  }
918
904
  async setAnimationFromFile(animationFileUrl, animationType) {
919
905
  return new Promise(async (resolve, reject) => {
920
- const animation = await this.characterModelLoader.load(animationFileUrl, "animation");
906
+ const animation = await this.config.characterModelLoader.load(animationFileUrl, "animation");
921
907
  const cleanAnimation = this.cleanAnimationClips(this.mesh, animation);
922
908
  if (typeof animation !== "undefined" && cleanAnimation instanceof AnimationClip) {
923
909
  this.animations[animationType] = this.animationMixer.clipAction(cleanAnimation);
@@ -956,6 +942,8 @@ var CharacterModel = class {
956
942
  }
957
943
  }
958
944
  };
945
+ _CharacterModel.ModelLoader = new ModelLoader();
946
+ var CharacterModel = _CharacterModel;
959
947
 
960
948
  // src/character/CharacterSpeakingIndicator.ts
961
949
  import {
@@ -1116,27 +1104,27 @@ function CanvasText(message, options) {
1116
1104
  const padding = options.paddingPx || 0;
1117
1105
  const font = options.font || "Arial";
1118
1106
  const fontString = (options.bold ? "bold " : "") + fontsize + "px " + font;
1119
- const canvas = document.createElement("canvas");
1120
- const ct = canvas.getContext("2d");
1107
+ const canvas2 = document.createElement("canvas");
1108
+ const ct = canvas2.getContext("2d");
1121
1109
  const textAlign = options.alignment ?? "left";
1122
1110
  if (options.dimensions) {
1123
- canvas.width = options.dimensions.width;
1124
- canvas.height = options.dimensions.height;
1125
- ct.clearRect(0, 0, canvas.width, canvas.height);
1111
+ canvas2.width = options.dimensions.width;
1112
+ canvas2.height = options.dimensions.height;
1113
+ ct.clearRect(0, 0, canvas2.width, canvas2.height);
1126
1114
  ct.font = fontString;
1127
1115
  ct.textAlign = textAlign;
1128
1116
  ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1129
1117
  ct.lineWidth = 0;
1130
- ct.fillRect(0, 0, canvas.width, canvas.height);
1118
+ ct.fillRect(0, 0, canvas2.width, canvas2.height);
1131
1119
  ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1132
1120
  ct.font = fontString;
1133
1121
  printAtWordWrap(
1134
1122
  ct,
1135
1123
  message,
1136
- getTextAlignOffset(textAlign, canvas.width),
1124
+ getTextAlignOffset(textAlign, canvas2.width),
1137
1125
  fontsize,
1138
1126
  fontsize,
1139
- canvas.width,
1127
+ canvas2.width,
1140
1128
  padding,
1141
1129
  textAlign
1142
1130
  );
@@ -1145,28 +1133,28 @@ function CanvasText(message, options) {
1145
1133
  const metrics = ct.measureText(message);
1146
1134
  const textWidth = metrics.width;
1147
1135
  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);
1136
+ canvas2.width = textWidth + padding * 2;
1137
+ canvas2.height = textHeight + padding;
1138
+ ct.clearRect(0, 0, canvas2.width, canvas2.height);
1151
1139
  ct.font = fontString;
1152
1140
  ct.textAlign = textAlign;
1153
1141
  ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1154
1142
  ct.lineWidth = 0;
1155
- ct.fillRect(0, 0, canvas.width, canvas.height);
1143
+ ct.fillRect(0, 0, canvas2.width, canvas2.height);
1156
1144
  ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1157
1145
  ct.font = fontString;
1158
1146
  ct.fillText(message, padding + getTextAlignOffset(textAlign, textWidth), textHeight);
1159
1147
  }
1160
- return canvas;
1148
+ return canvas2;
1161
1149
  }
1162
1150
  function THREECanvasTextTexture(text, options) {
1163
- const canvas = CanvasText(text, options);
1164
- const texture = new Texture2(canvas);
1151
+ const canvas2 = CanvasText(text, options);
1152
+ const texture = new Texture2(canvas2);
1165
1153
  texture.minFilter = LinearFilter;
1166
1154
  texture.magFilter = LinearFilter;
1167
1155
  texture.format = RGBAFormat;
1168
1156
  texture.needsUpdate = true;
1169
- return { texture, width: canvas.width, height: canvas.height };
1157
+ return { texture, width: canvas2.width, height: canvas2.height };
1170
1158
  }
1171
1159
 
1172
1160
  // src/character/CharacterTooltip.ts
@@ -1175,20 +1163,19 @@ var defaultLabelColor = new Color2(0);
1175
1163
  var defaultFontColor = new Color2(16777215);
1176
1164
  var defaultLabelAlignment = "center" /* center */;
1177
1165
  var defaultLabelFontSize = 8;
1178
- var defaultLabelPadding = 0;
1166
+ var defaultLabelPadding = 8;
1179
1167
  var defaultLabelWidth = 0.25;
1180
1168
  var defaultLabelHeight = 0.1;
1181
1169
  var defaultLabelCastShadows = true;
1182
1170
  var tooltipGeometry = new PlaneGeometry(1, 1, 1, 1);
1183
1171
  var CharacterTooltip = class extends Mesh3 {
1184
- constructor() {
1172
+ constructor(configArg) {
1185
1173
  super(tooltipGeometry);
1186
1174
  this.visibleOpacity = 0.85;
1187
1175
  this.targetOpacity = 0;
1188
1176
  this.fadingSpeed = 0.02;
1189
1177
  this.secondsToFadeOut = 10;
1190
- this.props = {
1191
- content: "",
1178
+ this.config = {
1192
1179
  alignment: defaultLabelAlignment,
1193
1180
  width: defaultLabelWidth,
1194
1181
  height: defaultLabelHeight,
@@ -1196,7 +1183,8 @@ var CharacterTooltip = class extends Mesh3 {
1196
1183
  padding: defaultLabelPadding,
1197
1184
  color: defaultLabelColor,
1198
1185
  fontColor: defaultFontColor,
1199
- castShadows: defaultLabelCastShadows
1186
+ castShadows: defaultLabelCastShadows,
1187
+ ...configArg
1200
1188
  };
1201
1189
  this.tooltipMaterial = new MeshBasicMaterial2({
1202
1190
  map: null,
@@ -1217,25 +1205,21 @@ var CharacterTooltip = class extends Mesh3 {
1217
1205
  }
1218
1206
  const { texture, width, height } = THREECanvasTextTexture(content, {
1219
1207
  bold: true,
1220
- fontSize: this.props.fontSize * fontScale,
1221
- paddingPx: this.props.padding,
1208
+ fontSize: this.config.fontSize * fontScale,
1209
+ paddingPx: this.config.padding,
1222
1210
  textColorRGB255A1: {
1223
- r: this.props.fontColor.r * 255,
1224
- g: this.props.fontColor.g * 255,
1225
- b: this.props.fontColor.b * 255,
1211
+ r: this.config.fontColor.r * 255,
1212
+ g: this.config.fontColor.g * 255,
1213
+ b: this.config.fontColor.b * 255,
1226
1214
  a: 1
1227
1215
  },
1228
1216
  backgroundColorRGB255A1: {
1229
- r: this.props.color.r * 255,
1230
- g: this.props.color.g * 255,
1231
- b: this.props.color.b * 255,
1217
+ r: this.config.color.r * 255,
1218
+ g: this.config.color.g * 255,
1219
+ b: this.config.color.b * 255,
1232
1220
  a: 1
1233
1221
  },
1234
- dimensions: {
1235
- width: this.props.width * (100 * fontScale),
1236
- height: this.props.height * (100 * fontScale)
1237
- },
1238
- alignment: this.props.alignment
1222
+ alignment: this.config.alignment
1239
1223
  });
1240
1224
  this.tooltipMaterial.map = texture;
1241
1225
  this.tooltipMaterial.map.magFilter = LinearFilter2;
@@ -1246,7 +1230,8 @@ var CharacterTooltip = class extends Mesh3 {
1246
1230
  this.position.y = 1.4;
1247
1231
  }
1248
1232
  setText(text, temporary = false) {
1249
- this.redrawText(text);
1233
+ const sanitizedText = text.replace(/(\r\n|\n|\r)/gm, "");
1234
+ this.redrawText(sanitizedText);
1250
1235
  this.visible = true;
1251
1236
  this.targetOpacity = this.visibleOpacity;
1252
1237
  if (temporary) {
@@ -1287,39 +1272,43 @@ var CharacterTooltip = class extends Mesh3 {
1287
1272
 
1288
1273
  // src/character/Character.ts
1289
1274
  var Character = class extends Group {
1290
- constructor(characterDescription, animationConfig, characterModelLoader, characterId, modelLoadedCallback, cameraManager, composer, isLocal) {
1275
+ constructor(config) {
1291
1276
  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;
1277
+ this.config = config;
1300
1278
  this.model = null;
1301
1279
  this.color = new Color3();
1302
- this.tooltip = null;
1303
1280
  this.speakingIndicator = null;
1304
1281
  this.tooltip = new CharacterTooltip();
1282
+ this.tooltip.setText(this.config.username, this.config.isLocal);
1305
1283
  this.add(this.tooltip);
1284
+ this.load().then(() => {
1285
+ this.config.modelLoadedCallback();
1286
+ });
1287
+ }
1288
+ updateCharacter(username, characterDescription) {
1289
+ this.config.username = username;
1290
+ this.config.characterDescription = characterDescription;
1306
1291
  this.load();
1292
+ this.tooltip.setText(username, this.config.isLocal);
1307
1293
  }
1308
1294
  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
- );
1295
+ const previousModel = this.model;
1296
+ this.model = new CharacterModel({
1297
+ characterDescription: this.config.characterDescription,
1298
+ animationConfig: this.config.animationConfig,
1299
+ characterModelLoader: this.config.characterModelLoader,
1300
+ cameraManager: this.config.cameraManager,
1301
+ characterId: this.config.characterId,
1302
+ isLocal: this.config.isLocal
1303
+ });
1317
1304
  await this.model.init();
1305
+ if (previousModel && previousModel.mesh) {
1306
+ this.remove(previousModel.mesh);
1307
+ }
1318
1308
  this.add(this.model.mesh);
1319
1309
  if (this.speakingIndicator === null) {
1320
- this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1310
+ this.speakingIndicator = new CharacterSpeakingIndicator(this.config.composer.postPostScene);
1321
1311
  }
1322
- this.modelLoadedCallback();
1323
1312
  }
1324
1313
  updateAnimation(targetAnimation) {
1325
1314
  var _a;
@@ -1330,14 +1319,14 @@ var Character = class extends Group {
1330
1319
  if (!this.model)
1331
1320
  return;
1332
1321
  if (this.tooltip) {
1333
- this.tooltip.update(this.cameraManager.camera);
1322
+ this.tooltip.update(this.config.cameraManager.camera);
1334
1323
  }
1335
1324
  if (this.speakingIndicator) {
1336
1325
  this.speakingIndicator.setTime(time);
1337
1326
  if (this.model.mesh && this.model.headBone) {
1338
1327
  this.speakingIndicator.setBillboarding(
1339
1328
  (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
1340
- this.cameraManager.camera
1329
+ this.config.cameraManager.camera
1341
1330
  );
1342
1331
  }
1343
1332
  }
@@ -1364,13 +1353,8 @@ var baseControl = 200;
1364
1353
  var collisionDetectionSteps = 15;
1365
1354
  var minimumSurfaceAngle = 0.9;
1366
1355
  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;
1356
+ constructor(config) {
1357
+ this.config = config;
1374
1358
  this.capsuleInfo = {
1375
1359
  radius: 0.4,
1376
1360
  segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
@@ -1408,53 +1392,54 @@ var LocalController = class {
1408
1392
  this.surfaceTempRay = new Ray();
1409
1393
  this.lastFrameSurfaceState = null;
1410
1394
  this.networkState = {
1411
- id: this.id,
1395
+ id: this.config.id,
1412
1396
  position: { x: 0, y: 0, z: 0 },
1413
1397
  rotation: { quaternionY: 0, quaternionW: 1 },
1414
1398
  state: 0 /* idle */
1415
1399
  };
1416
1400
  }
1417
1401
  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;
1402
+ var _a, _b, _c, _d, _e;
1403
+ this.forward = this.config.keyInputManager.forward || ((_a = this.config.virtualJoystick) == null ? void 0 : _a.up) || false;
1404
+ this.backward = this.config.keyInputManager.backward || ((_b = this.config.virtualJoystick) == null ? void 0 : _b.down) || false;
1405
+ this.left = this.config.keyInputManager.left || ((_c = this.config.virtualJoystick) == null ? void 0 : _c.left) || false;
1406
+ this.right = this.config.keyInputManager.right || ((_d = this.config.virtualJoystick) == null ? void 0 : _d.right) || false;
1407
+ this.run = this.config.keyInputManager.run;
1408
+ this.jump = this.config.keyInputManager.jump;
1409
+ this.anyDirection = this.config.keyInputManager.anyDirection || ((_e = this.config.virtualJoystick) == null ? void 0 : _e.hasDirection) || false;
1410
+ this.conflictingDirections = this.config.keyInputManager.conflictingDirection;
1426
1411
  }
1427
1412
  update() {
1428
1413
  this.updateControllerState();
1429
- this.rayCaster.set(this.character.position, this.vectorDown);
1430
- const firstRaycastHit = this.collisionsManager.raycastFirst(this.rayCaster.ray);
1414
+ this.rayCaster.set(this.config.character.position, this.vectorDown);
1415
+ const firstRaycastHit = this.config.collisionsManager.raycastFirst(this.rayCaster.ray);
1431
1416
  if (firstRaycastHit !== null) {
1432
1417
  this.currentHeight = firstRaycastHit[0];
1433
1418
  this.currentSurfaceAngle.copy(firstRaycastHit[1]);
1434
1419
  }
1435
1420
  if (this.anyDirection || !this.characterOnGround) {
1436
1421
  const targetAnimation = this.getTargetAnimation();
1437
- this.character.updateAnimation(targetAnimation);
1422
+ this.config.character.updateAnimation(targetAnimation);
1438
1423
  } else {
1439
- this.character.updateAnimation(0 /* idle */);
1424
+ this.config.character.updateAnimation(0 /* idle */);
1440
1425
  }
1441
1426
  if (this.anyDirection) {
1442
1427
  this.updateRotation();
1443
1428
  }
1444
1429
  for (let i = 0; i < collisionDetectionSteps; i++) {
1445
1430
  this.updatePosition(
1446
- this.timeManager.deltaTime,
1447
- this.timeManager.deltaTime / collisionDetectionSteps,
1431
+ this.config.timeManager.deltaTime,
1432
+ this.config.timeManager.deltaTime / collisionDetectionSteps,
1448
1433
  i
1449
1434
  );
1450
1435
  }
1451
- if (this.character.position.y < 0) {
1436
+ if (this.config.character.position.y < 0) {
1452
1437
  this.resetPosition();
1453
1438
  }
1454
1439
  this.updateNetworkState();
1455
1440
  }
1456
1441
  getTargetAnimation() {
1457
- if (!this.character)
1442
+ if (!this.config.character)
1458
1443
  return 0 /* idle */;
1459
1444
  const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8;
1460
1445
  if (this.currentHeight > jumpHeight && !this.characterOnGround) {
@@ -1487,22 +1472,22 @@ var LocalController = class {
1487
1472
  }
1488
1473
  }
1489
1474
  updateAzimuthalAngle() {
1490
- const camToModelDistance = this.cameraManager.camera.position.distanceTo(
1491
- this.character.position
1475
+ const camToModelDistance = this.config.cameraManager.camera.position.distanceTo(
1476
+ this.config.character.position
1492
1477
  );
1493
1478
  const isCameraFirstPerson = camToModelDistance < 2;
1494
1479
  if (isCameraFirstPerson) {
1495
- const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.cameraManager.camera.quaternion);
1480
+ const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.config.cameraManager.camera.quaternion);
1496
1481
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1497
1482
  } else {
1498
1483
  this.azimuthalAngle = Math.atan2(
1499
- this.cameraManager.camera.position.x - this.character.position.x,
1500
- this.cameraManager.camera.position.z - this.character.position.z
1484
+ this.config.cameraManager.camera.position.x - this.config.character.position.x,
1485
+ this.config.cameraManager.camera.position.z - this.config.character.position.z
1501
1486
  );
1502
1487
  }
1503
1488
  }
1504
1489
  computeAngularDifference(rotationQuaternion) {
1505
- return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion)));
1490
+ return 2 * Math.acos(Math.abs(this.config.character.quaternion.dot(rotationQuaternion)));
1506
1491
  }
1507
1492
  updateRotation() {
1508
1493
  this.updateRotationOffset();
@@ -1514,8 +1499,8 @@ var LocalController = class {
1514
1499
  const angularDifference = this.computeAngularDifference(rotationQuaternion);
1515
1500
  const desiredTime = 0.07;
1516
1501
  const angularSpeed = angularDifference / desiredTime;
1517
- const frameRotation = angularSpeed * this.timeManager.deltaTime;
1518
- this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1502
+ const frameRotation = angularSpeed * this.config.timeManager.deltaTime;
1503
+ this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1519
1504
  }
1520
1505
  applyControls(deltaTime) {
1521
1506
  const resistance = this.characterOnGround ? groundResistance : airResistance;
@@ -1567,31 +1552,31 @@ var LocalController = class {
1567
1552
  }
1568
1553
  acceleration.add(controlAcceleration);
1569
1554
  this.characterVelocity.addScaledVector(acceleration, deltaTime);
1570
- this.character.position.addScaledVector(this.characterVelocity, deltaTime);
1555
+ this.config.character.position.addScaledVector(this.characterVelocity, deltaTime);
1571
1556
  }
1572
1557
  updatePosition(deltaTime, stepDeltaTime, iter) {
1573
1558
  this.applyControls(stepDeltaTime);
1574
1559
  if (iter === 0) {
1575
- const lastMovement = this.getMovementFromSurfaces(this.character.position, deltaTime);
1560
+ const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime);
1576
1561
  if (lastMovement) {
1577
- this.character.position.add(lastMovement.position);
1578
- const asQuaternion = this.tempQuaternion.setFromEuler(this.character.rotation);
1562
+ this.config.character.position.add(lastMovement.position);
1563
+ const asQuaternion = this.tempQuaternion.setFromEuler(this.config.character.rotation);
1579
1564
  const lastMovementEuler = this.tempEuler.setFromQuaternion(lastMovement.rotation);
1580
1565
  lastMovementEuler.x = 0;
1581
1566
  lastMovementEuler.z = 0;
1582
1567
  lastMovement.rotation.setFromEuler(lastMovementEuler);
1583
1568
  asQuaternion.multiply(lastMovement.rotation);
1584
- this.character.rotation.setFromQuaternion(asQuaternion);
1569
+ this.config.character.rotation.setFromQuaternion(asQuaternion);
1585
1570
  }
1586
1571
  }
1587
- this.character.updateMatrixWorld();
1572
+ this.config.character.updateMatrixWorld();
1588
1573
  const avatarSegment = this.tempSegment;
1589
1574
  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);
1575
+ avatarSegment.start.applyMatrix4(this.config.character.matrixWorld).applyMatrix4(this.tempMatrix);
1576
+ avatarSegment.end.applyMatrix4(this.config.character.matrixWorld).applyMatrix4(this.tempMatrix);
1592
1577
  const positionBeforeCollisions = this.tempVector.copy(avatarSegment.start);
1593
- this.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1594
- this.character.position.copy(avatarSegment.start);
1578
+ this.config.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1579
+ this.config.character.position.copy(avatarSegment.start);
1595
1580
  const deltaCollisionPosition = avatarSegment.start.sub(positionBeforeCollisions);
1596
1581
  this.characterOnGround = deltaCollisionPosition.y > 0;
1597
1582
  if (this.characterWasOnGround && !this.characterOnGround) {
@@ -1636,7 +1621,7 @@ var LocalController = class {
1636
1621
  }
1637
1622
  newPosition.setY(newPosition.y + 0.05);
1638
1623
  const ray = this.surfaceTempRay.set(newPosition, downVector);
1639
- const hit = this.collisionsManager.raycastFirst(ray);
1624
+ const hit = this.config.collisionsManager.raycastFirst(ray);
1640
1625
  if (hit && hit[0] < 0.8) {
1641
1626
  const currentCollisionMeshState = hit[2];
1642
1627
  this.lastFrameSurfaceState = [
@@ -1655,53 +1640,61 @@ var LocalController = class {
1655
1640
  return lastMovement;
1656
1641
  }
1657
1642
  updateNetworkState() {
1658
- const characterQuaternion = this.character.getWorldQuaternion(this.tempQuaternion);
1643
+ const characterQuaternion = this.config.character.getWorldQuaternion(this.tempQuaternion);
1659
1644
  this.networkState = {
1660
- id: this.id,
1645
+ id: this.config.id,
1661
1646
  position: {
1662
- x: this.character.position.x,
1663
- y: this.character.position.y,
1664
- z: this.character.position.z
1647
+ x: this.config.character.position.x,
1648
+ y: this.config.character.position.y,
1649
+ z: this.config.character.position.z
1665
1650
  },
1666
1651
  rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
1667
- state: this.character.getCurrentAnimation()
1652
+ state: this.config.character.getCurrentAnimation()
1668
1653
  };
1669
1654
  }
1670
1655
  resetPosition() {
1671
1656
  this.characterVelocity.y = 0;
1672
- this.character.position.y = 3;
1657
+ this.config.character.position.y = 3;
1673
1658
  this.characterOnGround = false;
1674
1659
  }
1675
1660
  };
1676
1661
 
1677
1662
  // src/character/RemoteController.ts
1678
1663
  import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
1664
+ var tempQuaternion = new Quaternion3();
1679
1665
  var RemoteController = class {
1680
- constructor(character, id) {
1681
- this.character = character;
1682
- this.id = id;
1666
+ constructor(config) {
1667
+ this.config = config;
1683
1668
  this.currentAnimation = 0 /* idle */;
1684
1669
  this.networkState = {
1685
- id: this.id,
1686
- position: { x: 0, y: 0, z: 0 },
1687
- rotation: { quaternionY: 0, quaternionW: 1 },
1670
+ id: this.config.id,
1671
+ position: {
1672
+ x: this.config.character.position.x,
1673
+ y: this.config.character.position.y,
1674
+ z: this.config.character.position.z
1675
+ },
1676
+ rotation: {
1677
+ quaternionY: tempQuaternion.setFromEuler(this.config.character.rotation).y,
1678
+ quaternionW: 1
1679
+ },
1688
1680
  state: this.currentAnimation
1689
1681
  };
1690
1682
  }
1691
1683
  update(clientUpdate, time, deltaTime) {
1692
- if (!this.character)
1684
+ if (!this.config.character) {
1693
1685
  return;
1686
+ }
1694
1687
  this.updateFromNetwork(clientUpdate);
1695
- this.character.update(time, deltaTime);
1688
+ this.config.character.update(time, deltaTime);
1696
1689
  }
1697
1690
  updateFromNetwork(clientUpdate) {
1698
1691
  const { position, rotation, state } = clientUpdate;
1699
- this.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1692
+ this.config.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1700
1693
  const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1701
- this.character.quaternion.slerp(rotationQuaternion, 0.6);
1694
+ this.config.character.quaternion.slerp(rotationQuaternion, 0.6);
1702
1695
  if (state !== this.currentAnimation) {
1703
1696
  this.currentAnimation = state;
1704
- this.character.updateAnimation(state);
1697
+ this.config.character.updateAnimation(state);
1705
1698
  }
1706
1699
  }
1707
1700
  };
@@ -1732,20 +1725,11 @@ function decodeCharacterAndCamera(hash) {
1732
1725
 
1733
1726
  // src/character/CharacterManager.ts
1734
1727
  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;
1728
+ constructor(config) {
1729
+ this.config = config;
1746
1730
  this.updateLocationHash = true;
1747
1731
  this.headTargetOffset = new Vector38(0, 1.3, 0);
1748
- this.id = 0;
1732
+ this.localClientId = 0;
1749
1733
  this.remoteCharacters = /* @__PURE__ */ new Map();
1750
1734
  this.remoteCharacterControllers = /* @__PURE__ */ new Map();
1751
1735
  this.localCharacterSpawned = false;
@@ -1753,21 +1737,21 @@ var CharacterManager = class {
1753
1737
  this.speakingCharacters = /* @__PURE__ */ new Map();
1754
1738
  this.group = new Group2();
1755
1739
  }
1756
- spawnLocalCharacter(characterDescription, id, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1757
- var _a;
1758
- const character = new Character(
1740
+ spawnLocalCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1741
+ const character = new Character({
1742
+ username,
1759
1743
  characterDescription,
1760
- this.animationConfig,
1761
- this.characterModelLoader,
1762
- id,
1763
- () => {
1744
+ animationConfig: this.config.animationConfig,
1745
+ characterModelLoader: this.config.characterModelLoader,
1746
+ characterId: id,
1747
+ modelLoadedCallback: () => {
1764
1748
  },
1765
- this.cameraManager,
1766
- this.composer,
1767
- true
1768
- );
1749
+ cameraManager: this.config.cameraManager,
1750
+ composer: this.config.composer,
1751
+ isLocal: true
1752
+ });
1769
1753
  const quaternion = new Quaternion5().setFromEuler(character.rotation);
1770
- this.sendUpdate({
1754
+ this.config.sendUpdate({
1771
1755
  id,
1772
1756
  position: {
1773
1757
  x: spawnPosition.x,
@@ -1777,41 +1761,40 @@ var CharacterManager = class {
1777
1761
  rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
1778
1762
  state: 0 /* idle */
1779
1763
  });
1780
- this.id = id;
1764
+ this.localClientId = id;
1781
1765
  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
- );
1766
+ this.localController = new LocalController({
1767
+ character: this.localCharacter,
1768
+ id: this.localClientId,
1769
+ collisionsManager: this.config.collisionsManager,
1770
+ keyInputManager: this.config.keyInputManager,
1771
+ virtualJoystick: this.config.virtualJoystick,
1772
+ cameraManager: this.config.cameraManager,
1773
+ timeManager: this.config.timeManager
1774
+ });
1790
1775
  this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1791
1776
  this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1792
- (_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`, true);
1793
1777
  this.group.add(character);
1794
1778
  this.localCharacterSpawned = true;
1795
1779
  }
1796
- spawnRemoteCharacter(characterDescription, id, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1797
- var _a;
1798
- const character = new Character(
1780
+ spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1781
+ const character = new Character({
1782
+ username,
1799
1783
  characterDescription,
1800
- this.animationConfig,
1801
- this.characterModelLoader,
1802
- id,
1803
- () => {
1784
+ animationConfig: this.config.animationConfig,
1785
+ characterModelLoader: this.config.characterModelLoader,
1786
+ characterId: id,
1787
+ modelLoadedCallback: () => {
1804
1788
  },
1805
- this.cameraManager,
1806
- this.composer,
1807
- false
1808
- );
1789
+ cameraManager: this.config.cameraManager,
1790
+ composer: this.config.composer,
1791
+ isLocal: false
1792
+ });
1809
1793
  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);
1794
+ character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1795
+ character.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1796
+ const remoteController = new RemoteController({ character, id });
1813
1797
  this.remoteCharacterControllers.set(id, remoteController);
1814
- (_a = character.tooltip) == null ? void 0 : _a.setText(`${id}`);
1815
1798
  this.group.add(character);
1816
1799
  }
1817
1800
  getLocalCharacterPositionAndRotation() {
@@ -1840,50 +1823,71 @@ var CharacterManager = class {
1840
1823
  setSpeakingCharacter(id, value) {
1841
1824
  this.speakingCharacters.set(id, value);
1842
1825
  }
1826
+ respawnIfPresent(id) {
1827
+ const characterInfo = this.config.characterResolve(id);
1828
+ if (this.localCharacter && this.localClientId == id) {
1829
+ this.localCharacter.updateCharacter(
1830
+ characterInfo.username,
1831
+ characterInfo.characterDescription
1832
+ );
1833
+ }
1834
+ const remoteCharacter = this.remoteCharacters.get(id);
1835
+ if (remoteCharacter) {
1836
+ remoteCharacter.updateCharacter(characterInfo.username, characterInfo.characterDescription);
1837
+ }
1838
+ }
1843
1839
  update() {
1844
1840
  var _a, _b, _c;
1845
1841
  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));
1842
+ this.localCharacter.update(this.config.timeManager.time, this.config.timeManager.deltaTime);
1843
+ if (this.speakingCharacters.has(this.localClientId)) {
1844
+ (_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(
1845
+ this.speakingCharacters.get(this.localClientId)
1846
+ );
1849
1847
  }
1850
1848
  this.localController.update();
1851
- if (this.timeManager.frame % 2 === 0) {
1852
- this.sendUpdate(this.localController.networkState);
1849
+ if (this.config.timeManager.frame % 2 === 0) {
1850
+ this.config.sendUpdate(this.localController.networkState);
1853
1851
  }
1854
1852
  const targetOffset = new Vector38();
1855
1853
  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) {
1854
+ this.config.cameraManager.setTarget(targetOffset);
1855
+ for (const [id, update] of this.config.remoteUserStates) {
1858
1856
  if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
1859
1857
  const character = this.remoteCharacters.get(id);
1860
1858
  (_b = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _b.setSpeaking(this.speakingCharacters.get(id));
1861
1859
  }
1862
1860
  const { position } = update;
1863
1861
  if (!this.remoteCharacters.has(id) && this.localCharacterSpawned === true) {
1862
+ const characterInfo = this.config.characterResolve(id);
1864
1863
  this.spawnRemoteCharacter(
1865
- this.characterDescription,
1866
1864
  id,
1865
+ characterInfo.username,
1866
+ characterInfo.characterDescription,
1867
1867
  new Vector38(position.x, position.y, position.z)
1868
1868
  );
1869
1869
  }
1870
1870
  const characterController = this.remoteCharacterControllers.get(id);
1871
1871
  if (characterController) {
1872
- characterController.update(update, this.timeManager.time, this.timeManager.deltaTime);
1872
+ characterController.update(
1873
+ update,
1874
+ this.config.timeManager.time,
1875
+ this.config.timeManager.deltaTime
1876
+ );
1873
1877
  }
1874
1878
  }
1875
1879
  for (const [id, character] of this.remoteCharacters) {
1876
- if (!this.clientStates.has(id)) {
1880
+ if (!this.config.remoteUserStates.has(id)) {
1877
1881
  (_c = character.speakingIndicator) == null ? void 0 : _c.dispose();
1878
1882
  this.group.remove(character);
1879
1883
  this.remoteCharacters.delete(id);
1880
1884
  this.remoteCharacterControllers.delete(id);
1881
1885
  }
1882
1886
  }
1883
- if (this.updateLocationHash && this.timeManager.frame % 60 === 0) {
1887
+ if (this.updateLocationHash && this.config.timeManager.frame % 60 === 0) {
1884
1888
  window.location.hash = encodeCharacterAndCamera(
1885
1889
  this.localCharacter,
1886
- this.cameraManager.camera
1890
+ this.config.cameraManager.camera
1887
1891
  );
1888
1892
  }
1889
1893
  }
@@ -1891,32 +1895,7 @@ var CharacterManager = class {
1891
1895
  };
1892
1896
 
1893
1897
  // 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
- };
1898
+ import { ModelLoader as ModelLoader2 } from "@mml-io/model-loader";
1920
1899
  var LRUCache = class {
1921
1900
  constructor(maxSize = 100) {
1922
1901
  this.maxSize = maxSize;
@@ -1941,16 +1920,13 @@ var LRUCache = class {
1941
1920
  var CharacterModelLoader = class {
1942
1921
  constructor(maxCacheSize = 100, debug = false) {
1943
1922
  this.debug = debug;
1923
+ this.modelLoader = new ModelLoader2();
1944
1924
  this.ongoingLoads = /* @__PURE__ */ new Map();
1945
- this.loadingManager = new LoadingManager();
1946
- this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug);
1947
1925
  this.modelCache = new LRUCache(maxCacheSize);
1948
1926
  }
1949
1927
  async load(fileUrl, fileType) {
1950
1928
  const cachedModel = this.modelCache.get(fileUrl);
1951
1929
  if (cachedModel) {
1952
- const blobURL = URL.createObjectURL(cachedModel.blob);
1953
- this.gltfLoader.setBlobUrl(fileUrl, blobURL);
1954
1930
  return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
1955
1931
  } else {
1956
1932
  if (this.debug === true) {
@@ -1978,26 +1954,21 @@ var CharacterModelLoader = class {
1978
1954
  }
1979
1955
  async loadFromUrl(url, fileType, extension) {
1980
1956
  if (["gltf", "glb"].includes(extension)) {
1981
- return new Promise((resolve, reject) => {
1982
- this.gltfLoader.load(
1957
+ return new Promise(async (resolve, reject) => {
1958
+ const modelLoadResult = await this.modelLoader.load(
1983
1959
  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);
1960
+ (loaded, total) => {
1999
1961
  }
2000
1962
  );
1963
+ if (fileType === "model") {
1964
+ resolve(modelLoadResult.group);
1965
+ } else if (fileType === "animation") {
1966
+ resolve(modelLoadResult.animations[0]);
1967
+ } else {
1968
+ const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
1969
+ console.error(error);
1970
+ reject(error);
1971
+ }
2001
1972
  });
2002
1973
  } else {
2003
1974
  console.error(`Error: can't recognize ${url} extension: ${extension}`);
@@ -2011,17 +1982,9 @@ var KeyInputManager = class {
2011
1982
  this.shouldCaptureKeyPress = shouldCaptureKeyPress;
2012
1983
  this.keys = /* @__PURE__ */ new Map();
2013
1984
  this.eventHandlerCollection = new EventHandlerCollection();
2014
- this.directionJoystick = null;
2015
1985
  this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
2016
1986
  this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
2017
1987
  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
1988
  }
2026
1989
  handleUnfocus(_event) {
2027
1990
  this.keys.clear();
@@ -2045,19 +2008,19 @@ var KeyInputManager = class {
2045
2008
  return this.keys.get(key) || false;
2046
2009
  }
2047
2010
  isMovementKeyPressed() {
2048
- return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key)) || this.directionJoystick.hasDirection;
2011
+ return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
2049
2012
  }
2050
2013
  get forward() {
2051
- return this.isKeyPressed("w" /* W */) || this.directionJoystick.up;
2014
+ return this.isKeyPressed("w" /* W */);
2052
2015
  }
2053
2016
  get backward() {
2054
- return this.isKeyPressed("s" /* S */) || this.directionJoystick.down;
2017
+ return this.isKeyPressed("s" /* S */);
2055
2018
  }
2056
2019
  get left() {
2057
- return this.isKeyPressed("a" /* A */) || this.directionJoystick.left;
2020
+ return this.isKeyPressed("a" /* A */);
2058
2021
  }
2059
2022
  get right() {
2060
- return this.isKeyPressed("d" /* D */) || this.directionJoystick.right;
2023
+ return this.isKeyPressed("d" /* D */);
2061
2024
  }
2062
2025
  get run() {
2063
2026
  return this.isKeyPressed("shift" /* SHIFT */);
@@ -2085,40 +2048,35 @@ import {
2085
2048
  } from "mml-web";
2086
2049
  import { Group as Group3 } from "three";
2087
2050
  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;
2051
+ constructor(config) {
2052
+ this.config = config;
2095
2053
  this.chatProbes = /* @__PURE__ */ new Set();
2096
2054
  this.group = new Group3();
2097
- this.promptManager = PromptManager.init(targetElement);
2055
+ this.promptManager = PromptManager.init(this.config.targetElement);
2098
2056
  const { interactionListener, interactionManager } = InteractionManager.init(
2099
- targetElement,
2100
- this.camera,
2101
- this.scene
2057
+ this.config.targetElement,
2058
+ this.config.camera,
2059
+ this.config.scene
2102
2060
  );
2103
2061
  this.interactionManager = interactionManager;
2104
2062
  this.interactionListener = interactionListener;
2105
2063
  this.loadingProgressManager = new LoadingProgressManager();
2106
2064
  this.mmlScene = {
2107
- getAudioListener: () => this.audioListener,
2108
- getRenderer: () => this.renderer,
2109
- getThreeScene: () => this.scene,
2065
+ getAudioListener: () => this.config.audioListener,
2066
+ getRenderer: () => this.config.renderer,
2067
+ getThreeScene: () => this.config.scene,
2110
2068
  getRootContainer: () => this.group,
2111
- getCamera: () => this.camera,
2069
+ getCamera: () => this.config.camera,
2112
2070
  addCollider: (object, mElement) => {
2113
- this.collisionsManager.addMeshesGroup(object, mElement);
2071
+ this.config.collisionsManager.addMeshesGroup(object, mElement);
2114
2072
  },
2115
2073
  updateCollider: (object) => {
2116
- this.collisionsManager.updateMeshesGroup(object);
2074
+ this.config.collisionsManager.updateMeshesGroup(object);
2117
2075
  },
2118
2076
  removeCollider: (object) => {
2119
- this.collisionsManager.removeMeshesGroup(object);
2077
+ this.config.collisionsManager.removeMeshesGroup(object);
2120
2078
  },
2121
- getUserPositionAndRotation: this.getUserPositionAndRotation,
2079
+ getUserPositionAndRotation: this.config.getUserPositionAndRotation,
2122
2080
  addInteraction: (interaction) => {
2123
2081
  this.interactionListener.addInteraction(interaction);
2124
2082
  },
@@ -2143,7 +2101,7 @@ var MMLCompositionScene = class {
2143
2101
  return this.loadingProgressManager;
2144
2102
  }
2145
2103
  };
2146
- this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
2104
+ this.clickTrigger = MMLClickTrigger.init(this.config.targetElement, this.mmlScene);
2147
2105
  }
2148
2106
  onChatMessage(message) {
2149
2107
  for (const chatProbe of this.chatProbes) {
@@ -2214,7 +2172,7 @@ var sunValues = {
2214
2172
  sunAzimuthalAngle: 214.5,
2215
2173
  sunPolarAngle: -41.5
2216
2174
  },
2217
- sunIntensity: 1,
2175
+ sunIntensity: 2,
2218
2176
  sunColor: { r: 1, g: 1, b: 1 }
2219
2177
  };
2220
2178
  var sunOptions = {
@@ -2226,7 +2184,7 @@ var sunOptions = {
2226
2184
  };
2227
2185
  var envValues = {
2228
2186
  ambientLight: {
2229
- ambientLightIntensity: 0.05,
2187
+ ambientLightIntensity: 0.1,
2230
2188
  ambientLightColor: { r: 1, g: 1, b: 1 }
2231
2189
  },
2232
2190
  fog: {
@@ -2742,6 +2700,10 @@ var SSAOFolder = class {
2742
2700
  case "enabled":
2743
2701
  if (e.value === true) {
2744
2702
  composer.addPass(n8aopass, this.postProcessingSSAOIndex + 2);
2703
+ composer.passes[this.postProcessingSSAOIndex + 2].setSize(
2704
+ window.innerWidth,
2705
+ window.innerHeight
2706
+ );
2745
2707
  } else {
2746
2708
  composer.removePass(n8aopass);
2747
2709
  }
@@ -2942,16 +2904,26 @@ var tweakPaneStyle = `
2942
2904
 
2943
2905
  // src/tweakpane/TweakPane.ts
2944
2906
  var TweakPane = class {
2945
- constructor(renderer, scene, composer) {
2907
+ constructor(holderElement, renderer, scene, composer) {
2908
+ this.holderElement = holderElement;
2946
2909
  this.renderer = renderer;
2947
2910
  this.scene = scene;
2948
2911
  this.composer = composer;
2949
2912
  this.saveVisibilityInLocalStorage = true;
2950
2913
  this.guiVisible = false;
2951
- const appWrapper = document.getElementById("app");
2952
2914
  const tweakPaneWrapper = document.createElement("div");
2953
- tweakPaneWrapper.id = "tweakpane-panel";
2954
- appWrapper.appendChild(tweakPaneWrapper);
2915
+ tweakPaneWrapper.style.position = "fixed";
2916
+ tweakPaneWrapper.style.width = "400px";
2917
+ tweakPaneWrapper.style.height = "100%";
2918
+ tweakPaneWrapper.style.top = "0px";
2919
+ tweakPaneWrapper.style.right = "calc(-50vw)";
2920
+ tweakPaneWrapper.style.zIndex = "99";
2921
+ tweakPaneWrapper.style.overflow = "auto";
2922
+ tweakPaneWrapper.style.backgroundColor = "rgba(0, 0, 0, 0.66)";
2923
+ tweakPaneWrapper.style.paddingLeft = "5px";
2924
+ tweakPaneWrapper.style.boxShadow = "-7px 0px 12px rgba(0, 0, 0, 0.5)";
2925
+ tweakPaneWrapper.style.transition = "right cubic-bezier(0.83, 0, 0.17, 1) 0.7s";
2926
+ holderElement.appendChild(tweakPaneWrapper);
2955
2927
  this.gui = new Pane({ container: tweakPaneWrapper });
2956
2928
  this.gui.registerPlugin(EssentialsPlugin);
2957
2929
  if (this.saveVisibilityInLocalStorage) {
@@ -3077,6 +3049,7 @@ var TweakPane = class {
3077
3049
  };
3078
3050
 
3079
3051
  // src/rendering/composer.ts
3052
+ import { HDRJPGLoader } from "@monogrid/gainmap-js";
3080
3053
  import {
3081
3054
  EffectComposer as EffectComposer2,
3082
3055
  RenderPass,
@@ -3100,12 +3073,13 @@ import {
3100
3073
  Fog as Fog2,
3101
3074
  HalfFloatType as HalfFloatType2,
3102
3075
  LinearSRGBColorSpace,
3103
- LoadingManager as LoadingManager2,
3076
+ LoadingManager,
3104
3077
  PMREMGenerator,
3105
3078
  SRGBColorSpace,
3106
3079
  Scene as Scene4,
3107
3080
  Vector2 as Vector27,
3108
- WebGLRenderer as WebGLRenderer4
3081
+ WebGLRenderer as WebGLRenderer4,
3082
+ EquirectangularReflectionMapping
3109
3083
  } from "three";
3110
3084
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
3111
3085
 
@@ -3135,7 +3109,7 @@ var Sun = class extends Group4 {
3135
3109
  if (this.debug === true) {
3136
3110
  this.camHelper = new CameraHelper(this.shadowCamera);
3137
3111
  }
3138
- this.directionalLight = new DirectionalLight(16777215, 0.5);
3112
+ this.directionalLight = new DirectionalLight(16777215);
3139
3113
  this.directionalLight.intensity = sunValues.sunIntensity;
3140
3114
  this.directionalLight.shadow.normalBias = 0.01;
3141
3115
  this.directionalLight.shadow.radius = 0.02;
@@ -4840,11 +4814,30 @@ var Composer = class {
4840
4814
  this.effectComposer.render();
4841
4815
  this.renderer.render(this.postPostScene, this.camera);
4842
4816
  }
4817
+ useHDRJPG(url, fromFile = false) {
4818
+ const pmremGenerator = new PMREMGenerator(this.renderer);
4819
+ const hdrJpg = new HDRJPGLoader(this.renderer).load(url, () => {
4820
+ const hdrJpgEquirectangularMap = hdrJpg.renderTarget.texture;
4821
+ hdrJpgEquirectangularMap.mapping = EquirectangularReflectionMapping;
4822
+ hdrJpgEquirectangularMap.needsUpdate = true;
4823
+ const envMap = pmremGenerator.fromEquirectangular(hdrJpgEquirectangularMap).texture;
4824
+ if (envMap) {
4825
+ envMap.colorSpace = LinearSRGBColorSpace;
4826
+ envMap.needsUpdate = true;
4827
+ this.scene.background = envMap;
4828
+ this.scene.backgroundIntensity = rendererValues.bgIntensity;
4829
+ this.isEnvHDRI = true;
4830
+ hdrJpgEquirectangularMap.dispose();
4831
+ pmremGenerator.dispose();
4832
+ }
4833
+ hdrJpg.dispose();
4834
+ });
4835
+ }
4843
4836
  useHDRI(url, fromFile = false) {
4844
4837
  if (this.isEnvHDRI && fromFile === false || !this.renderer)
4845
4838
  return;
4846
4839
  const pmremGenerator = new PMREMGenerator(this.renderer);
4847
- new RGBELoader(new LoadingManager2()).load(
4840
+ new RGBELoader(new LoadingManager()).load(
4848
4841
  url,
4849
4842
  (texture) => {
4850
4843
  const envMap = pmremGenerator.fromEquirectangular(texture).texture;
@@ -4870,7 +4863,7 @@ var Composer = class {
4870
4863
  return;
4871
4864
  const fileInput = document.createElement("input");
4872
4865
  fileInput.type = "file";
4873
- fileInput.accept = ".hdr";
4866
+ fileInput.accept = ".hdr,.jpg";
4874
4867
  fileInput.addEventListener("change", () => {
4875
4868
  var _a;
4876
4869
  const file = (_a = fileInput.files) == null ? void 0 : _a[0];
@@ -4878,9 +4871,16 @@ var Composer = class {
4878
4871
  console.log("no file");
4879
4872
  return;
4880
4873
  }
4874
+ const extension = file.name.split(".").pop();
4881
4875
  const fileURL = URL.createObjectURL(file);
4882
4876
  if (fileURL) {
4883
- this.useHDRI(fileURL, true);
4877
+ if (extension === "hdr") {
4878
+ this.useHDRI(fileURL, true);
4879
+ } else if (extension === "jpg") {
4880
+ this.useHDRJPG(fileURL);
4881
+ } else {
4882
+ console.error(`Unrecognized extension for HDR file ${file.name}`);
4883
+ }
4884
4884
  URL.revokeObjectURL(fileURL);
4885
4885
  document.body.removeChild(fileInput);
4886
4886
  }
@@ -5195,6 +5195,200 @@ var CollisionsManager = class {
5195
5195
  this.collisionTrigger.setCurrentCollisions(reportedCollidingElements);
5196
5196
  }
5197
5197
  };
5198
+
5199
+ // src/ground-plane/GroundPlane.ts
5200
+ import {
5201
+ CanvasTexture,
5202
+ CircleGeometry as CircleGeometry2,
5203
+ FrontSide as FrontSide2,
5204
+ Group as Group6,
5205
+ LinearMipMapLinearFilter,
5206
+ Mesh as Mesh6,
5207
+ MeshStandardMaterial as MeshStandardMaterial3,
5208
+ NearestFilter as NearestFilter2,
5209
+ RepeatWrapping as RepeatWrapping2
5210
+ } from "three";
5211
+ var canvas = document.createElement("canvas");
5212
+ canvas.width = 2;
5213
+ canvas.height = 2;
5214
+ var ctx = canvas.getContext("2d");
5215
+ ctx.fillStyle = "#C0C0C0";
5216
+ ctx.fillRect(0, 0, 2, 2);
5217
+ ctx.fillStyle = "#808080";
5218
+ ctx.fillRect(0, 0, 1, 1);
5219
+ ctx.fillRect(1, 1, 1, 1);
5220
+ var GroundPlane = class extends Group6 {
5221
+ constructor() {
5222
+ super();
5223
+ this.floorSize = 210;
5224
+ this.floorTexture = null;
5225
+ this.floorGeometry = new CircleGeometry2(this.floorSize, this.floorSize);
5226
+ this.floorMesh = null;
5227
+ this.floorMaterial = new MeshStandardMaterial3({
5228
+ color: 16777215,
5229
+ side: FrontSide2,
5230
+ metalness: 0.05,
5231
+ roughness: 0.95
5232
+ });
5233
+ this.floorMesh = new Mesh6(this.floorGeometry, this.floorMaterial);
5234
+ this.floorMesh.receiveShadow = true;
5235
+ this.floorMesh.rotation.x = Math.PI * -0.5;
5236
+ this.add(this.floorMesh);
5237
+ this.floorTexture = new CanvasTexture(canvas);
5238
+ this.floorTexture.wrapS = RepeatWrapping2;
5239
+ this.floorTexture.wrapT = RepeatWrapping2;
5240
+ this.floorTexture.magFilter = NearestFilter2;
5241
+ this.floorTexture.minFilter = LinearMipMapLinearFilter;
5242
+ this.floorTexture.repeat.set(this.floorSize / 1.5, this.floorSize / 1.5);
5243
+ this.floorMaterial.map = this.floorTexture;
5244
+ this.floorMaterial.needsUpdate = true;
5245
+ }
5246
+ };
5247
+
5248
+ // src/loading-screen/LoadingScreen.ts
5249
+ import { LoadingProgressManager as LoadingProgressManager2 } from "mml-web";
5250
+ var LoadingScreen = class {
5251
+ constructor(loadingProgressManager) {
5252
+ this.loadingProgressManager = loadingProgressManager;
5253
+ this.hasCompleted = false;
5254
+ this.element = document.createElement("div");
5255
+ this.element.style.position = "absolute";
5256
+ this.element.style.top = "0";
5257
+ this.element.style.left = "0";
5258
+ this.element.style.width = "100%";
5259
+ this.element.style.height = "100%";
5260
+ this.element.style.background = "linear-gradient(45deg, #28284B 0%, #303056 100%)";
5261
+ this.element.style.color = "white";
5262
+ this.element.addEventListener("click", (event) => {
5263
+ event.stopPropagation();
5264
+ });
5265
+ this.element.addEventListener("mousedown", (event) => {
5266
+ event.stopPropagation();
5267
+ });
5268
+ this.element.addEventListener("mousemove", (event) => {
5269
+ event.stopPropagation();
5270
+ });
5271
+ this.element.addEventListener("mouseup", (event) => {
5272
+ event.stopPropagation();
5273
+ });
5274
+ this.loadingBannerText = document.createElement("div");
5275
+ this.loadingBannerText.textContent = "Loading...";
5276
+ this.loadingBannerText.style.position = "absolute";
5277
+ this.loadingBannerText.style.display = "flex";
5278
+ this.loadingBannerText.style.top = "0";
5279
+ this.loadingBannerText.style.left = "0";
5280
+ this.loadingBannerText.style.width = "100%";
5281
+ this.loadingBannerText.style.height = "100%";
5282
+ this.loadingBannerText.style.color = "white";
5283
+ this.loadingBannerText.style.fontSize = "80px";
5284
+ this.loadingBannerText.style.fontWeight = "bold";
5285
+ this.loadingBannerText.style.fontFamily = "sans-serif";
5286
+ this.loadingBannerText.style.alignItems = "center";
5287
+ this.loadingBannerText.style.justifyContent = "center";
5288
+ this.element.append(this.loadingBannerText);
5289
+ this.progressDebugViewHolder = document.createElement("div");
5290
+ this.progressDebugViewHolder.style.display = "flex";
5291
+ this.progressDebugViewHolder.style.position = "absolute";
5292
+ this.progressDebugViewHolder.style.maxHeight = "calc(100% - 74px)";
5293
+ this.progressDebugViewHolder.style.left = "0";
5294
+ this.progressDebugViewHolder.style.bottom = "74px";
5295
+ this.progressDebugViewHolder.style.width = "100%";
5296
+ this.progressDebugViewHolder.style.justifyContent = "center";
5297
+ this.element.append(this.progressDebugViewHolder);
5298
+ this.progressDebugView = document.createElement("div");
5299
+ this.progressDebugView.style.backgroundColor = "rgba(128, 128, 128, 0.25)";
5300
+ this.progressDebugView.style.border = "1px solid black";
5301
+ this.progressDebugView.style.maxWidth = "100%";
5302
+ this.progressDebugView.style.overflow = "auto";
5303
+ this.progressDebugViewHolder.append(this.progressDebugView);
5304
+ this.debugCheckbox = document.createElement("input");
5305
+ this.debugCheckbox.type = "checkbox";
5306
+ this.debugCheckbox.checked = false;
5307
+ this.debugCheckbox.addEventListener("change", () => {
5308
+ this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
5309
+ if (this.hasCompleted) {
5310
+ this.dispose();
5311
+ }
5312
+ });
5313
+ this.debugLabel = document.createElement("label");
5314
+ this.debugLabel.textContent = "Debug loading";
5315
+ this.debugLabel.style.fontFamily = "sans-serif";
5316
+ this.debugLabel.style.padding = "5px";
5317
+ this.debugLabel.style.display = "inline-block";
5318
+ this.debugLabel.style.userSelect = "none";
5319
+ this.debugLabel.append(this.debugCheckbox);
5320
+ this.progressDebugView.append(this.debugLabel);
5321
+ this.progressDebugElement = document.createElement("pre");
5322
+ this.progressDebugElement.style.margin = "0";
5323
+ this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
5324
+ this.progressDebugView.append(this.progressDebugElement);
5325
+ this.progressBarHolder = document.createElement("div");
5326
+ this.progressBarHolder.style.display = "flex";
5327
+ this.progressBarHolder.style.alignItems = "center";
5328
+ this.progressBarHolder.style.justifyContent = "center";
5329
+ this.progressBarHolder.style.position = "absolute";
5330
+ this.progressBarHolder.style.bottom = "20px";
5331
+ this.progressBarHolder.style.left = "0";
5332
+ this.progressBarHolder.style.width = "100%";
5333
+ this.element.append(this.progressBarHolder);
5334
+ this.progressBarBackground = document.createElement("div");
5335
+ this.progressBarBackground.style.position = "relative";
5336
+ this.progressBarBackground.style.width = "500px";
5337
+ this.progressBarBackground.style.maxWidth = "80%";
5338
+ this.progressBarBackground.style.backgroundColor = "gray";
5339
+ this.progressBarBackground.style.height = "50px";
5340
+ this.progressBarBackground.style.lineHeight = "50px";
5341
+ this.progressBarBackground.style.borderRadius = "25px";
5342
+ this.progressBarBackground.style.border = "2px solid white";
5343
+ this.progressBarBackground.style.overflow = "hidden";
5344
+ this.progressBarHolder.append(this.progressBarBackground);
5345
+ this.progressBar = document.createElement("div");
5346
+ this.progressBar.style.position = "absolute";
5347
+ this.progressBar.style.top = "0";
5348
+ this.progressBar.style.left = "0";
5349
+ this.progressBar.style.width = "0";
5350
+ this.progressBar.style.height = "100%";
5351
+ this.progressBar.style.backgroundColor = "#0050a4";
5352
+ this.progressBarBackground.append(this.progressBar);
5353
+ this.loadingStatusText = document.createElement("div");
5354
+ this.loadingStatusText.style.position = "absolute";
5355
+ this.loadingStatusText.style.top = "0";
5356
+ this.loadingStatusText.style.left = "0";
5357
+ this.loadingStatusText.style.width = "100%";
5358
+ this.loadingStatusText.style.height = "100%";
5359
+ this.loadingStatusText.style.color = "white";
5360
+ this.loadingStatusText.style.textAlign = "center";
5361
+ this.loadingStatusText.style.verticalAlign = "middle";
5362
+ this.loadingStatusText.style.fontFamily = "sans-serif";
5363
+ this.loadingStatusText.style.fontWeight = "bold";
5364
+ this.loadingStatusText.textContent = "Loading...";
5365
+ this.progressBarBackground.append(this.loadingStatusText);
5366
+ this.loadingCallback = () => {
5367
+ const [loadingRatio, completedLoading] = this.loadingProgressManager.toRatio();
5368
+ if (completedLoading) {
5369
+ if (!this.hasCompleted) {
5370
+ this.hasCompleted = true;
5371
+ if (!this.debugCheckbox.checked) {
5372
+ this.dispose();
5373
+ }
5374
+ }
5375
+ this.loadingStatusText.textContent = "Completed";
5376
+ this.progressBar.style.width = "100%";
5377
+ } else {
5378
+ this.loadingStatusText.textContent = `Loading... ${(loadingRatio * 100).toFixed(2)}%`;
5379
+ this.progressBar.style.width = `${loadingRatio * 100}%`;
5380
+ }
5381
+ this.progressDebugElement.textContent = LoadingProgressManager2.LoadingProgressSummaryToString(
5382
+ this.loadingProgressManager.toSummary()
5383
+ );
5384
+ };
5385
+ this.loadingProgressManager.addProgressCallback(this.loadingCallback);
5386
+ }
5387
+ dispose() {
5388
+ this.loadingProgressManager.removeProgressCallback(this.loadingCallback);
5389
+ this.element.remove();
5390
+ }
5391
+ };
5198
5392
  export {
5199
5393
  AnimationState,
5200
5394
  CameraManager,
@@ -5202,11 +5396,14 @@ export {
5202
5396
  CharacterModelLoader,
5203
5397
  CollisionsManager,
5204
5398
  Composer,
5399
+ GroundPlane,
5205
5400
  KeyInputManager,
5401
+ LoadingScreen,
5206
5402
  MMLCompositionScene,
5207
5403
  Sun,
5208
5404
  TimeManager,
5209
5405
  TweakPane,
5406
+ VirtualJoystick,
5210
5407
  clamp,
5211
5408
  decodeCharacterAndCamera,
5212
5409
  ease,