@mml-io/3d-web-client-core 0.0.0-experimental-a61f041-20240424 → 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
@@ -1181,14 +1169,13 @@ 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,21 +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
- alignment: this.props.alignment
1222
+ alignment: this.config.alignment
1235
1223
  });
1236
1224
  this.tooltipMaterial.map = texture;
1237
1225
  this.tooltipMaterial.map.magFilter = LinearFilter2;
@@ -1284,50 +1272,42 @@ var CharacterTooltip = class extends Mesh3 {
1284
1272
 
1285
1273
  // src/character/Character.ts
1286
1274
  var Character = class extends Group {
1287
- constructor(username, characterDescription, animationConfig, characterModelLoader, characterId, modelLoadedCallback, cameraManager, composer, isLocal) {
1275
+ constructor(config) {
1288
1276
  super();
1289
- this.username = username;
1290
- this.characterDescription = characterDescription;
1291
- this.animationConfig = animationConfig;
1292
- this.characterModelLoader = characterModelLoader;
1293
- this.characterId = characterId;
1294
- this.modelLoadedCallback = modelLoadedCallback;
1295
- this.cameraManager = cameraManager;
1296
- this.composer = composer;
1297
- this.isLocal = isLocal;
1277
+ this.config = config;
1298
1278
  this.model = null;
1299
1279
  this.color = new Color3();
1300
1280
  this.speakingIndicator = null;
1301
1281
  this.tooltip = new CharacterTooltip();
1302
- this.tooltip.setText(this.username, isLocal);
1282
+ this.tooltip.setText(this.config.username, this.config.isLocal);
1303
1283
  this.add(this.tooltip);
1304
1284
  this.load().then(() => {
1305
- this.modelLoadedCallback();
1285
+ this.config.modelLoadedCallback();
1306
1286
  });
1307
1287
  }
1308
1288
  updateCharacter(username, characterDescription) {
1309
- this.username = username;
1310
- this.characterDescription = characterDescription;
1289
+ this.config.username = username;
1290
+ this.config.characterDescription = characterDescription;
1311
1291
  this.load();
1312
- this.tooltip.setText(username, this.isLocal);
1292
+ this.tooltip.setText(username, this.config.isLocal);
1313
1293
  }
1314
- async load(callback) {
1294
+ async load() {
1315
1295
  const previousModel = this.model;
1316
- this.model = new CharacterModel(
1317
- this.characterDescription,
1318
- this.animationConfig,
1319
- this.characterModelLoader,
1320
- this.cameraManager,
1321
- this.characterId,
1322
- this.isLocal
1323
- );
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
+ });
1324
1304
  await this.model.init();
1325
1305
  if (previousModel && previousModel.mesh) {
1326
1306
  this.remove(previousModel.mesh);
1327
1307
  }
1328
1308
  this.add(this.model.mesh);
1329
1309
  if (this.speakingIndicator === null) {
1330
- this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1310
+ this.speakingIndicator = new CharacterSpeakingIndicator(this.config.composer.postPostScene);
1331
1311
  }
1332
1312
  }
1333
1313
  updateAnimation(targetAnimation) {
@@ -1339,14 +1319,14 @@ var Character = class extends Group {
1339
1319
  if (!this.model)
1340
1320
  return;
1341
1321
  if (this.tooltip) {
1342
- this.tooltip.update(this.cameraManager.camera);
1322
+ this.tooltip.update(this.config.cameraManager.camera);
1343
1323
  }
1344
1324
  if (this.speakingIndicator) {
1345
1325
  this.speakingIndicator.setTime(time);
1346
1326
  if (this.model.mesh && this.model.headBone) {
1347
1327
  this.speakingIndicator.setBillboarding(
1348
1328
  (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
1349
- this.cameraManager.camera
1329
+ this.config.cameraManager.camera
1350
1330
  );
1351
1331
  }
1352
1332
  }
@@ -1373,13 +1353,8 @@ var baseControl = 200;
1373
1353
  var collisionDetectionSteps = 15;
1374
1354
  var minimumSurfaceAngle = 0.9;
1375
1355
  var LocalController = class {
1376
- constructor(character, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
1377
- this.character = character;
1378
- this.id = id;
1379
- this.collisionsManager = collisionsManager;
1380
- this.keyInputManager = keyInputManager;
1381
- this.cameraManager = cameraManager;
1382
- this.timeManager = timeManager;
1356
+ constructor(config) {
1357
+ this.config = config;
1383
1358
  this.capsuleInfo = {
1384
1359
  radius: 0.4,
1385
1360
  segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
@@ -1417,53 +1392,54 @@ var LocalController = class {
1417
1392
  this.surfaceTempRay = new Ray();
1418
1393
  this.lastFrameSurfaceState = null;
1419
1394
  this.networkState = {
1420
- id: this.id,
1395
+ id: this.config.id,
1421
1396
  position: { x: 0, y: 0, z: 0 },
1422
1397
  rotation: { quaternionY: 0, quaternionW: 1 },
1423
1398
  state: 0 /* idle */
1424
1399
  };
1425
1400
  }
1426
1401
  updateControllerState() {
1427
- this.forward = this.keyInputManager.forward;
1428
- this.backward = this.keyInputManager.backward;
1429
- this.left = this.keyInputManager.left;
1430
- this.right = this.keyInputManager.right;
1431
- this.run = this.keyInputManager.run;
1432
- this.jump = this.keyInputManager.jump;
1433
- this.anyDirection = this.keyInputManager.anyDirection;
1434
- 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;
1435
1411
  }
1436
1412
  update() {
1437
1413
  this.updateControllerState();
1438
- this.rayCaster.set(this.character.position, this.vectorDown);
1439
- 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);
1440
1416
  if (firstRaycastHit !== null) {
1441
1417
  this.currentHeight = firstRaycastHit[0];
1442
1418
  this.currentSurfaceAngle.copy(firstRaycastHit[1]);
1443
1419
  }
1444
1420
  if (this.anyDirection || !this.characterOnGround) {
1445
1421
  const targetAnimation = this.getTargetAnimation();
1446
- this.character.updateAnimation(targetAnimation);
1422
+ this.config.character.updateAnimation(targetAnimation);
1447
1423
  } else {
1448
- this.character.updateAnimation(0 /* idle */);
1424
+ this.config.character.updateAnimation(0 /* idle */);
1449
1425
  }
1450
1426
  if (this.anyDirection) {
1451
1427
  this.updateRotation();
1452
1428
  }
1453
1429
  for (let i = 0; i < collisionDetectionSteps; i++) {
1454
1430
  this.updatePosition(
1455
- this.timeManager.deltaTime,
1456
- this.timeManager.deltaTime / collisionDetectionSteps,
1431
+ this.config.timeManager.deltaTime,
1432
+ this.config.timeManager.deltaTime / collisionDetectionSteps,
1457
1433
  i
1458
1434
  );
1459
1435
  }
1460
- if (this.character.position.y < 0) {
1436
+ if (this.config.character.position.y < 0) {
1461
1437
  this.resetPosition();
1462
1438
  }
1463
1439
  this.updateNetworkState();
1464
1440
  }
1465
1441
  getTargetAnimation() {
1466
- if (!this.character)
1442
+ if (!this.config.character)
1467
1443
  return 0 /* idle */;
1468
1444
  const jumpHeight = this.characterVelocity.y > 0 ? 0.2 : 1.8;
1469
1445
  if (this.currentHeight > jumpHeight && !this.characterOnGround) {
@@ -1496,22 +1472,22 @@ var LocalController = class {
1496
1472
  }
1497
1473
  }
1498
1474
  updateAzimuthalAngle() {
1499
- const camToModelDistance = this.cameraManager.camera.position.distanceTo(
1500
- this.character.position
1475
+ const camToModelDistance = this.config.cameraManager.camera.position.distanceTo(
1476
+ this.config.character.position
1501
1477
  );
1502
1478
  const isCameraFirstPerson = camToModelDistance < 2;
1503
1479
  if (isCameraFirstPerson) {
1504
- 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);
1505
1481
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1506
1482
  } else {
1507
1483
  this.azimuthalAngle = Math.atan2(
1508
- this.cameraManager.camera.position.x - this.character.position.x,
1509
- 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
1510
1486
  );
1511
1487
  }
1512
1488
  }
1513
1489
  computeAngularDifference(rotationQuaternion) {
1514
- return 2 * Math.acos(Math.abs(this.character.quaternion.dot(rotationQuaternion)));
1490
+ return 2 * Math.acos(Math.abs(this.config.character.quaternion.dot(rotationQuaternion)));
1515
1491
  }
1516
1492
  updateRotation() {
1517
1493
  this.updateRotationOffset();
@@ -1523,8 +1499,8 @@ var LocalController = class {
1523
1499
  const angularDifference = this.computeAngularDifference(rotationQuaternion);
1524
1500
  const desiredTime = 0.07;
1525
1501
  const angularSpeed = angularDifference / desiredTime;
1526
- const frameRotation = angularSpeed * this.timeManager.deltaTime;
1527
- this.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1502
+ const frameRotation = angularSpeed * this.config.timeManager.deltaTime;
1503
+ this.config.character.quaternion.rotateTowards(rotationQuaternion, frameRotation);
1528
1504
  }
1529
1505
  applyControls(deltaTime) {
1530
1506
  const resistance = this.characterOnGround ? groundResistance : airResistance;
@@ -1576,31 +1552,31 @@ var LocalController = class {
1576
1552
  }
1577
1553
  acceleration.add(controlAcceleration);
1578
1554
  this.characterVelocity.addScaledVector(acceleration, deltaTime);
1579
- this.character.position.addScaledVector(this.characterVelocity, deltaTime);
1555
+ this.config.character.position.addScaledVector(this.characterVelocity, deltaTime);
1580
1556
  }
1581
1557
  updatePosition(deltaTime, stepDeltaTime, iter) {
1582
1558
  this.applyControls(stepDeltaTime);
1583
1559
  if (iter === 0) {
1584
- const lastMovement = this.getMovementFromSurfaces(this.character.position, deltaTime);
1560
+ const lastMovement = this.getMovementFromSurfaces(this.config.character.position, deltaTime);
1585
1561
  if (lastMovement) {
1586
- this.character.position.add(lastMovement.position);
1587
- 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);
1588
1564
  const lastMovementEuler = this.tempEuler.setFromQuaternion(lastMovement.rotation);
1589
1565
  lastMovementEuler.x = 0;
1590
1566
  lastMovementEuler.z = 0;
1591
1567
  lastMovement.rotation.setFromEuler(lastMovementEuler);
1592
1568
  asQuaternion.multiply(lastMovement.rotation);
1593
- this.character.rotation.setFromQuaternion(asQuaternion);
1569
+ this.config.character.rotation.setFromQuaternion(asQuaternion);
1594
1570
  }
1595
1571
  }
1596
- this.character.updateMatrixWorld();
1572
+ this.config.character.updateMatrixWorld();
1597
1573
  const avatarSegment = this.tempSegment;
1598
1574
  avatarSegment.copy(this.capsuleInfo.segment);
1599
- avatarSegment.start.applyMatrix4(this.character.matrixWorld).applyMatrix4(this.tempMatrix);
1600
- 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);
1601
1577
  const positionBeforeCollisions = this.tempVector.copy(avatarSegment.start);
1602
- this.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1603
- this.character.position.copy(avatarSegment.start);
1578
+ this.config.collisionsManager.applyColliders(avatarSegment, this.capsuleInfo.radius);
1579
+ this.config.character.position.copy(avatarSegment.start);
1604
1580
  const deltaCollisionPosition = avatarSegment.start.sub(positionBeforeCollisions);
1605
1581
  this.characterOnGround = deltaCollisionPosition.y > 0;
1606
1582
  if (this.characterWasOnGround && !this.characterOnGround) {
@@ -1645,7 +1621,7 @@ var LocalController = class {
1645
1621
  }
1646
1622
  newPosition.setY(newPosition.y + 0.05);
1647
1623
  const ray = this.surfaceTempRay.set(newPosition, downVector);
1648
- const hit = this.collisionsManager.raycastFirst(ray);
1624
+ const hit = this.config.collisionsManager.raycastFirst(ray);
1649
1625
  if (hit && hit[0] < 0.8) {
1650
1626
  const currentCollisionMeshState = hit[2];
1651
1627
  this.lastFrameSurfaceState = [
@@ -1664,53 +1640,61 @@ var LocalController = class {
1664
1640
  return lastMovement;
1665
1641
  }
1666
1642
  updateNetworkState() {
1667
- const characterQuaternion = this.character.getWorldQuaternion(this.tempQuaternion);
1643
+ const characterQuaternion = this.config.character.getWorldQuaternion(this.tempQuaternion);
1668
1644
  this.networkState = {
1669
- id: this.id,
1645
+ id: this.config.id,
1670
1646
  position: {
1671
- x: this.character.position.x,
1672
- y: this.character.position.y,
1673
- 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
1674
1650
  },
1675
1651
  rotation: { quaternionY: characterQuaternion.y, quaternionW: characterQuaternion.w },
1676
- state: this.character.getCurrentAnimation()
1652
+ state: this.config.character.getCurrentAnimation()
1677
1653
  };
1678
1654
  }
1679
1655
  resetPosition() {
1680
1656
  this.characterVelocity.y = 0;
1681
- this.character.position.y = 3;
1657
+ this.config.character.position.y = 3;
1682
1658
  this.characterOnGround = false;
1683
1659
  }
1684
1660
  };
1685
1661
 
1686
1662
  // src/character/RemoteController.ts
1687
1663
  import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
1664
+ var tempQuaternion = new Quaternion3();
1688
1665
  var RemoteController = class {
1689
- constructor(character, id) {
1690
- this.character = character;
1691
- this.id = id;
1666
+ constructor(config) {
1667
+ this.config = config;
1692
1668
  this.currentAnimation = 0 /* idle */;
1693
1669
  this.networkState = {
1694
- id: this.id,
1695
- position: { x: 0, y: 0, z: 0 },
1696
- 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
+ },
1697
1680
  state: this.currentAnimation
1698
1681
  };
1699
1682
  }
1700
1683
  update(clientUpdate, time, deltaTime) {
1701
- if (!this.character)
1684
+ if (!this.config.character) {
1702
1685
  return;
1686
+ }
1703
1687
  this.updateFromNetwork(clientUpdate);
1704
- this.character.update(time, deltaTime);
1688
+ this.config.character.update(time, deltaTime);
1705
1689
  }
1706
1690
  updateFromNetwork(clientUpdate) {
1707
1691
  const { position, rotation, state } = clientUpdate;
1708
- 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);
1709
1693
  const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1710
- this.character.quaternion.slerp(rotationQuaternion, 0.6);
1694
+ this.config.character.quaternion.slerp(rotationQuaternion, 0.6);
1711
1695
  if (state !== this.currentAnimation) {
1712
1696
  this.currentAnimation = state;
1713
- this.character.updateAnimation(state);
1697
+ this.config.character.updateAnimation(state);
1714
1698
  }
1715
1699
  }
1716
1700
  };
@@ -1741,17 +1725,8 @@ function decodeCharacterAndCamera(hash) {
1741
1725
 
1742
1726
  // src/character/CharacterManager.ts
1743
1727
  var CharacterManager = class {
1744
- constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, keyInputManager, clientStates, sendUpdate, animationConfig, characterResolve) {
1745
- this.composer = composer;
1746
- this.characterModelLoader = characterModelLoader;
1747
- this.collisionsManager = collisionsManager;
1748
- this.cameraManager = cameraManager;
1749
- this.timeManager = timeManager;
1750
- this.keyInputManager = keyInputManager;
1751
- this.clientStates = clientStates;
1752
- this.sendUpdate = sendUpdate;
1753
- this.animationConfig = animationConfig;
1754
- this.characterResolve = characterResolve;
1728
+ constructor(config) {
1729
+ this.config = config;
1755
1730
  this.updateLocationHash = true;
1756
1731
  this.headTargetOffset = new Vector38(0, 1.3, 0);
1757
1732
  this.localClientId = 0;
@@ -1763,20 +1738,20 @@ var CharacterManager = class {
1763
1738
  this.group = new Group2();
1764
1739
  }
1765
1740
  spawnLocalCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1766
- const character = new Character(
1741
+ const character = new Character({
1767
1742
  username,
1768
1743
  characterDescription,
1769
- this.animationConfig,
1770
- this.characterModelLoader,
1771
- id,
1772
- () => {
1744
+ animationConfig: this.config.animationConfig,
1745
+ characterModelLoader: this.config.characterModelLoader,
1746
+ characterId: id,
1747
+ modelLoadedCallback: () => {
1773
1748
  },
1774
- this.cameraManager,
1775
- this.composer,
1776
- true
1777
- );
1749
+ cameraManager: this.config.cameraManager,
1750
+ composer: this.config.composer,
1751
+ isLocal: true
1752
+ });
1778
1753
  const quaternion = new Quaternion5().setFromEuler(character.rotation);
1779
- this.sendUpdate({
1754
+ this.config.sendUpdate({
1780
1755
  id,
1781
1756
  position: {
1782
1757
  x: spawnPosition.x,
@@ -1788,36 +1763,37 @@ var CharacterManager = class {
1788
1763
  });
1789
1764
  this.localClientId = id;
1790
1765
  this.localCharacter = character;
1791
- this.localController = new LocalController(
1792
- this.localCharacter,
1793
- this.localClientId,
1794
- this.collisionsManager,
1795
- this.keyInputManager,
1796
- this.cameraManager,
1797
- this.timeManager
1798
- );
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
+ });
1799
1775
  this.localCharacter.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1800
1776
  this.localCharacter.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1801
1777
  this.group.add(character);
1802
1778
  this.localCharacterSpawned = true;
1803
1779
  }
1804
1780
  spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
1805
- const character = new Character(
1781
+ const character = new Character({
1806
1782
  username,
1807
1783
  characterDescription,
1808
- this.animationConfig,
1809
- this.characterModelLoader,
1810
- id,
1811
- () => {
1784
+ animationConfig: this.config.animationConfig,
1785
+ characterModelLoader: this.config.characterModelLoader,
1786
+ characterId: id,
1787
+ modelLoadedCallback: () => {
1812
1788
  },
1813
- this.cameraManager,
1814
- this.composer,
1815
- false
1816
- );
1789
+ cameraManager: this.config.cameraManager,
1790
+ composer: this.config.composer,
1791
+ isLocal: false
1792
+ });
1817
1793
  this.remoteCharacters.set(id, character);
1818
- const remoteController = new RemoteController(character, id);
1819
- remoteController.character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1820
- 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 });
1821
1797
  this.remoteCharacterControllers.set(id, remoteController);
1822
1798
  this.group.add(character);
1823
1799
  }
@@ -1848,7 +1824,7 @@ var CharacterManager = class {
1848
1824
  this.speakingCharacters.set(id, value);
1849
1825
  }
1850
1826
  respawnIfPresent(id) {
1851
- const characterInfo = this.characterResolve(id);
1827
+ const characterInfo = this.config.characterResolve(id);
1852
1828
  if (this.localCharacter && this.localClientId == id) {
1853
1829
  this.localCharacter.updateCharacter(
1854
1830
  characterInfo.username,
@@ -1863,27 +1839,27 @@ var CharacterManager = class {
1863
1839
  update() {
1864
1840
  var _a, _b, _c;
1865
1841
  if (this.localCharacter) {
1866
- this.localCharacter.update(this.timeManager.time, this.timeManager.deltaTime);
1842
+ this.localCharacter.update(this.config.timeManager.time, this.config.timeManager.deltaTime);
1867
1843
  if (this.speakingCharacters.has(this.localClientId)) {
1868
1844
  (_a = this.localCharacter.speakingIndicator) == null ? void 0 : _a.setSpeaking(
1869
1845
  this.speakingCharacters.get(this.localClientId)
1870
1846
  );
1871
1847
  }
1872
1848
  this.localController.update();
1873
- if (this.timeManager.frame % 2 === 0) {
1874
- this.sendUpdate(this.localController.networkState);
1849
+ if (this.config.timeManager.frame % 2 === 0) {
1850
+ this.config.sendUpdate(this.localController.networkState);
1875
1851
  }
1876
1852
  const targetOffset = new Vector38();
1877
1853
  targetOffset.add(this.headTargetOffset).applyQuaternion(this.localCharacter.quaternion).add(this.localCharacter.position);
1878
- this.cameraManager.setTarget(targetOffset);
1879
- for (const [id, update] of this.clientStates) {
1854
+ this.config.cameraManager.setTarget(targetOffset);
1855
+ for (const [id, update] of this.config.remoteUserStates) {
1880
1856
  if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
1881
1857
  const character = this.remoteCharacters.get(id);
1882
1858
  (_b = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _b.setSpeaking(this.speakingCharacters.get(id));
1883
1859
  }
1884
1860
  const { position } = update;
1885
1861
  if (!this.remoteCharacters.has(id) && this.localCharacterSpawned === true) {
1886
- const characterInfo = this.characterResolve(id);
1862
+ const characterInfo = this.config.characterResolve(id);
1887
1863
  this.spawnRemoteCharacter(
1888
1864
  id,
1889
1865
  characterInfo.username,
@@ -1893,21 +1869,25 @@ var CharacterManager = class {
1893
1869
  }
1894
1870
  const characterController = this.remoteCharacterControllers.get(id);
1895
1871
  if (characterController) {
1896
- 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
+ );
1897
1877
  }
1898
1878
  }
1899
1879
  for (const [id, character] of this.remoteCharacters) {
1900
- if (!this.clientStates.has(id)) {
1880
+ if (!this.config.remoteUserStates.has(id)) {
1901
1881
  (_c = character.speakingIndicator) == null ? void 0 : _c.dispose();
1902
1882
  this.group.remove(character);
1903
1883
  this.remoteCharacters.delete(id);
1904
1884
  this.remoteCharacterControllers.delete(id);
1905
1885
  }
1906
1886
  }
1907
- if (this.updateLocationHash && this.timeManager.frame % 60 === 0) {
1887
+ if (this.updateLocationHash && this.config.timeManager.frame % 60 === 0) {
1908
1888
  window.location.hash = encodeCharacterAndCamera(
1909
1889
  this.localCharacter,
1910
- this.cameraManager.camera
1890
+ this.config.cameraManager.camera
1911
1891
  );
1912
1892
  }
1913
1893
  }
@@ -1915,32 +1895,7 @@ var CharacterManager = class {
1915
1895
  };
1916
1896
 
1917
1897
  // src/character/CharacterModelLoader.ts
1918
- import { LoadingManager } from "three";
1919
- import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
1920
- var CachedGLTFLoader = class extends ThreeGLTFLoader {
1921
- constructor(manager, debug = false) {
1922
- super(manager);
1923
- this.debug = debug;
1924
- this.blobCache = /* @__PURE__ */ new Map();
1925
- }
1926
- setBlobUrl(originalUrl, blobUrl) {
1927
- this.blobCache.set(originalUrl, blobUrl);
1928
- }
1929
- getBlobUrl(originalUrl) {
1930
- return this.blobCache.get(originalUrl);
1931
- }
1932
- load(url, onLoad, onProgress, onError) {
1933
- const blobUrl = this.getBlobUrl(url);
1934
- if (blobUrl) {
1935
- if (this.debug === true) {
1936
- console.log(`Loading cached ${url.split("/").pop()}`);
1937
- }
1938
- super.load(blobUrl, onLoad, onProgress, onError);
1939
- } else {
1940
- super.load(url, onLoad, onProgress, onError);
1941
- }
1942
- }
1943
- };
1898
+ import { ModelLoader as ModelLoader2 } from "@mml-io/model-loader";
1944
1899
  var LRUCache = class {
1945
1900
  constructor(maxSize = 100) {
1946
1901
  this.maxSize = maxSize;
@@ -1965,16 +1920,13 @@ var LRUCache = class {
1965
1920
  var CharacterModelLoader = class {
1966
1921
  constructor(maxCacheSize = 100, debug = false) {
1967
1922
  this.debug = debug;
1923
+ this.modelLoader = new ModelLoader2();
1968
1924
  this.ongoingLoads = /* @__PURE__ */ new Map();
1969
- this.loadingManager = new LoadingManager();
1970
- this.gltfLoader = new CachedGLTFLoader(this.loadingManager, this.debug);
1971
1925
  this.modelCache = new LRUCache(maxCacheSize);
1972
1926
  }
1973
1927
  async load(fileUrl, fileType) {
1974
1928
  const cachedModel = this.modelCache.get(fileUrl);
1975
1929
  if (cachedModel) {
1976
- const blobURL = URL.createObjectURL(cachedModel.blob);
1977
- this.gltfLoader.setBlobUrl(fileUrl, blobURL);
1978
1930
  return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
1979
1931
  } else {
1980
1932
  if (this.debug === true) {
@@ -2002,26 +1954,21 @@ var CharacterModelLoader = class {
2002
1954
  }
2003
1955
  async loadFromUrl(url, fileType, extension) {
2004
1956
  if (["gltf", "glb"].includes(extension)) {
2005
- return new Promise((resolve, reject) => {
2006
- this.gltfLoader.load(
1957
+ return new Promise(async (resolve, reject) => {
1958
+ const modelLoadResult = await this.modelLoader.load(
2007
1959
  url,
2008
- (object) => {
2009
- if (fileType === "model") {
2010
- resolve(object.scene);
2011
- } else if (fileType === "animation") {
2012
- resolve(object.animations[0]);
2013
- } else {
2014
- const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
2015
- console.error(error);
2016
- reject(error);
2017
- }
2018
- },
2019
- void 0,
2020
- (error) => {
2021
- console.error(`Error loading GL(B|TF) from ${url}: ${error}`);
2022
- reject(error);
1960
+ (loaded, total) => {
2023
1961
  }
2024
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
+ }
2025
1972
  });
2026
1973
  } else {
2027
1974
  console.error(`Error: can't recognize ${url} extension: ${extension}`);
@@ -2035,17 +1982,9 @@ var KeyInputManager = class {
2035
1982
  this.shouldCaptureKeyPress = shouldCaptureKeyPress;
2036
1983
  this.keys = /* @__PURE__ */ new Map();
2037
1984
  this.eventHandlerCollection = new EventHandlerCollection();
2038
- this.directionJoystick = null;
2039
1985
  this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
2040
1986
  this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
2041
1987
  this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this));
2042
- this.directionJoystick = new VirtualJoystick({
2043
- radius: 70,
2044
- inner_radius: 20,
2045
- x: 70,
2046
- y: 0,
2047
- mouse_support: false
2048
- });
2049
1988
  }
2050
1989
  handleUnfocus(_event) {
2051
1990
  this.keys.clear();
@@ -2069,19 +2008,19 @@ var KeyInputManager = class {
2069
2008
  return this.keys.get(key) || false;
2070
2009
  }
2071
2010
  isMovementKeyPressed() {
2072
- 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));
2073
2012
  }
2074
2013
  get forward() {
2075
- return this.isKeyPressed("w" /* W */) || this.directionJoystick.up;
2014
+ return this.isKeyPressed("w" /* W */);
2076
2015
  }
2077
2016
  get backward() {
2078
- return this.isKeyPressed("s" /* S */) || this.directionJoystick.down;
2017
+ return this.isKeyPressed("s" /* S */);
2079
2018
  }
2080
2019
  get left() {
2081
- return this.isKeyPressed("a" /* A */) || this.directionJoystick.left;
2020
+ return this.isKeyPressed("a" /* A */);
2082
2021
  }
2083
2022
  get right() {
2084
- return this.isKeyPressed("d" /* D */) || this.directionJoystick.right;
2023
+ return this.isKeyPressed("d" /* D */);
2085
2024
  }
2086
2025
  get run() {
2087
2026
  return this.isKeyPressed("shift" /* SHIFT */);
@@ -2109,40 +2048,35 @@ import {
2109
2048
  } from "mml-web";
2110
2049
  import { Group as Group3 } from "three";
2111
2050
  var MMLCompositionScene = class {
2112
- constructor(targetElement, renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation) {
2113
- this.renderer = renderer;
2114
- this.scene = scene;
2115
- this.camera = camera;
2116
- this.audioListener = audioListener;
2117
- this.collisionsManager = collisionsManager;
2118
- this.getUserPositionAndRotation = getUserPositionAndRotation;
2051
+ constructor(config) {
2052
+ this.config = config;
2119
2053
  this.chatProbes = /* @__PURE__ */ new Set();
2120
2054
  this.group = new Group3();
2121
- this.promptManager = PromptManager.init(targetElement);
2055
+ this.promptManager = PromptManager.init(this.config.targetElement);
2122
2056
  const { interactionListener, interactionManager } = InteractionManager.init(
2123
- targetElement,
2124
- this.camera,
2125
- this.scene
2057
+ this.config.targetElement,
2058
+ this.config.camera,
2059
+ this.config.scene
2126
2060
  );
2127
2061
  this.interactionManager = interactionManager;
2128
2062
  this.interactionListener = interactionListener;
2129
2063
  this.loadingProgressManager = new LoadingProgressManager();
2130
2064
  this.mmlScene = {
2131
- getAudioListener: () => this.audioListener,
2132
- getRenderer: () => this.renderer,
2133
- getThreeScene: () => this.scene,
2065
+ getAudioListener: () => this.config.audioListener,
2066
+ getRenderer: () => this.config.renderer,
2067
+ getThreeScene: () => this.config.scene,
2134
2068
  getRootContainer: () => this.group,
2135
- getCamera: () => this.camera,
2069
+ getCamera: () => this.config.camera,
2136
2070
  addCollider: (object, mElement) => {
2137
- this.collisionsManager.addMeshesGroup(object, mElement);
2071
+ this.config.collisionsManager.addMeshesGroup(object, mElement);
2138
2072
  },
2139
2073
  updateCollider: (object) => {
2140
- this.collisionsManager.updateMeshesGroup(object);
2074
+ this.config.collisionsManager.updateMeshesGroup(object);
2141
2075
  },
2142
2076
  removeCollider: (object) => {
2143
- this.collisionsManager.removeMeshesGroup(object);
2077
+ this.config.collisionsManager.removeMeshesGroup(object);
2144
2078
  },
2145
- getUserPositionAndRotation: this.getUserPositionAndRotation,
2079
+ getUserPositionAndRotation: this.config.getUserPositionAndRotation,
2146
2080
  addInteraction: (interaction) => {
2147
2081
  this.interactionListener.addInteraction(interaction);
2148
2082
  },
@@ -2167,7 +2101,7 @@ var MMLCompositionScene = class {
2167
2101
  return this.loadingProgressManager;
2168
2102
  }
2169
2103
  };
2170
- this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
2104
+ this.clickTrigger = MMLClickTrigger.init(this.config.targetElement, this.mmlScene);
2171
2105
  }
2172
2106
  onChatMessage(message) {
2173
2107
  for (const chatProbe of this.chatProbes) {
@@ -2238,7 +2172,7 @@ var sunValues = {
2238
2172
  sunAzimuthalAngle: 214.5,
2239
2173
  sunPolarAngle: -41.5
2240
2174
  },
2241
- sunIntensity: 1,
2175
+ sunIntensity: 2,
2242
2176
  sunColor: { r: 1, g: 1, b: 1 }
2243
2177
  };
2244
2178
  var sunOptions = {
@@ -2250,7 +2184,7 @@ var sunOptions = {
2250
2184
  };
2251
2185
  var envValues = {
2252
2186
  ambientLight: {
2253
- ambientLightIntensity: 0.05,
2187
+ ambientLightIntensity: 0.1,
2254
2188
  ambientLightColor: { r: 1, g: 1, b: 1 }
2255
2189
  },
2256
2190
  fog: {
@@ -2766,6 +2700,10 @@ var SSAOFolder = class {
2766
2700
  case "enabled":
2767
2701
  if (e.value === true) {
2768
2702
  composer.addPass(n8aopass, this.postProcessingSSAOIndex + 2);
2703
+ composer.passes[this.postProcessingSSAOIndex + 2].setSize(
2704
+ window.innerWidth,
2705
+ window.innerHeight
2706
+ );
2769
2707
  } else {
2770
2708
  composer.removePass(n8aopass);
2771
2709
  }
@@ -2966,16 +2904,26 @@ var tweakPaneStyle = `
2966
2904
 
2967
2905
  // src/tweakpane/TweakPane.ts
2968
2906
  var TweakPane = class {
2969
- constructor(renderer, scene, composer) {
2907
+ constructor(holderElement, renderer, scene, composer) {
2908
+ this.holderElement = holderElement;
2970
2909
  this.renderer = renderer;
2971
2910
  this.scene = scene;
2972
2911
  this.composer = composer;
2973
2912
  this.saveVisibilityInLocalStorage = true;
2974
2913
  this.guiVisible = false;
2975
- const appWrapper = document.getElementById("app");
2976
2914
  const tweakPaneWrapper = document.createElement("div");
2977
- tweakPaneWrapper.id = "tweakpane-panel";
2978
- 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);
2979
2927
  this.gui = new Pane({ container: tweakPaneWrapper });
2980
2928
  this.gui.registerPlugin(EssentialsPlugin);
2981
2929
  if (this.saveVisibilityInLocalStorage) {
@@ -3101,6 +3049,7 @@ var TweakPane = class {
3101
3049
  };
3102
3050
 
3103
3051
  // src/rendering/composer.ts
3052
+ import { HDRJPGLoader } from "@monogrid/gainmap-js";
3104
3053
  import {
3105
3054
  EffectComposer as EffectComposer2,
3106
3055
  RenderPass,
@@ -3124,12 +3073,13 @@ import {
3124
3073
  Fog as Fog2,
3125
3074
  HalfFloatType as HalfFloatType2,
3126
3075
  LinearSRGBColorSpace,
3127
- LoadingManager as LoadingManager2,
3076
+ LoadingManager,
3128
3077
  PMREMGenerator,
3129
3078
  SRGBColorSpace,
3130
3079
  Scene as Scene4,
3131
3080
  Vector2 as Vector27,
3132
- WebGLRenderer as WebGLRenderer4
3081
+ WebGLRenderer as WebGLRenderer4,
3082
+ EquirectangularReflectionMapping
3133
3083
  } from "three";
3134
3084
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
3135
3085
 
@@ -3159,7 +3109,7 @@ var Sun = class extends Group4 {
3159
3109
  if (this.debug === true) {
3160
3110
  this.camHelper = new CameraHelper(this.shadowCamera);
3161
3111
  }
3162
- this.directionalLight = new DirectionalLight(16777215, 0.5);
3112
+ this.directionalLight = new DirectionalLight(16777215);
3163
3113
  this.directionalLight.intensity = sunValues.sunIntensity;
3164
3114
  this.directionalLight.shadow.normalBias = 0.01;
3165
3115
  this.directionalLight.shadow.radius = 0.02;
@@ -4864,11 +4814,30 @@ var Composer = class {
4864
4814
  this.effectComposer.render();
4865
4815
  this.renderer.render(this.postPostScene, this.camera);
4866
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
+ }
4867
4836
  useHDRI(url, fromFile = false) {
4868
4837
  if (this.isEnvHDRI && fromFile === false || !this.renderer)
4869
4838
  return;
4870
4839
  const pmremGenerator = new PMREMGenerator(this.renderer);
4871
- new RGBELoader(new LoadingManager2()).load(
4840
+ new RGBELoader(new LoadingManager()).load(
4872
4841
  url,
4873
4842
  (texture) => {
4874
4843
  const envMap = pmremGenerator.fromEquirectangular(texture).texture;
@@ -4894,7 +4863,7 @@ var Composer = class {
4894
4863
  return;
4895
4864
  const fileInput = document.createElement("input");
4896
4865
  fileInput.type = "file";
4897
- fileInput.accept = ".hdr";
4866
+ fileInput.accept = ".hdr,.jpg";
4898
4867
  fileInput.addEventListener("change", () => {
4899
4868
  var _a;
4900
4869
  const file = (_a = fileInput.files) == null ? void 0 : _a[0];
@@ -4902,9 +4871,16 @@ var Composer = class {
4902
4871
  console.log("no file");
4903
4872
  return;
4904
4873
  }
4874
+ const extension = file.name.split(".").pop();
4905
4875
  const fileURL = URL.createObjectURL(file);
4906
4876
  if (fileURL) {
4907
- 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
+ }
4908
4884
  URL.revokeObjectURL(fileURL);
4909
4885
  document.body.removeChild(fileInput);
4910
4886
  }
@@ -5219,6 +5195,200 @@ var CollisionsManager = class {
5219
5195
  this.collisionTrigger.setCurrentCollisions(reportedCollidingElements);
5220
5196
  }
5221
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
+ };
5222
5392
  export {
5223
5393
  AnimationState,
5224
5394
  CameraManager,
@@ -5226,11 +5396,14 @@ export {
5226
5396
  CharacterModelLoader,
5227
5397
  CollisionsManager,
5228
5398
  Composer,
5399
+ GroundPlane,
5229
5400
  KeyInputManager,
5401
+ LoadingScreen,
5230
5402
  MMLCompositionScene,
5231
5403
  Sun,
5232
5404
  TimeManager,
5233
5405
  TweakPane,
5406
+ VirtualJoystick,
5234
5407
  clamp,
5235
5408
  decodeCharacterAndCamera,
5236
5409
  ease,