@mml-io/3d-web-client-core 0.19.0 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/camera/CameraManager.ts
2
2
  import { PerspectiveCamera, Raycaster, Vector3 as Vector32 } from "three";
3
+ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3
4
 
4
5
  // src/helpers/math-helpers.ts
5
6
  import { Quaternion, Vector3, Vector4 } from "three";
@@ -218,6 +219,7 @@ var CameraManager = class {
218
219
  constructor(targetElement, collisionsManager, initialPhi = Math.PI / 2, initialTheta = -Math.PI / 2) {
219
220
  this.targetElement = targetElement;
220
221
  this.collisionsManager = collisionsManager;
222
+ this.isMainCameraActive = true;
221
223
  this.initialDistance = camValues.initialDistance;
222
224
  this.minDistance = camValues.minDistance;
223
225
  this.maxDistance = camValues.maxDistance;
@@ -248,19 +250,36 @@ var CameraManager = class {
248
250
  this.targetPhi = this.phi;
249
251
  this.theta = initialTheta;
250
252
  this.targetTheta = this.theta;
251
- this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
253
+ const aspect = window.innerWidth / window.innerHeight;
254
+ this.camera = new PerspectiveCamera(this.fov, aspect, 0.1, 400);
252
255
  this.camera.position.set(0, 1.4, -this.initialDistance);
256
+ this.camera.name = "MainCamera";
257
+ this.flyCamera = new PerspectiveCamera(this.initialFOV, aspect, 0.1, 400);
258
+ this.flyCamera.name = "FlyCamera";
259
+ this.flyCamera.position.copy(this.camera.position);
260
+ this.flyCamera.name = "FlyCamera";
261
+ this.orbitControls = new OrbitControls(this.flyCamera, this.targetElement);
262
+ this.orbitControls.enableDamping = true;
263
+ this.orbitControls.dampingFactor = 0.05;
264
+ this.orbitControls.enablePan = true;
265
+ this.orbitControls.enabled = false;
253
266
  this.rayCaster = new Raycaster();
267
+ this.createEventHandlers();
268
+ }
269
+ createEventHandlers() {
254
270
  this.eventHandlerCollection = EventHandlerCollection.create([
255
- [targetElement, "pointerdown", this.onPointerDown.bind(this)],
256
- [targetElement, "gesturestart", this.preventDefaultAndStopPropagation.bind(this)],
271
+ [this.targetElement, "pointerdown", this.onPointerDown.bind(this)],
272
+ [this.targetElement, "gesturestart", this.preventDefaultAndStopPropagation.bind(this)],
273
+ [this.targetElement, "wheel", this.onMouseWheel.bind(this)],
274
+ [this.targetElement, "contextmenu", this.onContextMenu.bind(this)],
257
275
  [document, "pointerup", this.onPointerUp.bind(this)],
258
276
  [document, "pointercancel", this.onPointerUp.bind(this)],
259
- [document, "pointermove", this.onPointerMove.bind(this)],
260
- [targetElement, "wheel", this.onMouseWheel.bind(this)],
261
- [targetElement, "contextmenu", this.onContextMenu.bind(this)]
277
+ [document, "pointermove", this.onPointerMove.bind(this)]
262
278
  ]);
263
279
  }
280
+ disposeEventHandlers() {
281
+ this.eventHandlerCollection.clear();
282
+ }
264
283
  preventDefaultAndStopPropagation(evt) {
265
284
  evt.preventDefault();
266
285
  evt.stopPropagation();
@@ -391,7 +410,8 @@ var CameraManager = class {
391
410
  }
392
411
  }
393
412
  dispose() {
394
- this.eventHandlerCollection.clear();
413
+ this.disposeEventHandlers();
414
+ this.orbitControls.dispose();
395
415
  document.body.style.cursor = "";
396
416
  }
397
417
  easeOutExpo(x) {
@@ -399,6 +419,7 @@ var CameraManager = class {
399
419
  }
400
420
  updateAspect(aspect) {
401
421
  this.camera.aspect = aspect;
422
+ this.flyCamera.aspect = aspect;
402
423
  }
403
424
  recomputeFoV(immediately = false) {
404
425
  this.targetFOV = remap(
@@ -412,7 +433,31 @@ var CameraManager = class {
412
433
  this.fov = this.targetFOV;
413
434
  }
414
435
  }
436
+ toggleFlyCamera() {
437
+ this.isMainCameraActive = !this.isMainCameraActive;
438
+ this.orbitControls.enabled = !this.isMainCameraActive;
439
+ if (!this.isMainCameraActive) {
440
+ this.updateAspect(window.innerWidth / window.innerHeight);
441
+ this.flyCamera.position.copy(this.camera.position);
442
+ this.flyCamera.rotation.copy(this.camera.rotation);
443
+ const target = new Vector32();
444
+ this.camera.getWorldDirection(target);
445
+ target.multiplyScalar(this.targetDistance).add(this.camera.position);
446
+ this.orbitControls.target.copy(target);
447
+ this.orbitControls.update();
448
+ this.disposeEventHandlers();
449
+ } else {
450
+ this.createEventHandlers();
451
+ }
452
+ }
453
+ get activeCamera() {
454
+ return this.isMainCameraActive ? this.camera : this.flyCamera;
455
+ }
415
456
  update() {
457
+ if (!this.isMainCameraActive) {
458
+ this.orbitControls.update();
459
+ return;
460
+ }
416
461
  if (this.isLerping && this.lerpFactor < 1) {
417
462
  this.lerpFactor += 0.01 / this.lerpDuration;
418
463
  this.lerpFactor = Math.min(1, this.lerpFactor);
@@ -442,7 +487,7 @@ var CameraManager = class {
442
487
  };
443
488
 
444
489
  // src/character/Character.ts
445
- import { Color as Color3, Group, Vector3 as Vector34 } from "three";
490
+ import { Color as Color3, Group, Vector3 as Vector35 } from "three";
446
491
 
447
492
  // src/character/CharacterModel.ts
448
493
  import {
@@ -453,7 +498,9 @@ import { ModelLoader } from "@mml-io/model-loader";
453
498
  import {
454
499
  AnimationClip,
455
500
  AnimationMixer,
456
- LoopRepeat
501
+ Box3,
502
+ LoopRepeat,
503
+ Vector3 as Vector33
457
504
  } from "three";
458
505
 
459
506
  // src/character/CharacterMaterial.ts
@@ -741,6 +788,7 @@ var _CharacterModel = class _CharacterModel {
741
788
  this.config = config;
742
789
  this.mesh = null;
743
790
  this.headBone = null;
791
+ this.characterHeight = null;
744
792
  this.materials = /* @__PURE__ */ new Map();
745
793
  this.animations = {};
746
794
  this.animationMixer = null;
@@ -749,41 +797,49 @@ var _CharacterModel = class _CharacterModel {
749
797
  }
750
798
  async init() {
751
799
  await this.loadMainMesh();
752
- await this.setAnimationFromFile(
753
- this.config.animationConfig.idleAnimationFileUrl,
754
- 0 /* idle */,
755
- true
756
- );
757
- await this.setAnimationFromFile(
758
- this.config.animationConfig.jogAnimationFileUrl,
759
- 1 /* walking */,
760
- true
761
- );
762
- await this.setAnimationFromFile(
763
- this.config.animationConfig.sprintAnimationFileUrl,
764
- 2 /* running */,
765
- true
766
- );
767
- await this.setAnimationFromFile(
768
- this.config.animationConfig.airAnimationFileUrl,
769
- 4 /* air */,
770
- true
771
- );
772
- await this.setAnimationFromFile(
773
- this.config.animationConfig.doubleJumpAnimationFileUrl,
774
- 6 /* doubleJump */,
775
- false,
776
- 1.45
777
- );
778
- this.applyCustomMaterials();
800
+ if (this.mesh) {
801
+ await this.setAnimationFromFile(
802
+ this.config.animationConfig.idleAnimationFileUrl,
803
+ 0 /* idle */,
804
+ true
805
+ );
806
+ await this.setAnimationFromFile(
807
+ this.config.animationConfig.jogAnimationFileUrl,
808
+ 1 /* walking */,
809
+ true
810
+ );
811
+ await this.setAnimationFromFile(
812
+ this.config.animationConfig.sprintAnimationFileUrl,
813
+ 2 /* running */,
814
+ true
815
+ );
816
+ await this.setAnimationFromFile(
817
+ this.config.animationConfig.airAnimationFileUrl,
818
+ 4 /* air */,
819
+ true
820
+ );
821
+ await this.setAnimationFromFile(
822
+ this.config.animationConfig.doubleJumpAnimationFileUrl,
823
+ 6 /* doubleJump */,
824
+ false,
825
+ 1.45
826
+ );
827
+ this.applyCustomMaterials();
828
+ }
779
829
  }
780
830
  applyCustomMaterials() {
781
831
  if (!this.mesh)
782
832
  return;
833
+ const boundingBox = new Box3();
834
+ this.mesh.updateWorldMatrix(true, true);
835
+ boundingBox.expandByObject(this.mesh);
836
+ this.characterHeight = boundingBox.max.y - boundingBox.min.y;
783
837
  this.mesh.traverse((child) => {
784
838
  if (child.isBone) {
785
839
  if (child.name === "head") {
840
+ const worldPosition = new Vector33();
786
841
  this.headBone = child;
842
+ this.headBone.getWorldPosition(worldPosition);
787
843
  }
788
844
  }
789
845
  if (child.isMesh || child.isSkinnedMesh) {
@@ -886,23 +942,31 @@ var _CharacterModel = class _CharacterModel {
886
942
  return null;
887
943
  }
888
944
  async loadMainMesh() {
889
- const mainMesh = await this.loadCharacterFromDescription();
890
- if (typeof mainMesh !== "undefined") {
945
+ let mainMesh = null;
946
+ try {
947
+ mainMesh = await this.loadCharacterFromDescription();
948
+ } catch (error) {
949
+ console.error("Failed to load character from description", error);
950
+ }
951
+ if (mainMesh) {
891
952
  this.setMainMesh(mainMesh);
892
- } else {
893
- throw new Error("ERROR: No Character Model was loaded");
894
953
  }
895
954
  }
896
- cleanAnimationClips(skeletalMesh, animationClip) {
955
+ cleanAnimationClips(skeletalMesh, animationClip, keepRootBonePositionAnimation) {
897
956
  const availableBones = /* @__PURE__ */ new Set();
898
- skeletalMesh.traverse((child) => {
899
- const asBone = child;
900
- if (asBone.isBone) {
901
- availableBones.add(child.name);
902
- }
903
- });
957
+ if (skeletalMesh) {
958
+ skeletalMesh.traverse((child) => {
959
+ const asBone = child;
960
+ if (asBone.isBone) {
961
+ availableBones.add(child.name);
962
+ }
963
+ });
964
+ }
904
965
  animationClip.tracks = animationClip.tracks.filter((track) => {
905
966
  const [trackName, trackProperty] = track.name.split(".");
967
+ if (keepRootBonePositionAnimation && trackName === "root" && trackProperty === "position") {
968
+ return true;
969
+ }
906
970
  const shouldAnimate = availableBones.has(trackName) && trackProperty !== "position" && trackProperty !== "scale";
907
971
  return shouldAnimate;
908
972
  });
@@ -911,7 +975,7 @@ var _CharacterModel = class _CharacterModel {
911
975
  async setAnimationFromFile(animationFileUrl, animationType, loop = true, playbackSpeed = 1) {
912
976
  return new Promise(async (resolve, reject) => {
913
977
  const animation = await this.config.characterModelLoader.load(animationFileUrl, "animation");
914
- const cleanAnimation = this.cleanAnimationClips(this.mesh, animation);
978
+ const cleanAnimation = this.cleanAnimationClips(this.mesh, animation, true);
915
979
  if (typeof animation !== "undefined" && cleanAnimation instanceof AnimationClip) {
916
980
  this.animations[animationType] = this.animationMixer.clipAction(cleanAnimation);
917
981
  this.animations[animationType].stop();
@@ -1060,17 +1124,10 @@ var CharacterSpeakingIndicator = class {
1060
1124
  };
1061
1125
 
1062
1126
  // src/character/CharacterTooltip.ts
1063
- import {
1064
- Color as Color2,
1065
- FrontSide,
1066
- LinearFilter as LinearFilter2,
1067
- Mesh as Mesh3,
1068
- MeshBasicMaterial as MeshBasicMaterial2,
1069
- PlaneGeometry
1070
- } from "three";
1127
+ import { Color as Color2, FrontSide, LinearFilter as LinearFilter2, Sprite, SpriteMaterial } from "three";
1071
1128
 
1072
1129
  // src/character/CanvasText.ts
1073
- import { Texture, LinearFilter, RGBAFormat, MeshBasicMaterial } from "three";
1130
+ import { Texture, LinearFilter, RGBAFormat } from "three";
1074
1131
  function getTextAlignOffset(textAlign, width) {
1075
1132
  switch (textAlign) {
1076
1133
  case "center":
@@ -1081,7 +1138,8 @@ function getTextAlignOffset(textAlign, width) {
1081
1138
  return 0;
1082
1139
  }
1083
1140
  }
1084
- function printAtWordWrap(context, fullText, x, y, lineHeight, fitWidth, padding, alignment) {
1141
+ function printAtWordWrap(context, fullText, textAlign, y, lineHeight, fitWidth, padding) {
1142
+ const x = getTextAlignOffset(textAlign, fitWidth - padding * 2);
1085
1143
  const lines = fullText.split("\n");
1086
1144
  let currentLine = 0;
1087
1145
  for (const text of lines) {
@@ -1098,7 +1156,30 @@ function printAtWordWrap(context, fullText, x, y, lineHeight, fitWidth, padding,
1098
1156
  const textWidth = context.measureText(str).width;
1099
1157
  if (textWidth + padding * 2 > fitWidth) {
1100
1158
  if (lastWordIndex === 1) {
1101
- lastWordIndex = 2;
1159
+ const word = words[0];
1160
+ let charIndex = 1;
1161
+ while (charIndex < word.length) {
1162
+ const substring = word.substring(0, charIndex);
1163
+ const subWidth = context.measureText(substring).width;
1164
+ if (subWidth + padding * 2 > fitWidth) {
1165
+ if (charIndex === 1)
1166
+ charIndex = 2;
1167
+ context.fillText(
1168
+ word.substring(0, charIndex - 1),
1169
+ x + padding,
1170
+ y + lineHeight * currentLine + padding
1171
+ );
1172
+ currentLine++;
1173
+ words[0] = word.substring(charIndex - 1);
1174
+ break;
1175
+ }
1176
+ charIndex++;
1177
+ }
1178
+ if (charIndex >= word.length) {
1179
+ lastWordIndex = 2;
1180
+ } else {
1181
+ continue;
1182
+ }
1102
1183
  }
1103
1184
  context.fillText(
1104
1185
  words.slice(0, lastWordIndex - 1).join(" "),
@@ -1113,64 +1194,96 @@ function printAtWordWrap(context, fullText, x, y, lineHeight, fitWidth, padding,
1113
1194
  }
1114
1195
  }
1115
1196
  if (lastWordIndex > 0 && words.length > 0) {
1116
- const xOffset = alignment === "center" ? 0 : padding;
1117
- context.fillText(words.join(" "), x + xOffset, y + lineHeight * currentLine + padding);
1197
+ context.fillText(words.join(" "), x + padding, y + lineHeight * currentLine + padding);
1118
1198
  currentLine++;
1119
1199
  }
1120
1200
  }
1121
1201
  }
1122
- function CanvasText(message, options) {
1123
- const fontsize = options.fontSize;
1124
- const textColor = options.textColorRGB255A1;
1125
- const backgroundColor = options.backgroundColorRGB255A1 || { r: 255, g: 255, b: 255, a: 1 };
1126
- const padding = options.paddingPx || 0;
1127
- const font = options.font || "Arial";
1128
- const fontString = (options.bold ? "bold " : "") + fontsize + "px " + font;
1129
- const canvas2 = document.createElement("canvas");
1130
- const ct = canvas2.getContext("2d");
1131
- const textAlign = options.alignment ?? "left";
1132
- if (options.dimensions) {
1133
- canvas2.width = options.dimensions.width;
1134
- canvas2.height = options.dimensions.height;
1135
- ct.clearRect(0, 0, canvas2.width, canvas2.height);
1136
- ct.font = fontString;
1137
- ct.textAlign = textAlign;
1138
- ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1139
- ct.lineWidth = 0;
1140
- ct.fillRect(0, 0, canvas2.width, canvas2.height);
1141
- ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1142
- ct.font = fontString;
1143
- printAtWordWrap(
1144
- ct,
1145
- message,
1146
- getTextAlignOffset(textAlign, canvas2.width),
1147
- fontsize,
1148
- fontsize,
1149
- canvas2.width,
1150
- padding,
1151
- textAlign
1152
- );
1153
- } else {
1154
- ct.font = fontString;
1155
- const metrics = ct.measureText(message);
1156
- const textWidth = metrics.width;
1157
- const textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
1158
- canvas2.width = textWidth + padding * 2;
1159
- canvas2.height = textHeight + padding;
1160
- ct.clearRect(0, 0, canvas2.width, canvas2.height);
1161
- ct.font = fontString;
1162
- ct.textAlign = textAlign;
1163
- ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1164
- ct.lineWidth = 0;
1165
- ct.fillRect(0, 0, canvas2.width, canvas2.height);
1166
- ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1167
- ct.font = fontString;
1168
- ct.fillText(message, padding + getTextAlignOffset(textAlign, textWidth), textHeight);
1169
- }
1170
- return canvas2;
1171
- }
1202
+ var CanvasText = class {
1203
+ constructor() {
1204
+ this.canvas = document.createElement("canvas");
1205
+ this.context = this.canvas.getContext("2d");
1206
+ }
1207
+ renderText(message, options) {
1208
+ const fontsize = options.fontSize;
1209
+ const textColor = options.textColorRGB255A1;
1210
+ const backgroundColor = options.backgroundColorRGB255A1 || { r: 255, g: 255, b: 255, a: 1 };
1211
+ const padding = options.paddingPx || 0;
1212
+ const font = options.font || "Arial";
1213
+ const fontString = (options.bold ? "bold " : "") + fontsize + "px " + font;
1214
+ const textAlign = options.alignment ?? "left";
1215
+ if (options.dimensions && options.dimensions.maxWidth === void 0) {
1216
+ this.canvas.width = options.dimensions.width;
1217
+ this.canvas.height = options.dimensions.height;
1218
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1219
+ this.context.font = fontString;
1220
+ this.context.textAlign = textAlign;
1221
+ this.context.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1222
+ this.context.lineWidth = 0;
1223
+ this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
1224
+ this.context.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1225
+ printAtWordWrap(
1226
+ this.context,
1227
+ message,
1228
+ textAlign,
1229
+ fontsize,
1230
+ fontsize,
1231
+ this.canvas.width,
1232
+ padding
1233
+ );
1234
+ return this.canvas;
1235
+ } else {
1236
+ this.context.font = fontString;
1237
+ this.context.textAlign = textAlign;
1238
+ const metrics = this.context.measureText(message);
1239
+ const textWidth = metrics.width;
1240
+ const textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
1241
+ if (options.dimensions && options.dimensions.maxWidth !== void 0) {
1242
+ const maxWidthWithoutPadding = options.dimensions.maxWidth - padding * 2;
1243
+ if (textWidth > maxWidthWithoutPadding) {
1244
+ const lineCount = Math.ceil(textWidth / maxWidthWithoutPadding);
1245
+ this.canvas.width = options.dimensions.maxWidth;
1246
+ this.canvas.height = textHeight * lineCount + padding * 2;
1247
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1248
+ this.context.font = fontString;
1249
+ this.context.textAlign = textAlign;
1250
+ this.context.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1251
+ this.context.lineWidth = 0;
1252
+ this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
1253
+ this.context.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1254
+ printAtWordWrap(
1255
+ this.context,
1256
+ message,
1257
+ textAlign,
1258
+ fontsize,
1259
+ fontsize,
1260
+ this.canvas.width,
1261
+ padding
1262
+ );
1263
+ return this.canvas;
1264
+ } else {
1265
+ }
1266
+ }
1267
+ this.canvas.width = textWidth + padding * 2;
1268
+ this.canvas.height = textHeight + padding * 2;
1269
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1270
+ this.context.font = fontString;
1271
+ this.context.textAlign = textAlign;
1272
+ this.context.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
1273
+ this.context.lineWidth = 0;
1274
+ this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
1275
+ this.context.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
1276
+ this.context.fillText(
1277
+ message,
1278
+ padding + getTextAlignOffset(textAlign, textWidth),
1279
+ textHeight
1280
+ );
1281
+ }
1282
+ return this.canvas;
1283
+ }
1284
+ };
1172
1285
  function THREECanvasTextTexture(text, options) {
1173
- const canvas2 = CanvasText(text, options);
1286
+ const canvas2 = new CanvasText().renderText(text, options);
1174
1287
  const texture = new Texture(canvas2);
1175
1288
  texture.minFilter = LinearFilter;
1176
1289
  texture.magFilter = LinearFilter;
@@ -1184,46 +1297,46 @@ var fontScale = 5;
1184
1297
  var defaultLabelColor = new Color2(0);
1185
1298
  var defaultFontColor = new Color2(16777215);
1186
1299
  var defaultLabelAlignment = "center" /* center */;
1187
- var defaultLabelFontSize = 8;
1188
- var defaultLabelPadding = 8;
1189
- var defaultLabelWidth = 0.25;
1190
- var defaultLabelHeight = 0.1;
1191
- var defaultLabelCastShadows = true;
1192
- var tooltipGeometry = new PlaneGeometry(1, 1, 1, 1);
1193
- var CharacterTooltip = class extends Mesh3 {
1300
+ var defaultLabelFontSize = 10;
1301
+ var defaultLabelPadding = 10;
1302
+ var defaultVisibleOpacity = 0.85;
1303
+ var defaultSecondsToFadeOut = null;
1304
+ var CharacterTooltip = class extends Sprite {
1194
1305
  constructor(configArg) {
1195
- super(tooltipGeometry);
1196
- this.visibleOpacity = 0.85;
1306
+ super();
1197
1307
  this.targetOpacity = 0;
1198
1308
  this.fadingSpeed = 0.02;
1199
- this.secondsToFadeOut = 10;
1309
+ this.content = null;
1310
+ this.hideTimeout = null;
1200
1311
  this.config = {
1201
1312
  alignment: defaultLabelAlignment,
1202
- width: defaultLabelWidth,
1203
- height: defaultLabelHeight,
1204
1313
  fontSize: defaultLabelFontSize,
1205
1314
  padding: defaultLabelPadding,
1206
1315
  color: defaultLabelColor,
1207
1316
  fontColor: defaultFontColor,
1208
- castShadows: defaultLabelCastShadows,
1317
+ visibleOpacity: defaultVisibleOpacity,
1318
+ secondsToFadeOut: defaultSecondsToFadeOut,
1209
1319
  ...configArg
1210
1320
  };
1211
- this.tooltipMaterial = new MeshBasicMaterial2({
1321
+ this.material = new SpriteMaterial({
1212
1322
  map: null,
1213
1323
  transparent: true,
1214
- opacity: 0,
1324
+ opacity: this.config.visibleOpacity,
1215
1325
  side: FrontSide
1216
1326
  });
1217
- this.material = this.tooltipMaterial;
1218
1327
  this.position.set(0, 1.6, 0);
1219
1328
  this.visible = false;
1220
1329
  }
1330
+ setHeightOffset(height) {
1331
+ this.position.y = height + this.scale.y / 2;
1332
+ }
1221
1333
  redrawText(content) {
1222
- if (!this.tooltipMaterial) {
1334
+ if (content === this.content) {
1223
1335
  return;
1224
1336
  }
1225
- if (this.tooltipMaterial.map) {
1226
- this.tooltipMaterial.map.dispose();
1337
+ this.content = content;
1338
+ if (this.material.map) {
1339
+ this.material.map.dispose();
1227
1340
  }
1228
1341
  const { texture, width, height } = THREECanvasTextTexture(content, {
1229
1342
  bold: true,
@@ -1241,51 +1354,63 @@ var CharacterTooltip = class extends Mesh3 {
1241
1354
  b: this.config.color.b * 255,
1242
1355
  a: 1
1243
1356
  },
1244
- alignment: this.config.alignment
1357
+ alignment: this.config.alignment,
1358
+ dimensions: this.config.maxWidth !== void 0 ? {
1359
+ maxWidth: this.config.maxWidth
1360
+ } : void 0
1245
1361
  });
1246
- this.tooltipMaterial.map = texture;
1247
- this.tooltipMaterial.map.magFilter = LinearFilter2;
1248
- this.tooltipMaterial.map.minFilter = LinearFilter2;
1249
- this.tooltipMaterial.needsUpdate = true;
1362
+ this.material.map = texture;
1363
+ this.material.map.magFilter = LinearFilter2;
1364
+ this.material.map.minFilter = LinearFilter2;
1365
+ this.material.needsUpdate = true;
1250
1366
  this.scale.x = width / (100 * fontScale);
1251
1367
  this.scale.y = height / (100 * fontScale);
1252
- this.position.y = 1.4;
1253
1368
  }
1254
- setText(text, temporary = false) {
1369
+ setText(text, onRemove) {
1255
1370
  const sanitizedText = text.replace(/(\r\n|\n|\r)/gm, "");
1256
- this.redrawText(sanitizedText);
1257
1371
  this.visible = true;
1258
- this.targetOpacity = this.visibleOpacity;
1259
- if (temporary) {
1260
- setTimeout(() => {
1372
+ this.targetOpacity = this.config.visibleOpacity;
1373
+ if (this.hideTimeout) {
1374
+ clearTimeout(this.hideTimeout);
1375
+ this.hideTimeout = null;
1376
+ }
1377
+ if (this.config.secondsToFadeOut !== null) {
1378
+ this.hideTimeout = setTimeout(() => {
1379
+ this.hideTimeout = null;
1261
1380
  this.hide();
1262
- }, this.secondsToFadeOut * 1e3);
1381
+ if (onRemove) {
1382
+ onRemove();
1383
+ }
1384
+ }, this.config.secondsToFadeOut * 1e3);
1263
1385
  }
1386
+ this.redrawText(sanitizedText);
1264
1387
  }
1265
1388
  hide() {
1266
1389
  this.targetOpacity = 0;
1267
1390
  }
1268
- update(camera) {
1269
- this.lookAt(camera.position);
1270
- const opacity = this.tooltipMaterial.opacity;
1391
+ show() {
1392
+ this.setText(this.content || "");
1393
+ }
1394
+ update() {
1395
+ const opacity = this.material.opacity;
1271
1396
  if (opacity < this.targetOpacity) {
1272
- this.tooltipMaterial.opacity = Math.min(
1273
- this.tooltipMaterial.opacity + this.fadingSpeed,
1397
+ this.material.opacity = Math.min(
1398
+ this.material.opacity + this.fadingSpeed,
1274
1399
  this.targetOpacity
1275
1400
  );
1276
1401
  } else if (opacity > this.targetOpacity) {
1277
- this.tooltipMaterial.opacity = Math.max(
1278
- this.tooltipMaterial.opacity - this.fadingSpeed,
1402
+ this.material.opacity = Math.max(
1403
+ this.material.opacity - this.fadingSpeed,
1279
1404
  this.targetOpacity
1280
1405
  );
1281
- if (opacity >= 1 && this.tooltipMaterial.transparent) {
1282
- this.tooltipMaterial.transparent = false;
1283
- this.tooltipMaterial.needsUpdate = true;
1284
- } else if (opacity > 0 && opacity < 1 && !this.tooltipMaterial.transparent) {
1285
- this.tooltipMaterial.transparent = true;
1286
- this.tooltipMaterial.needsUpdate = true;
1406
+ if (opacity >= 1 && this.material.transparent) {
1407
+ this.material.transparent = false;
1408
+ this.material.needsUpdate = true;
1409
+ } else if (opacity > 0 && opacity < 1 && !this.material.transparent) {
1410
+ this.material.transparent = true;
1411
+ this.material.needsUpdate = true;
1287
1412
  }
1288
- if (this.tooltipMaterial.opacity <= 0) {
1413
+ if (this.material.opacity <= 0) {
1289
1414
  this.visible = false;
1290
1415
  }
1291
1416
  }
@@ -1293,6 +1418,12 @@ var CharacterTooltip = class extends Mesh3 {
1293
1418
  };
1294
1419
 
1295
1420
  // src/character/Character.ts
1421
+ function characterHeightToTooltipHeightOffset(characterHeight) {
1422
+ return characterHeight - 0.4 + 0.1;
1423
+ }
1424
+ function characterDescriptionMatches(a, b) {
1425
+ return a.meshFileUrl === b.meshFileUrl && a.mmlCharacterString === b.mmlCharacterString && a.mmlCharacterUrl === b.mmlCharacterUrl;
1426
+ }
1296
1427
  var Character = class extends Group {
1297
1428
  constructor(config) {
1298
1429
  super();
@@ -1300,18 +1431,42 @@ var Character = class extends Group {
1300
1431
  this.model = null;
1301
1432
  this.color = new Color3();
1302
1433
  this.speakingIndicator = null;
1303
- this.tooltip = new CharacterTooltip();
1304
- this.tooltip.setText(this.config.username, this.config.isLocal);
1434
+ this.chatTooltips = [];
1435
+ this.tooltip = new CharacterTooltip(
1436
+ this.config.isLocal ? {
1437
+ secondsToFadeOut: 10
1438
+ } : {}
1439
+ );
1440
+ this.tooltip.setText(this.config.username);
1305
1441
  this.add(this.tooltip);
1306
1442
  this.load().then(() => {
1307
1443
  this.config.modelLoadedCallback();
1444
+ this.setTooltipHeights();
1308
1445
  });
1309
1446
  }
1310
1447
  updateCharacter(username, characterDescription) {
1311
- this.config.username = username;
1312
- this.config.characterDescription = characterDescription;
1313
- this.load();
1314
- this.tooltip.setText(username, this.config.isLocal);
1448
+ if (!characterDescriptionMatches(this.config.characterDescription, characterDescription)) {
1449
+ this.config.characterDescription = characterDescription;
1450
+ this.load().then(() => {
1451
+ this.setTooltipHeights();
1452
+ });
1453
+ }
1454
+ if (this.config.username !== username) {
1455
+ this.config.username = username;
1456
+ this.tooltip.setText(username);
1457
+ this.tooltip.show();
1458
+ }
1459
+ }
1460
+ setTooltipHeights() {
1461
+ if (this.model && this.model.characterHeight) {
1462
+ let height = characterHeightToTooltipHeightOffset(this.model.characterHeight);
1463
+ this.tooltip.setHeightOffset(height);
1464
+ height += this.tooltip.scale.y;
1465
+ for (const chatTooltip of this.chatTooltips) {
1466
+ chatTooltip.setHeightOffset(height);
1467
+ height += chatTooltip.scale.y;
1468
+ }
1469
+ }
1315
1470
  }
1316
1471
  async load() {
1317
1472
  const previousModel = this.model;
@@ -1327,7 +1482,9 @@ var Character = class extends Group {
1327
1482
  isLocal: this.config.isLocal
1328
1483
  });
1329
1484
  await this.model.init();
1330
- this.add(this.model.mesh);
1485
+ if (this.model.mesh) {
1486
+ this.add(this.model.mesh);
1487
+ }
1331
1488
  if (this.speakingIndicator === null) {
1332
1489
  this.speakingIndicator = new CharacterSpeakingIndicator(this.config.composer.postPostScene);
1333
1490
  }
@@ -1341,13 +1498,13 @@ var Character = class extends Group {
1341
1498
  if (!this.model)
1342
1499
  return;
1343
1500
  if (this.tooltip) {
1344
- this.tooltip.update(this.config.cameraManager.camera);
1501
+ this.tooltip.update();
1345
1502
  }
1346
1503
  if (this.speakingIndicator) {
1347
1504
  this.speakingIndicator.setTime(time);
1348
1505
  if (this.model.mesh && this.model.headBone) {
1349
1506
  this.speakingIndicator.setBillboarding(
1350
- (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector34()),
1507
+ (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector35()),
1351
1508
  this.config.cameraManager.camera
1352
1509
  );
1353
1510
  }
@@ -1358,13 +1515,31 @@ var Character = class extends Group {
1358
1515
  var _a;
1359
1516
  return ((_a = this.model) == null ? void 0 : _a.currentAnimation) || 0 /* idle */;
1360
1517
  }
1518
+ addChatBubble(message) {
1519
+ const tooltip = new CharacterTooltip({
1520
+ maxWidth: 1e3,
1521
+ secondsToFadeOut: 10,
1522
+ color: new Color3(0.125, 0.125, 0.125)
1523
+ });
1524
+ this.add(tooltip);
1525
+ this.chatTooltips.push(tooltip);
1526
+ tooltip.setText(message, () => {
1527
+ this.chatTooltips = this.chatTooltips.filter((t) => t !== tooltip);
1528
+ this.remove(tooltip);
1529
+ this.setTooltipHeights();
1530
+ });
1531
+ if (this.config.isLocal) {
1532
+ this.tooltip.show();
1533
+ }
1534
+ this.setTooltipHeights();
1535
+ }
1361
1536
  };
1362
1537
 
1363
1538
  // src/character/CharacterManager.ts
1364
- import { Euler as Euler2, Group as Group2, Quaternion as Quaternion5, Vector3 as Vector38 } from "three";
1539
+ import { Euler as Euler2, Group as Group2, Quaternion as Quaternion5, Vector3 as Vector39 } from "three";
1365
1540
 
1366
1541
  // src/character/LocalController.ts
1367
- import { Euler, Line3, Matrix4, Quaternion as Quaternion2, Ray, Raycaster as Raycaster2, Vector3 as Vector35 } from "three";
1542
+ import { Euler, Line3, Matrix4, Quaternion as Quaternion2, Ray, Raycaster as Raycaster2, Vector3 as Vector36 } from "three";
1368
1543
 
1369
1544
  // src/tweakpane/blades/characterControlsFolder.ts
1370
1545
  var characterControllerValues = {
@@ -1547,13 +1722,13 @@ var CharacterControlsFolder = class {
1547
1722
  };
1548
1723
 
1549
1724
  // src/character/LocalController.ts
1550
- var downVector = new Vector35(0, -1, 0);
1725
+ var downVector = new Vector36(0, -1, 0);
1551
1726
  var LocalController = class {
1552
1727
  constructor(config) {
1553
1728
  this.config = config;
1554
1729
  this.capsuleInfo = {
1555
1730
  radius: 0.4,
1556
- segment: new Line3(new Vector35(), new Vector35(0, 1.05, 0))
1731
+ segment: new Line3(new Vector36(), new Vector36(0, 1.05, 0))
1557
1732
  };
1558
1733
  this.gravity = -characterControllerValues.gravity;
1559
1734
  this.jumpForce = characterControllerValues.jumpForce;
@@ -1571,34 +1746,34 @@ var LocalController = class {
1571
1746
  this.groundRunControl = characterControllerValues.groundRunControl;
1572
1747
  this.baseControl = characterControllerValues.baseControlMultiplier;
1573
1748
  this.minimumSurfaceAngle = characterControllerValues.minimumSurfaceAngle;
1574
- this.latestPosition = new Vector35();
1749
+ this.latestPosition = new Vector36();
1575
1750
  this.characterOnGround = false;
1576
1751
  this.coyoteTime = false;
1577
1752
  this.collisionDetectionSteps = 15;
1578
1753
  this.characterWasOnGround = false;
1579
1754
  this.characterAirborneSince = 0;
1580
1755
  this.currentHeight = 0;
1581
- this.currentSurfaceAngle = new Vector35();
1582
- this.characterVelocity = new Vector35();
1583
- this.vectorUp = new Vector35(0, 1, 0);
1584
- this.vectorDown = new Vector35(0, -1, 0);
1756
+ this.currentSurfaceAngle = new Vector36();
1757
+ this.characterVelocity = new Vector36();
1758
+ this.vectorUp = new Vector36(0, 1, 0);
1759
+ this.vectorDown = new Vector36(0, -1, 0);
1585
1760
  this.rotationOffset = 0;
1586
1761
  this.azimuthalAngle = 0;
1587
1762
  this.tempMatrix = new Matrix4();
1588
1763
  this.tempSegment = new Line3();
1589
1764
  this.tempQuaternion = new Quaternion2();
1590
1765
  this.tempEuler = new Euler();
1591
- this.tempVector = new Vector35();
1592
- this.tempVector2 = new Vector35();
1593
- this.tempVector3 = new Vector35();
1766
+ this.tempVector = new Vector36();
1767
+ this.tempVector2 = new Vector36();
1768
+ this.tempVector3 = new Vector36();
1594
1769
  this.rayCaster = new Raycaster2();
1595
1770
  this.surfaceTempQuaternion = new Quaternion2();
1596
1771
  this.surfaceTempQuaternion2 = new Quaternion2();
1597
- this.surfaceTempVector1 = new Vector35();
1598
- this.surfaceTempVector2 = new Vector35();
1599
- this.surfaceTempVector3 = new Vector35();
1600
- this.surfaceTempVector4 = new Vector35();
1601
- this.surfaceTempVector5 = new Vector35();
1772
+ this.surfaceTempVector1 = new Vector36();
1773
+ this.surfaceTempVector2 = new Vector36();
1774
+ this.surfaceTempVector3 = new Vector36();
1775
+ this.surfaceTempVector4 = new Vector36();
1776
+ this.surfaceTempVector5 = new Vector36();
1602
1777
  this.surfaceTempRay = new Ray();
1603
1778
  this.lastFrameSurfaceState = null;
1604
1779
  this.jumpPressed = false;
@@ -1666,17 +1841,17 @@ var LocalController = class {
1666
1841
  }
1667
1842
  }
1668
1843
  updateAzimuthalAngle() {
1669
- const camToModelDistance = this.config.cameraManager.camera.position.distanceTo(
1844
+ const camToModelDistance = this.config.cameraManager.activeCamera.position.distanceTo(
1670
1845
  this.config.character.position
1671
1846
  );
1672
1847
  const isCameraFirstPerson = camToModelDistance < 2;
1673
1848
  if (isCameraFirstPerson) {
1674
- const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.config.cameraManager.camera.quaternion);
1849
+ const cameraForward = this.tempVector.set(0, 0, 1).applyQuaternion(this.config.cameraManager.activeCamera.quaternion);
1675
1850
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1676
1851
  } else {
1677
1852
  this.azimuthalAngle = Math.atan2(
1678
- this.config.cameraManager.camera.position.x - this.config.character.position.x,
1679
- this.config.cameraManager.camera.position.z - this.config.character.position.z
1853
+ this.config.cameraManager.activeCamera.position.x - this.config.character.position.x,
1854
+ this.config.cameraManager.activeCamera.position.z - this.config.character.position.z
1680
1855
  );
1681
1856
  }
1682
1857
  }
@@ -1895,7 +2070,7 @@ var LocalController = class {
1895
2070
  };
1896
2071
 
1897
2072
  // src/character/RemoteController.ts
1898
- import { Quaternion as Quaternion3, Vector3 as Vector36 } from "three";
2073
+ import { Quaternion as Quaternion3, Vector3 as Vector37 } from "three";
1899
2074
  var tempQuaternion = new Quaternion3();
1900
2075
  var RemoteController = class {
1901
2076
  constructor(config) {
@@ -1924,7 +2099,7 @@ var RemoteController = class {
1924
2099
  }
1925
2100
  updateFromNetwork(clientUpdate) {
1926
2101
  const { position, rotation, state } = clientUpdate;
1927
- this.config.character.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
2102
+ this.config.character.position.lerp(new Vector37(position.x, position.y, position.z), 0.15);
1928
2103
  const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1929
2104
  this.config.character.quaternion.slerp(rotationQuaternion, 0.6);
1930
2105
  if (state !== this.currentAnimation) {
@@ -1935,7 +2110,7 @@ var RemoteController = class {
1935
2110
  };
1936
2111
 
1937
2112
  // src/character/url-position.ts
1938
- import { Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
2113
+ import { Quaternion as Quaternion4, Vector3 as Vector38 } from "three";
1939
2114
  function encodeCharacterAndCamera(character, camera) {
1940
2115
  return [
1941
2116
  ...toArray(character.position),
@@ -1948,11 +2123,11 @@ function decodeCharacterAndCamera(hash) {
1948
2123
  const values = hash.split(",").map(Number);
1949
2124
  return {
1950
2125
  character: {
1951
- position: new Vector37(values[0], values[1], values[2]),
2126
+ position: new Vector38(values[0], values[1], values[2]),
1952
2127
  quaternion: new Quaternion4(values[3], values[4], values[5], values[6])
1953
2128
  },
1954
2129
  camera: {
1955
- position: new Vector37(values[7], values[8], values[9]),
2130
+ position: new Vector38(values[7], values[8], values[9]),
1956
2131
  quaternion: new Quaternion4(values[10], values[11], values[12], values[13])
1957
2132
  }
1958
2133
  };
@@ -1962,16 +2137,17 @@ function decodeCharacterAndCamera(hash) {
1962
2137
  var CharacterManager = class {
1963
2138
  constructor(config) {
1964
2139
  this.config = config;
1965
- this.headTargetOffset = new Vector38(0, 1.3, 0);
2140
+ this.headTargetOffset = new Vector39(0, 1.3, 0);
1966
2141
  this.localClientId = 0;
1967
2142
  this.remoteCharacters = /* @__PURE__ */ new Map();
1968
2143
  this.remoteCharacterControllers = /* @__PURE__ */ new Map();
1969
2144
  this.localCharacterSpawned = false;
1970
2145
  this.localCharacter = null;
1971
2146
  this.speakingCharacters = /* @__PURE__ */ new Map();
2147
+ this.lastUpdateSentTime = 0;
1972
2148
  this.group = new Group2();
1973
2149
  }
1974
- spawnLocalCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
2150
+ spawnLocalCharacter(id, username, characterDescription, spawnPosition = new Vector39(), spawnRotation = new Euler2()) {
1975
2151
  const character = new Character({
1976
2152
  username,
1977
2153
  characterDescription,
@@ -2014,7 +2190,7 @@ var CharacterManager = class {
2014
2190
  setupTweakPane(tweakPane) {
2015
2191
  tweakPane.setupCharacterController(this.localController);
2016
2192
  }
2017
- spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector38(), spawnRotation = new Euler2()) {
2193
+ spawnRemoteCharacter(id, username, characterDescription, spawnPosition = new Vector39(), spawnRotation = new Euler2()) {
2018
2194
  const character = new Character({
2019
2195
  username,
2020
2196
  characterDescription,
@@ -2060,6 +2236,15 @@ var CharacterManager = class {
2060
2236
  setSpeakingCharacter(id, value) {
2061
2237
  this.speakingCharacters.set(id, value);
2062
2238
  }
2239
+ addSelfChatBubble(message) {
2240
+ if (this.localCharacter) {
2241
+ this.localCharacter.addChatBubble(message);
2242
+ }
2243
+ }
2244
+ addChatBubble(id, message) {
2245
+ var _a;
2246
+ (_a = this.remoteCharacters.get(id)) == null ? void 0 : _a.addChatBubble(message);
2247
+ }
2063
2248
  respawnIfPresent(id) {
2064
2249
  const characterInfo = this.config.characterResolve(id);
2065
2250
  if (this.localCharacter && this.localClientId == id) {
@@ -2083,10 +2268,13 @@ var CharacterManager = class {
2083
2268
  );
2084
2269
  }
2085
2270
  this.localController.update();
2086
- if (this.config.timeManager.frame % 2 === 0) {
2271
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
2272
+ const timeSinceLastUpdate = currentTime - this.lastUpdateSentTime;
2273
+ if (timeSinceLastUpdate > 30) {
2274
+ this.lastUpdateSentTime = currentTime;
2087
2275
  this.config.sendUpdate(this.localController.networkState);
2088
2276
  }
2089
- const targetOffset = new Vector38();
2277
+ const targetOffset = new Vector39();
2090
2278
  targetOffset.add(this.headTargetOffset).applyQuaternion(this.localCharacter.quaternion).add(this.localCharacter.position);
2091
2279
  this.config.cameraManager.setTarget(targetOffset);
2092
2280
  for (const [id, update] of this.config.remoteUserStates) {
@@ -2101,7 +2289,7 @@ var CharacterManager = class {
2101
2289
  id,
2102
2290
  characterInfo.username,
2103
2291
  characterInfo.characterDescription,
2104
- new Vector38(position.x, position.y, position.z)
2292
+ new Vector39(position.x, position.y, position.z)
2105
2293
  );
2106
2294
  }
2107
2295
  const characterController = this.remoteCharacterControllers.get(id);
@@ -2197,35 +2385,42 @@ var CharacterModelLoader = class {
2197
2385
  }
2198
2386
  }
2199
2387
  async loadFromUrl(url, fileType, extension) {
2200
- if (["gltf", "glb"].includes(extension)) {
2201
- return new Promise(async (resolve, reject) => {
2202
- const modelLoadResult = await this.modelLoader.load(
2203
- url,
2204
- (loaded, total) => {
2205
- }
2206
- );
2207
- if (fileType === "model") {
2208
- resolve(modelLoadResult.group);
2209
- } else if (fileType === "animation") {
2210
- resolve(modelLoadResult.animations[0]);
2211
- } else {
2212
- const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
2213
- console.error(error);
2214
- reject(error);
2388
+ return new Promise(async (resolve, reject) => {
2389
+ const modelLoadResult = await this.modelLoader.load(
2390
+ url,
2391
+ (loaded, total) => {
2215
2392
  }
2216
- });
2217
- } else {
2218
- console.error(`Error: can't recognize ${url} extension: ${extension}`);
2219
- }
2393
+ );
2394
+ if (fileType === "model") {
2395
+ resolve(modelLoadResult.group);
2396
+ } else if (fileType === "animation") {
2397
+ resolve(modelLoadResult.animations[0]);
2398
+ } else {
2399
+ const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
2400
+ console.error(error);
2401
+ reject(error);
2402
+ }
2403
+ });
2220
2404
  }
2221
2405
  };
2222
2406
 
2223
2407
  // src/input/KeyInputManager.ts
2408
+ var Key = /* @__PURE__ */ ((Key2) => {
2409
+ Key2["W"] = "w";
2410
+ Key2["A"] = "a";
2411
+ Key2["S"] = "s";
2412
+ Key2["D"] = "d";
2413
+ Key2["SHIFT"] = "shift";
2414
+ Key2["SPACE"] = " ";
2415
+ Key2["C"] = "c";
2416
+ return Key2;
2417
+ })(Key || {});
2224
2418
  var KeyInputManager = class {
2225
2419
  constructor(shouldCaptureKeyPress = () => true) {
2226
2420
  this.shouldCaptureKeyPress = shouldCaptureKeyPress;
2227
2421
  this.keys = /* @__PURE__ */ new Map();
2228
2422
  this.eventHandlerCollection = new EventHandlerCollection();
2423
+ this.bindings = /* @__PURE__ */ new Map();
2229
2424
  this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
2230
2425
  this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
2231
2426
  this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this));
@@ -2247,10 +2442,16 @@ var KeyInputManager = class {
2247
2442
  }
2248
2443
  onKeyUp(event) {
2249
2444
  this.keys.set(event.key.toLowerCase(), false);
2445
+ if (this.bindings.has(event.key.toLowerCase())) {
2446
+ this.bindings.get(event.key.toLowerCase())();
2447
+ }
2250
2448
  }
2251
2449
  isKeyPressed(key) {
2252
2450
  return this.keys.get(key) || false;
2253
2451
  }
2452
+ createKeyBinding(key, callback) {
2453
+ this.bindings.set(key, callback);
2454
+ }
2254
2455
  isMovementKeyPressed() {
2255
2456
  return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
2256
2457
  }
@@ -2287,6 +2488,7 @@ var KeyInputManager = class {
2287
2488
  }
2288
2489
  dispose() {
2289
2490
  this.eventHandlerCollection.clear();
2491
+ this.bindings.clear();
2290
2492
  }
2291
2493
  };
2292
2494
 
@@ -2487,11 +2689,15 @@ var VirtualJoystick = class _VirtualJoystick {
2487
2689
  // src/mml/MMLCompositionScene.ts
2488
2690
  import {
2489
2691
  InteractionManager,
2490
- MMLClickTrigger,
2491
- PromptManager,
2492
2692
  LoadingProgressManager,
2493
- MMLDocumentTimeManager
2494
- } from "mml-web";
2693
+ MMLDocumentTimeManager,
2694
+ PromptManager
2695
+ } from "@mml-io/mml-web";
2696
+ import {
2697
+ ThreeJSClickTrigger,
2698
+ ThreeJSGraphicsInterface,
2699
+ ThreeJSInteractionAdapter
2700
+ } from "@mml-io/mml-web-threejs";
2495
2701
  import { Group as Group3 } from "three";
2496
2702
  var MMLCompositionScene = class {
2497
2703
  constructor(config) {
@@ -2499,21 +2705,54 @@ var MMLCompositionScene = class {
2499
2705
  this.chatProbes = /* @__PURE__ */ new Set();
2500
2706
  this.group = new Group3();
2501
2707
  this.promptManager = PromptManager.init(this.config.targetElement);
2708
+ const graphicsAdapter = {
2709
+ collisionType: null,
2710
+ containerType: null,
2711
+ getGraphicsAdapterFactory: () => {
2712
+ return ThreeJSGraphicsInterface;
2713
+ },
2714
+ getRootContainer: () => {
2715
+ return this.group;
2716
+ },
2717
+ interactionShouldShowDistance(interaction) {
2718
+ return ThreeJSInteractionAdapter.interactionShouldShowDistance(
2719
+ interaction,
2720
+ this.config.camera,
2721
+ this.config.scene
2722
+ );
2723
+ },
2724
+ dispose() {
2725
+ },
2726
+ getAudioListener: () => {
2727
+ return config.audioListener;
2728
+ },
2729
+ getCamera: () => {
2730
+ return config.camera;
2731
+ },
2732
+ getThreeScene: () => {
2733
+ return config.scene;
2734
+ },
2735
+ getUserPositionAndRotation: () => {
2736
+ return this.config.getUserPositionAndRotation();
2737
+ }
2738
+ };
2502
2739
  const { interactionListener, interactionManager } = InteractionManager.init(
2503
2740
  this.config.targetElement,
2504
- this.config.camera,
2505
- this.config.scene
2741
+ (interaction) => {
2742
+ return graphicsAdapter.interactionShouldShowDistance(interaction);
2743
+ }
2506
2744
  );
2507
2745
  this.interactionManager = interactionManager;
2508
2746
  this.interactionListener = interactionListener;
2509
2747
  this.loadingProgressManager = new LoadingProgressManager();
2510
2748
  this.documentTimeManager = new MMLDocumentTimeManager();
2511
2749
  this.mmlScene = {
2512
- getAudioListener: () => this.config.audioListener,
2513
- getRenderer: () => this.config.renderer,
2514
- getThreeScene: () => this.config.scene,
2515
- getRootContainer: () => this.group,
2516
- getCamera: () => this.config.camera,
2750
+ getGraphicsAdapter() {
2751
+ return graphicsAdapter;
2752
+ },
2753
+ hasGraphicsAdapter() {
2754
+ return true;
2755
+ },
2517
2756
  addCollider: (object, mElement) => {
2518
2757
  this.config.collisionsManager.addMeshesGroup(object, mElement);
2519
2758
  },
@@ -2551,7 +2790,11 @@ var MMLCompositionScene = class {
2551
2790
  return this.loadingProgressManager;
2552
2791
  }
2553
2792
  };
2554
- this.clickTrigger = MMLClickTrigger.init(this.config.targetElement, this.mmlScene);
2793
+ this.clickTrigger = ThreeJSClickTrigger.init(
2794
+ this.config.targetElement,
2795
+ this.group,
2796
+ this.config.camera
2797
+ );
2555
2798
  }
2556
2799
  onChatMessage(message) {
2557
2800
  for (const chatProbe of this.chatProbes) {
@@ -3612,12 +3855,12 @@ import {
3612
3855
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
3613
3856
 
3614
3857
  // src/sun/Sun.ts
3615
- import { CameraHelper, Color as Color5, DirectionalLight, Group as Group4, OrthographicCamera, Vector3 as Vector39 } from "three";
3858
+ import { CameraHelper, Color as Color5, DirectionalLight, Group as Group4, OrthographicCamera, Vector3 as Vector310 } from "three";
3616
3859
  var Sun = class extends Group4 {
3617
3860
  constructor() {
3618
3861
  super();
3619
3862
  this.debug = false;
3620
- this.sunOffset = new Vector39(
3863
+ this.sunOffset = new Vector310(
3621
3864
  sunValues.sunPosition.sunAzimuthalAngle * (Math.PI / 180),
3622
3865
  sunValues.sunPosition.sunPolarAngle * (Math.PI / 180),
3623
3866
  100
@@ -3645,7 +3888,7 @@ var Sun = class extends Group4 {
3645
3888
  this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
3646
3889
  this.directionalLight.castShadow = true;
3647
3890
  this.setColor();
3648
- this.updateCharacterPosition(new Vector39(0, 0, 0));
3891
+ this.updateCharacterPosition(new Vector310(0, 0, 0));
3649
3892
  this.add(this.directionalLight);
3650
3893
  if (this.debug === true && this.camHelper instanceof CameraHelper) {
3651
3894
  this.add(this.camHelper);
@@ -3683,7 +3926,7 @@ var Sun = class extends Group4 {
3683
3926
  if (!this.target)
3684
3927
  return;
3685
3928
  const distance = this.sunOffset.z;
3686
- const sphericalPosition = new Vector39(
3929
+ const sphericalPosition = new Vector310(
3687
3930
  distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
3688
3931
  distance * Math.cos(polarAngle),
3689
3932
  distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
@@ -3858,7 +4101,7 @@ import {
3858
4101
  ShaderMaterial as ShaderMaterial4,
3859
4102
  Uniform as Uniform7,
3860
4103
  Vector2 as Vector26,
3861
- Vector3 as Vector313,
4104
+ Vector3 as Vector314,
3862
4105
  WebGLMultipleRenderTargets,
3863
4106
  WebGLRenderTarget
3864
4107
  } from "three";
@@ -4003,7 +4246,7 @@ var DepthDownSample = {
4003
4246
  };
4004
4247
 
4005
4248
  // src/rendering/post-effects/n8-ssao/EffectCompositer.ts
4006
- import { Matrix4 as Matrix43, Uniform as Uniform4, Vector2 as Vector23, Vector3 as Vector310 } from "three";
4249
+ import { Matrix4 as Matrix43, Uniform as Uniform4, Vector2 as Vector23, Vector3 as Vector311 } from "three";
4007
4250
  var EffectCompositer = {
4008
4251
  uniforms: {
4009
4252
  sceneDiffuse: new Uniform4(null),
@@ -4013,9 +4256,9 @@ var EffectCompositer = {
4013
4256
  viewMat: new Uniform4(new Matrix43()),
4014
4257
  projectionMatrixInv: new Uniform4(new Matrix43()),
4015
4258
  viewMatrixInv: new Uniform4(new Matrix43()),
4016
- cameraPos: new Uniform4(new Vector310()),
4259
+ cameraPos: new Uniform4(new Vector311()),
4017
4260
  resolution: new Uniform4(new Vector23()),
4018
- color: new Uniform4(new Vector310()),
4261
+ color: new Uniform4(new Vector311()),
4019
4262
  blueNoise: new Uniform4(null),
4020
4263
  downsampledDepth: new Uniform4(null),
4021
4264
  time: new Uniform4(0),
@@ -4266,7 +4509,7 @@ var EffectCompositer = {
4266
4509
  };
4267
4510
 
4268
4511
  // src/rendering/post-effects/n8-ssao/EffectShader.ts
4269
- import { Matrix4 as Matrix44, Uniform as Uniform5, Vector2 as Vector24, Vector3 as Vector311 } from "three";
4512
+ import { Matrix4 as Matrix44, Uniform as Uniform5, Vector2 as Vector24, Vector3 as Vector312 } from "three";
4270
4513
  var EffectShader = {
4271
4514
  uniforms: {
4272
4515
  sceneDiffuse: new Uniform5(null),
@@ -4277,7 +4520,7 @@ var EffectShader = {
4277
4520
  projViewMat: new Uniform5(new Matrix44()),
4278
4521
  projectionMatrixInv: new Uniform5(new Matrix44()),
4279
4522
  viewMatrixInv: new Uniform5(new Matrix44()),
4280
- cameraPos: new Uniform5(new Vector311()),
4523
+ cameraPos: new Uniform5(new Vector312()),
4281
4524
  resolution: new Uniform5(new Vector24()),
4282
4525
  time: new Uniform5(0),
4283
4526
  samples: new Uniform5([]),
@@ -4489,7 +4732,7 @@ var EffectShader = {
4489
4732
  import {
4490
4733
  BufferAttribute,
4491
4734
  BufferGeometry,
4492
- Mesh as Mesh4,
4735
+ Mesh as Mesh3,
4493
4736
  OrthographicCamera as OrthographicCamera2,
4494
4737
  Sphere
4495
4738
  } from "three";
@@ -4505,7 +4748,7 @@ var FullScreenTriangle = class {
4505
4748
  this.geometry.boundingSphere = new Sphere();
4506
4749
  this.geometry.computeBoundingSphere = function() {
4507
4750
  };
4508
- this.mesh = new Mesh4(this.geometry, material);
4751
+ this.mesh = new Mesh3(this.geometry, material);
4509
4752
  this.mesh.frustumCulled = false;
4510
4753
  }
4511
4754
  get material() {
@@ -4524,7 +4767,7 @@ var FullScreenTriangle = class {
4524
4767
  };
4525
4768
 
4526
4769
  // src/rendering/post-effects/n8-ssao/PoissionBlur.ts
4527
- import { Matrix4 as Matrix45, Uniform as Uniform6, Vector2 as Vector25, Vector3 as Vector312 } from "three";
4770
+ import { Matrix4 as Matrix45, Uniform as Uniform6, Vector2 as Vector25, Vector3 as Vector313 } from "three";
4528
4771
  var PoissionBlur = {
4529
4772
  uniforms: {
4530
4773
  sceneDiffuse: new Uniform6(null),
@@ -4534,7 +4777,7 @@ var PoissionBlur = {
4534
4777
  viewMat: new Uniform6(new Matrix45()),
4535
4778
  projectionMatrixInv: new Uniform6(new Matrix45()),
4536
4779
  viewMatrixInv: new Uniform6(new Matrix45()),
4537
- cameraPos: new Uniform6(new Vector312()),
4780
+ cameraPos: new Uniform6(new Vector313()),
4538
4781
  resolution: new Uniform6(new Vector25()),
4539
4782
  time: new Uniform6(0),
4540
4783
  r: new Uniform6(5),
@@ -4920,7 +5163,7 @@ var N8SSAOPass = class extends Pass {
4920
5163
  const x = r * Math.cos(theta);
4921
5164
  const y = r * Math.sin(theta);
4922
5165
  const z = Math.sqrt(1 - (x * x + y * y));
4923
- points.push(new Vector313(x, y, z));
5166
+ points.push(new Vector314(x, y, z));
4924
5167
  }
4925
5168
  return points;
4926
5169
  }
@@ -5019,7 +5262,7 @@ var N8SSAOPass = class extends Pass {
5019
5262
  effectShaderUniforms.projViewMat.value = this.camera.projectionMatrix.clone().multiply(this.camera.matrixWorldInverse.clone());
5020
5263
  effectShaderUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
5021
5264
  effectShaderUniforms.viewMatrixInv.value = this.camera.matrixWorld;
5022
- effectShaderUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
5265
+ effectShaderUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector314());
5023
5266
  effectShaderUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
5024
5267
  effectShaderUniforms.time.value = performance.now() / 1e3;
5025
5268
  effectShaderUniforms.samples.value = this.samples;
@@ -5048,7 +5291,7 @@ var N8SSAOPass = class extends Pass {
5048
5291
  poissonBlurUniforms.viewMat.value = this.camera.matrixWorldInverse;
5049
5292
  poissonBlurUniforms.projectionMatrixInv.value = this.camera.projectionMatrixInverse;
5050
5293
  poissonBlurUniforms.viewMatrixInv.value = this.camera.matrixWorld;
5051
- poissonBlurUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
5294
+ poissonBlurUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector314());
5052
5295
  poissonBlurUniforms.resolution.value = this.configuration.halfRes ? this.r.clone().multiplyScalar(1 / 2).floor() : this.r;
5053
5296
  poissonBlurUniforms.time.value = performance.now() / 1e3;
5054
5297
  poissonBlurUniforms.blueNoise.value = this.bluenoise;
@@ -5087,7 +5330,7 @@ var N8SSAOPass = class extends Pass {
5087
5330
  effectCompositerUniforms.tDiffuse.value = this.writeTargetInternal.texture;
5088
5331
  effectCompositerUniforms.color.value = this.c.copy(this.configuration.color).convertSRGBToLinear();
5089
5332
  effectCompositerUniforms.colorMultiply.value = this.configuration.colorMultiply;
5090
- effectCompositerUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector313());
5333
+ effectCompositerUniforms.cameraPos.value = this.camera.getWorldPosition(new Vector314());
5091
5334
  effectCompositerUniforms.fog.value = !!this.scene.fog;
5092
5335
  if (this.scene.fog) {
5093
5336
  if (this.scene.fog instanceof Fog && this.scene.fog.isFog === true) {
@@ -5152,7 +5395,7 @@ var N8SSAOPass = class extends Pass {
5152
5395
  var Composer = class {
5153
5396
  constructor({
5154
5397
  scene,
5155
- camera,
5398
+ cameraManager,
5156
5399
  spawnSun = false,
5157
5400
  environmentConfiguration
5158
5401
  }) {
@@ -5166,8 +5409,8 @@ var Composer = class {
5166
5409
  this.sun = null;
5167
5410
  var _a, _b;
5168
5411
  this.scene = scene;
5412
+ this.cameraManager = cameraManager;
5169
5413
  this.postPostScene = new Scene4();
5170
- this.camera = camera;
5171
5414
  this.spawnSun = spawnSun;
5172
5415
  this.renderer = new WebGLRenderer4({
5173
5416
  powerPreference: "high-performance",
@@ -5187,14 +5430,14 @@ var Composer = class {
5187
5430
  this.effectComposer = new EffectComposer2(this.renderer, {
5188
5431
  frameBufferType: HalfFloatType2
5189
5432
  });
5190
- this.renderPass = new RenderPass(this.scene, this.camera);
5191
- this.normalPass = new NormalPass2(this.scene, this.camera);
5433
+ this.renderPass = new RenderPass(this.scene, this.cameraManager.activeCamera);
5434
+ this.normalPass = new NormalPass2(this.scene, this.cameraManager.activeCamera);
5192
5435
  this.normalPass.enabled = ppssaoValues.enabled;
5193
5436
  this.normalTextureEffect = new TextureEffect({
5194
5437
  blendFunction: BlendFunction2.SKIP,
5195
5438
  texture: this.normalPass.texture
5196
5439
  });
5197
- this.ppssaoEffect = new SSAOEffect2(this.camera, this.normalPass.texture, {
5440
+ this.ppssaoEffect = new SSAOEffect2(this.cameraManager.activeCamera, this.normalPass.texture, {
5198
5441
  blendFunction: ppssaoValues.blendFunction,
5199
5442
  distanceScaling: ppssaoValues.distanceScaling,
5200
5443
  depthAwareUpsampling: ppssaoValues.depthAwareUpsampling,
@@ -5212,7 +5455,11 @@ var Composer = class {
5212
5455
  worldProximityThreshold: ppssaoValues.worldProximityThreshold,
5213
5456
  worldProximityFalloff: ppssaoValues.worldProximityFalloff
5214
5457
  });
5215
- this.ppssaoPass = new EffectPass2(this.camera, this.ppssaoEffect, this.normalTextureEffect);
5458
+ this.ppssaoPass = new EffectPass2(
5459
+ this.cameraManager.activeCamera,
5460
+ this.ppssaoEffect,
5461
+ this.normalTextureEffect
5462
+ );
5216
5463
  this.ppssaoPass.enabled = ppssaoValues.enabled;
5217
5464
  this.fxaaEffect = new FXAAEffect();
5218
5465
  if ((_a = environmentConfiguration == null ? void 0 : environmentConfiguration.postProcessing) == null ? void 0 : _a.bloomIntensity) {
@@ -5221,7 +5468,12 @@ var Composer = class {
5221
5468
  this.bloomEffect = new BloomEffect({
5222
5469
  intensity: extrasValues.bloom
5223
5470
  });
5224
- this.n8aopass = new N8SSAOPass(this.scene, this.camera, this.width, this.height);
5471
+ this.n8aopass = new N8SSAOPass(
5472
+ this.scene,
5473
+ this.cameraManager.activeCamera,
5474
+ this.width,
5475
+ this.height
5476
+ );
5225
5477
  this.n8aopass.configuration.aoRadius = n8ssaoValues.aoRadius;
5226
5478
  this.n8aopass.configuration.distanceFalloff = n8ssaoValues.distanceFalloff;
5227
5479
  this.n8aopass.configuration.intensity = n8ssaoValues.intensity;
@@ -5234,8 +5486,8 @@ var Composer = class {
5234
5486
  this.n8aopass.configuration.denoiseSamples = n8ssaoValues.denoiseSamples;
5235
5487
  this.n8aopass.configuration.denoiseRadius = n8ssaoValues.denoiseRadius;
5236
5488
  this.n8aopass.enabled = n8ssaoValues.enabled;
5237
- this.fxaaPass = new EffectPass2(this.camera, this.fxaaEffect);
5238
- this.bloomPass = new EffectPass2(this.camera, this.bloomEffect);
5489
+ this.fxaaPass = new EffectPass2(this.cameraManager.activeCamera, this.fxaaEffect);
5490
+ this.bloomPass = new EffectPass2(this.cameraManager.activeCamera, this.bloomEffect);
5239
5491
  this.toneMappingEffect = new ToneMappingEffect({
5240
5492
  mode: toneMappingValues.mode,
5241
5493
  resolution: toneMappingValues.resolution,
@@ -5250,7 +5502,7 @@ var Composer = class {
5250
5502
  edgeDetectionMode: EdgeDetectionMode.COLOR,
5251
5503
  predicationMode: PredicationMode.DEPTH
5252
5504
  });
5253
- this.toneMappingPass = new EffectPass2(this.camera, this.toneMappingEffect);
5505
+ this.toneMappingPass = new EffectPass2(this.cameraManager.activeCamera, this.toneMappingEffect);
5254
5506
  this.toneMappingPass.enabled = rendererValues.toneMapping === 5 || rendererValues.toneMapping === 0 ? true : false;
5255
5507
  this.bcsPass = new ShaderPass(this.bcs, "tDiffuse");
5256
5508
  this.bcs.uniforms.brightness.value = bcsValues.brightness;
@@ -5259,7 +5511,7 @@ var Composer = class {
5259
5511
  this.gaussGrainPass = new ShaderPass(this.gaussGrainEffect, "tDiffuse");
5260
5512
  this.gaussGrainEffect.uniforms.amount.value = extrasValues.grain;
5261
5513
  this.gaussGrainEffect.uniforms.alpha.value = 1;
5262
- this.smaaPass = new EffectPass2(this.camera, this.smaaEffect);
5514
+ this.smaaPass = new EffectPass2(this.cameraManager.activeCamera, this.smaaEffect);
5263
5515
  this.effectComposer.addPass(this.renderPass);
5264
5516
  if (ppssaoValues.enabled) {
5265
5517
  this.effectComposer.addPass(this.normalPass);
@@ -5346,8 +5598,8 @@ var Composer = class {
5346
5598
  }
5347
5599
  this.width = parentElement.clientWidth;
5348
5600
  this.height = parentElement.clientHeight;
5349
- this.camera.aspect = this.width / this.height;
5350
- this.camera.updateProjectionMatrix();
5601
+ this.cameraManager.activeCamera.aspect = this.width / this.height;
5602
+ this.cameraManager.activeCamera.updateProjectionMatrix();
5351
5603
  this.renderer.setPixelRatio(window.devicePixelRatio);
5352
5604
  this.resolution.set(
5353
5605
  this.width * window.devicePixelRatio,
@@ -5376,11 +5628,12 @@ var Composer = class {
5376
5628
  }
5377
5629
  render(timeManager) {
5378
5630
  this.renderer.info.reset();
5631
+ this.renderPass.mainCamera = this.cameraManager.activeCamera;
5379
5632
  this.normalPass.texture.needsUpdate = true;
5380
5633
  this.gaussGrainEffect.uniforms.time.value = timeManager.time;
5381
5634
  this.effectComposer.render();
5382
5635
  this.renderer.clearDepth();
5383
- this.renderer.render(this.postPostScene, this.camera);
5636
+ this.renderer.render(this.postPostScene, this.cameraManager.activeCamera);
5384
5637
  }
5385
5638
  updateSkyboxRotation() {
5386
5639
  this.scene.backgroundRotation = new Euler3(
@@ -5522,11 +5775,13 @@ var Composer = class {
5522
5775
  }
5523
5776
  if (typeof ((_e = (_d = this.environmentConfiguration) == null ? void 0 : _d.sun) == null ? void 0 : _e.azimuthalAngle) === "number") {
5524
5777
  sunValues.sunPosition.sunAzimuthalAngle = this.environmentConfiguration.sun.azimuthalAngle;
5525
- (_f = this.sun) == null ? void 0 : _f.setAzimuthalAngle(this.environmentConfiguration.sun.azimuthalAngle);
5778
+ (_f = this.sun) == null ? void 0 : _f.setAzimuthalAngle(
5779
+ this.environmentConfiguration.sun.azimuthalAngle * (Math.PI / 180)
5780
+ );
5526
5781
  }
5527
5782
  if (typeof ((_h = (_g = this.environmentConfiguration) == null ? void 0 : _g.sun) == null ? void 0 : _h.polarAngle) === "number") {
5528
5783
  sunValues.sunPosition.sunPolarAngle = this.environmentConfiguration.sun.polarAngle;
5529
- (_i = this.sun) == null ? void 0 : _i.setPolarAngle(this.environmentConfiguration.sun.polarAngle);
5784
+ (_i = this.sun) == null ? void 0 : _i.setPolarAngle(this.environmentConfiguration.sun.polarAngle * (Math.PI / 180));
5530
5785
  }
5531
5786
  }
5532
5787
  updateSkyboxAndEnvValues() {
@@ -5625,39 +5880,73 @@ var TimeManager = class {
5625
5880
  };
5626
5881
 
5627
5882
  // src/collisions/CollisionsManager.ts
5883
+ import { MMLCollisionTrigger } from "@mml-io/mml-web";
5628
5884
  import {
5629
- getRelativePositionAndRotationRelativeToObject,
5630
- MMLCollisionTrigger
5631
- } from "mml-web";
5632
- import {
5633
- Box3,
5885
+ Box3 as Box32,
5634
5886
  Color as Color8,
5635
5887
  DoubleSide,
5636
- Euler as Euler4,
5888
+ Euler as Euler5,
5637
5889
  Group as Group5,
5638
5890
  Line3 as Line32,
5639
- Matrix4 as Matrix46,
5640
- Mesh as Mesh5,
5641
- MeshBasicMaterial as MeshBasicMaterial3,
5642
- Quaternion as Quaternion6,
5891
+ Matrix4 as Matrix47,
5892
+ Mesh as Mesh4,
5893
+ MeshBasicMaterial,
5894
+ Quaternion as Quaternion7,
5643
5895
  Ray as Ray2,
5644
- Vector3 as Vector314
5896
+ Vector3 as Vector316
5645
5897
  } from "three";
5646
5898
  import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
5647
5899
  import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
5648
5900
  import { MeshBVH, MeshBVHHelper } from "three-mesh-bvh";
5901
+
5902
+ // src/collisions/getRelativePositionAndRotationRelativeToObject.ts
5903
+ import { Euler as Euler4, Matrix4 as Matrix46, Quaternion as Quaternion6, Vector3 as Vector315 } from "three";
5904
+ var tempContainerMatrix = new Matrix46();
5905
+ var tempTargetMatrix = new Matrix46();
5906
+ var tempPositionVector = new Vector315();
5907
+ var tempRotationEuler = new Euler4();
5908
+ var tempRotationQuaternion = new Quaternion6();
5909
+ var tempScaleVector = new Vector315();
5910
+ function getRelativePositionAndRotationRelativeToObject(positionAndRotation, container) {
5911
+ const { x, y, z } = positionAndRotation.position;
5912
+ const { x: rx, y: ry, z: rz } = positionAndRotation.rotation;
5913
+ container.updateWorldMatrix(true, false);
5914
+ tempContainerMatrix.copy(container.matrixWorld).invert();
5915
+ tempPositionVector.set(x, y, z);
5916
+ tempRotationEuler.set(rx, ry, rz);
5917
+ tempRotationQuaternion.setFromEuler(tempRotationEuler);
5918
+ tempScaleVector.set(1, 1, 1);
5919
+ tempTargetMatrix.compose(tempPositionVector, tempRotationQuaternion, tempScaleVector);
5920
+ tempTargetMatrix.premultiply(tempContainerMatrix);
5921
+ tempTargetMatrix.decompose(tempPositionVector, tempRotationQuaternion, tempScaleVector);
5922
+ tempRotationEuler.setFromQuaternion(tempRotationQuaternion);
5923
+ return {
5924
+ position: {
5925
+ x: tempPositionVector.x,
5926
+ y: tempPositionVector.y,
5927
+ z: tempPositionVector.z
5928
+ },
5929
+ rotation: {
5930
+ x: tempRotationEuler.x,
5931
+ y: tempRotationEuler.y,
5932
+ z: tempRotationEuler.z
5933
+ }
5934
+ };
5935
+ }
5936
+
5937
+ // src/collisions/CollisionsManager.ts
5649
5938
  var CollisionsManager = class {
5650
5939
  constructor(scene) {
5651
5940
  this.debug = false;
5652
- this.tempVector = new Vector314();
5653
- this.tempVector2 = new Vector314();
5654
- this.tempVector3 = new Vector314();
5655
- this.tempQuaternion = new Quaternion6();
5941
+ this.tempVector = new Vector316();
5942
+ this.tempVector2 = new Vector316();
5943
+ this.tempVector3 = new Vector316();
5944
+ this.tempQuaternion = new Quaternion7();
5656
5945
  this.tempRay = new Ray2();
5657
- this.tempMatrix = new Matrix46();
5658
- this.tempMatrix2 = new Matrix46();
5659
- this.tempBox = new Box3();
5660
- this.tempEuler = new Euler4();
5946
+ this.tempMatrix = new Matrix47();
5947
+ this.tempMatrix2 = new Matrix47();
5948
+ this.tempBox = new Box32();
5949
+ this.tempEuler = new Euler5();
5661
5950
  this.tempSegment = new Line32();
5662
5951
  this.tempSegment2 = new Line32();
5663
5952
  this.collisionMeshState = /* @__PURE__ */ new Map();
@@ -5667,7 +5956,7 @@ var CollisionsManager = class {
5667
5956
  raycastFirst(ray) {
5668
5957
  let minimumDistance = null;
5669
5958
  let minimumHit = null;
5670
- let minimumNormal = new Vector314();
5959
+ let minimumNormal = new Vector316();
5671
5960
  for (const [, collisionMeshState] of this.collisionMeshState) {
5672
5961
  this.tempRay.copy(ray).applyMatrix4(this.tempMatrix.copy(collisionMeshState.matrix).invert());
5673
5962
  const hit = collisionMeshState.meshBVH.raycastFirst(this.tempRay, DoubleSide);
@@ -5725,7 +6014,7 @@ var CollisionsManager = class {
5725
6014
  };
5726
6015
  if (this.debug) {
5727
6016
  newBufferGeometry.boundsTree = meshBVH;
5728
- const wireframeMesh = new Mesh5(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
6017
+ const wireframeMesh = new Mesh4(newBufferGeometry, new MeshBasicMaterial({ wireframe: true }));
5729
6018
  const normalsHelper = new VertexNormalsHelper(wireframeMesh, 0.25, 65280);
5730
6019
  const visualizer = new MeshBVHHelper(wireframeMesh, 4);
5731
6020
  visualizer.edgeMaterial.color = new Color8("blue");
@@ -5808,7 +6097,7 @@ var CollisionsManager = class {
5808
6097
  const realDistance = intersectionSegment.distance();
5809
6098
  if (realDistance < capsuleRadius) {
5810
6099
  if (!collisionPosition) {
5811
- collisionPosition = new Vector314().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
6100
+ collisionPosition = new Vector316().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
5812
6101
  }
5813
6102
  const ratio = realDistance / modelReferenceDistance;
5814
6103
  const realDepth = capsuleRadius - realDistance;
@@ -5866,10 +6155,10 @@ import {
5866
6155
  FrontSide as FrontSide2,
5867
6156
  Group as Group6,
5868
6157
  LinearMipMapLinearFilter,
5869
- Mesh as Mesh6,
6158
+ Mesh as Mesh5,
5870
6159
  MeshStandardMaterial as MeshStandardMaterial3,
5871
6160
  NearestFilter as NearestFilter2,
5872
- PlaneGeometry as PlaneGeometry2,
6161
+ PlaneGeometry,
5873
6162
  RepeatWrapping as RepeatWrapping2
5874
6163
  } from "three";
5875
6164
  var canvas = document.createElement("canvas");
@@ -5886,7 +6175,7 @@ var GroundPlane = class extends Group6 {
5886
6175
  super();
5887
6176
  this.floorSize = 210;
5888
6177
  this.floorTexture = null;
5889
- this.floorGeometry = new PlaneGeometry2(this.floorSize, this.floorSize, 1, 1);
6178
+ this.floorGeometry = new PlaneGeometry(this.floorSize, this.floorSize, 1, 1);
5890
6179
  this.floorMesh = null;
5891
6180
  this.floorMaterial = new MeshStandardMaterial3({
5892
6181
  color: 16777215,
@@ -5894,7 +6183,7 @@ var GroundPlane = class extends Group6 {
5894
6183
  metalness: 0.05,
5895
6184
  roughness: 0.95
5896
6185
  });
5897
- this.floorMesh = new Mesh6(this.floorGeometry, this.floorMaterial);
6186
+ this.floorMesh = new Mesh5(this.floorGeometry, this.floorMaterial);
5898
6187
  this.floorMesh.receiveShadow = true;
5899
6188
  this.floorMesh.rotation.x = Math.PI * -0.5;
5900
6189
  this.add(this.floorMesh);
@@ -5910,59 +6199,134 @@ var GroundPlane = class extends Group6 {
5910
6199
  };
5911
6200
 
5912
6201
  // src/loading-screen/LoadingScreen.ts
5913
- import { LoadingProgressManager as LoadingProgressManager2 } from "mml-web";
6202
+ import { LoadingProgressManager as LoadingProgressManager2 } from "@mml-io/mml-web";
5914
6203
  var LoadingScreen = class {
5915
- constructor(loadingProgressManager) {
6204
+ constructor(loadingProgressManager, config) {
5916
6205
  this.loadingProgressManager = loadingProgressManager;
6206
+ this.config = config;
6207
+ this.overlayLayers = [];
5917
6208
  this.hasCompleted = false;
5918
6209
  this.disposed = false;
6210
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
6211
+ const defaultBackground = "linear-gradient(45deg, #28284B 0%, #303056 100%)";
5919
6212
  this.element = document.createElement("div");
6213
+ this.element.id = "loading-screen";
5920
6214
  this.element.style.position = "absolute";
5921
6215
  this.element.style.top = "0";
5922
6216
  this.element.style.left = "0";
5923
6217
  this.element.style.width = "100%";
5924
6218
  this.element.style.height = "100%";
5925
- this.element.style.background = "linear-gradient(45deg, #28284B 0%, #303056 100%)";
5926
- this.element.style.color = "white";
5927
- this.element.addEventListener("click", (event) => {
5928
- event.stopPropagation();
5929
- });
5930
- this.element.addEventListener("mousedown", (event) => {
5931
- event.stopPropagation();
5932
- });
5933
- this.element.addEventListener("mousemove", (event) => {
5934
- event.stopPropagation();
5935
- });
5936
- this.element.addEventListener("mouseup", (event) => {
5937
- event.stopPropagation();
5938
- });
5939
- this.loadingBannerText = document.createElement("div");
5940
- this.loadingBannerText.textContent = "Loading...";
5941
- this.loadingBannerText.style.position = "absolute";
5942
- this.loadingBannerText.style.display = "flex";
5943
- this.loadingBannerText.style.top = "0";
5944
- this.loadingBannerText.style.left = "0";
5945
- this.loadingBannerText.style.width = "100%";
5946
- this.loadingBannerText.style.height = "100%";
5947
- this.loadingBannerText.style.color = "white";
5948
- this.loadingBannerText.style.fontSize = "80px";
5949
- this.loadingBannerText.style.fontWeight = "bold";
5950
- this.loadingBannerText.style.fontFamily = "sans-serif";
5951
- this.loadingBannerText.style.alignItems = "center";
5952
- this.loadingBannerText.style.justifyContent = "center";
5953
- this.element.append(this.loadingBannerText);
6219
+ this.element.style.backgroundColor = ((_a = this.config) == null ? void 0 : _a.background) || defaultBackground;
6220
+ this.element.style.background = ((_b = this.config) == null ? void 0 : _b.background) || defaultBackground;
6221
+ this.element.style.zIndex = "10001";
6222
+ this.backgroundBlur = document.createElement("div");
6223
+ this.backgroundBlur.id = "loading-screen-blur";
6224
+ this.backgroundBlur.style.position = "absolute";
6225
+ this.backgroundBlur.style.top = "0";
6226
+ this.backgroundBlur.style.left = "0";
6227
+ this.backgroundBlur.style.width = "100%";
6228
+ this.backgroundBlur.style.height = "100%";
6229
+ this.backgroundBlur.style.display = "flex";
6230
+ if ((_c = this.config) == null ? void 0 : _c.backgroundBlurAmount) {
6231
+ this.backgroundBlur.style.backdropFilter = `blur(${this.config.backgroundBlurAmount}px)`;
6232
+ }
6233
+ this.element.append(this.backgroundBlur);
6234
+ if ((_d = this.config) == null ? void 0 : _d.backgroundImageUrl) {
6235
+ this.element.style.backgroundImage = `url(${this.config.backgroundImageUrl})`;
6236
+ this.element.style.backgroundPosition = "center";
6237
+ this.element.style.backgroundSize = "cover";
6238
+ }
6239
+ if ((_e = this.config) == null ? void 0 : _e.overlayLayers) {
6240
+ const logLoadError = (imageUrl) => {
6241
+ console.error(`Failed to load overlay image: ${imageUrl}`);
6242
+ };
6243
+ for (const layer of this.config.overlayLayers) {
6244
+ const overlayLayer = document.createElement("div");
6245
+ overlayLayer.style.position = "absolute";
6246
+ overlayLayer.style.background = `url(${layer.overlayImageUrl}) no-repeat`;
6247
+ overlayLayer.style.backgroundSize = "contain";
6248
+ const anchor = layer.overlayAnchor;
6249
+ const offsetX = ((_f = layer.overlayOffset) == null ? void 0 : _f.x) || 0;
6250
+ const offsetY = ((_g = layer.overlayOffset) == null ? void 0 : _g.y) || 0;
6251
+ if (anchor.includes("top")) {
6252
+ overlayLayer.style.top = `${offsetY}px`;
6253
+ } else if (anchor.includes("bottom")) {
6254
+ overlayLayer.style.bottom = `${offsetY}px`;
6255
+ }
6256
+ if (anchor.includes("left")) {
6257
+ overlayLayer.style.left = `${offsetX}px`;
6258
+ } else if (anchor.includes("right")) {
6259
+ overlayLayer.style.right = `${offsetX}px`;
6260
+ }
6261
+ const image = new Image();
6262
+ image.src = layer.overlayImageUrl;
6263
+ image.onload = () => {
6264
+ const naturalWidth = image.naturalWidth;
6265
+ const naturalHeight = image.naturalHeight;
6266
+ overlayLayer.style.width = `${naturalWidth}px`;
6267
+ overlayLayer.style.height = `${naturalHeight}px`;
6268
+ };
6269
+ image.onerror = () => logLoadError(layer.overlayImageUrl);
6270
+ this.overlayLayers.push(overlayLayer);
6271
+ this.backgroundBlur.append(overlayLayer);
6272
+ }
6273
+ }
6274
+ this.element.style.color = ((_h = this.config) == null ? void 0 : _h.color) || "white";
6275
+ this.loadingBanner = document.createElement("div");
6276
+ this.loadingBanner.style.position = "absolute";
6277
+ this.loadingBanner.style.display = "flex";
6278
+ this.loadingBanner.style.flexDirection = "column";
6279
+ this.loadingBanner.style.left = "0";
6280
+ this.loadingBanner.style.bottom = "0";
6281
+ this.loadingBanner.style.padding = "0";
6282
+ this.loadingBanner.style.width = "100%";
6283
+ this.loadingBanner.style.justifyContent = "flex-end";
6284
+ this.backgroundBlur.append(this.loadingBanner);
6285
+ if ((_i = this.config) == null ? void 0 : _i.title) {
6286
+ this.loadingBannerTitle = document.createElement("div");
6287
+ this.loadingBannerTitle.textContent = this.config.title;
6288
+ this.loadingBannerTitle.style.color = ((_j = this.config) == null ? void 0 : _j.color) || "white";
6289
+ this.loadingBannerTitle.style.paddingLeft = "40px";
6290
+ this.loadingBannerTitle.style.paddingRight = "40px";
6291
+ this.loadingBannerTitle.style.fontSize = "42px";
6292
+ this.loadingBannerTitle.style.fontWeight = "bold";
6293
+ this.loadingBannerTitle.style.fontFamily = "sans-serif";
6294
+ if ((_k = this.config) == null ? void 0 : _k.background) {
6295
+ this.loadingBannerTitle.style.textShadow = `0px 0px 80px ${this.config.background}`;
6296
+ }
6297
+ this.loadingBanner.append(this.loadingBannerTitle);
6298
+ }
6299
+ if ((_l = this.config) == null ? void 0 : _l.subtitle) {
6300
+ this.loadingBannerSubtitle = document.createElement("div");
6301
+ this.loadingBannerSubtitle.style.color = ((_m = this.config) == null ? void 0 : _m.color) || "white";
6302
+ this.loadingBannerSubtitle.style.paddingLeft = "40px";
6303
+ this.loadingBannerSubtitle.style.paddingRight = "40px";
6304
+ this.loadingBannerSubtitle.style.fontSize = "16px";
6305
+ this.loadingBannerSubtitle.style.fontWeight = "400";
6306
+ this.loadingBannerSubtitle.style.fontFamily = "sans-serif";
6307
+ this.loadingBannerSubtitle.style.marginTop = "12px";
6308
+ if ((_n = this.config) == null ? void 0 : _n.background) {
6309
+ this.loadingBannerSubtitle.style.textShadow = `0px 0px 40px ${this.config.background}`;
6310
+ }
6311
+ this.loadingBannerSubtitle.textContent = this.config.subtitle;
6312
+ this.loadingBanner.append(this.loadingBannerSubtitle);
6313
+ }
5954
6314
  this.progressDebugViewHolder = document.createElement("div");
5955
- this.progressDebugViewHolder.style.display = "flex";
6315
+ this.progressDebugViewHolder.style.display = "none";
5956
6316
  this.progressDebugViewHolder.style.position = "absolute";
5957
- this.progressDebugViewHolder.style.maxHeight = "calc(100% - 74px)";
5958
- this.progressDebugViewHolder.style.left = "0";
5959
- this.progressDebugViewHolder.style.bottom = "74px";
5960
- this.progressDebugViewHolder.style.width = "100%";
6317
+ this.progressDebugViewHolder.style.width = "calc(100% - 80px)";
6318
+ this.progressDebugViewHolder.style.maxHeight = "calc(100% - 120px)";
6319
+ this.progressDebugViewHolder.style.left = "40px";
6320
+ this.progressDebugViewHolder.style.bottom = "60px";
6321
+ this.progressDebugViewHolder.style.alignItems = "center";
5961
6322
  this.progressDebugViewHolder.style.justifyContent = "center";
6323
+ this.progressDebugViewHolder.style.zIndex = "10003";
5962
6324
  this.element.append(this.progressDebugViewHolder);
5963
6325
  this.progressDebugView = document.createElement("div");
5964
- this.progressDebugView.style.backgroundColor = "rgba(128, 128, 128, 0.25)";
6326
+ this.progressDebugView.style.backgroundColor = "rgba(128, 128, 128, 0.5)";
5965
6327
  this.progressDebugView.style.border = "1px solid black";
6328
+ this.progressDebugView.style.borderRadius = "7px";
6329
+ this.progressDebugView.style.width = "100%";
5966
6330
  this.progressDebugView.style.maxWidth = "100%";
5967
6331
  this.progressDebugView.style.overflow = "auto";
5968
6332
  this.progressDebugViewHolder.append(this.progressDebugView);
@@ -5971,6 +6335,8 @@ var LoadingScreen = class {
5971
6335
  this.debugCheckbox.checked = false;
5972
6336
  this.debugCheckbox.addEventListener("change", () => {
5973
6337
  this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
6338
+ this.loadingBannerTitle.style.display = this.debugCheckbox.checked ? "none" : "flex";
6339
+ this.loadingBannerSubtitle.style.display = this.debugCheckbox.checked ? "none" : "flex";
5974
6340
  if (this.hasCompleted) {
5975
6341
  this.dispose();
5976
6342
  }
@@ -5989,23 +6355,36 @@ var LoadingScreen = class {
5989
6355
  this.progressDebugView.append(this.progressDebugElement);
5990
6356
  this.progressBarHolder = document.createElement("div");
5991
6357
  this.progressBarHolder.style.display = "flex";
5992
- this.progressBarHolder.style.alignItems = "center";
5993
- this.progressBarHolder.style.justifyContent = "center";
5994
- this.progressBarHolder.style.position = "absolute";
5995
- this.progressBarHolder.style.bottom = "20px";
5996
- this.progressBarHolder.style.left = "0";
6358
+ this.progressBarHolder.style.alignItems = "start";
6359
+ this.progressBarHolder.style.justifyContent = "flex-start";
5997
6360
  this.progressBarHolder.style.width = "100%";
5998
- this.element.append(this.progressBarHolder);
6361
+ this.progressBarHolder.style.marginLeft = "40px";
6362
+ this.progressBarHolder.style.marginBottom = "40px";
6363
+ this.progressBarHolder.style.cursor = "pointer";
6364
+ this.progressBarHolder.style.marginTop = "24px";
6365
+ this.loadingBanner.append(this.progressBarHolder);
5999
6366
  this.progressBarBackground = document.createElement("div");
6000
6367
  this.progressBarBackground.style.position = "relative";
6001
- this.progressBarBackground.style.width = "500px";
6002
- this.progressBarBackground.style.maxWidth = "80%";
6003
- this.progressBarBackground.style.backgroundColor = "gray";
6004
- this.progressBarBackground.style.height = "50px";
6005
- this.progressBarBackground.style.lineHeight = "50px";
6006
- this.progressBarBackground.style.borderRadius = "25px";
6007
- this.progressBarBackground.style.border = "2px solid white";
6368
+ this.progressBarBackground.style.width = "80%";
6369
+ this.progressBarBackground.style.maxWidth = "400px";
6370
+ this.progressBarBackground.style.minWidth = "240px";
6371
+ this.progressBarBackground.style.backgroundColor = "rgba(32,32,32, 0.25)";
6372
+ this.progressBarBackground.style.backdropFilter = "blur(4px)";
6373
+ this.progressBarBackground.style.height = "16px";
6374
+ this.progressBarBackground.style.lineHeight = "16px";
6375
+ this.progressBarBackground.style.borderRadius = "16px";
6008
6376
  this.progressBarBackground.style.overflow = "hidden";
6377
+ this.progressBarBackground.addEventListener("click", () => {
6378
+ const display = this.progressDebugViewHolder.style.display;
6379
+ if (display === "none") {
6380
+ this.progressDebugViewHolder.style.display = "flex";
6381
+ } else {
6382
+ this.progressDebugViewHolder.style.display = "none";
6383
+ this.debugCheckbox.checked = false;
6384
+ this.progressDebugElement.style.display = this.debugCheckbox.checked ? "block" : "none";
6385
+ this.loadingBannerTitle.style.display = this.debugCheckbox.checked ? "none" : "flex";
6386
+ }
6387
+ });
6009
6388
  this.progressBarHolder.append(this.progressBarBackground);
6010
6389
  this.progressBar = document.createElement("div");
6011
6390
  this.progressBar.style.position = "absolute";
@@ -6013,7 +6392,8 @@ var LoadingScreen = class {
6013
6392
  this.progressBar.style.left = "0";
6014
6393
  this.progressBar.style.width = "0";
6015
6394
  this.progressBar.style.height = "100%";
6016
- this.progressBar.style.backgroundColor = "#0050a4";
6395
+ this.progressBar.style.pointerEvents = "none";
6396
+ this.progressBar.style.backgroundColor = ((_o = this.config) == null ? void 0 : _o.color) || "#0050a4";
6017
6397
  this.progressBarBackground.append(this.progressBar);
6018
6398
  this.loadingStatusText = document.createElement("div");
6019
6399
  this.loadingStatusText.style.position = "absolute";
@@ -6021,11 +6401,14 @@ var LoadingScreen = class {
6021
6401
  this.loadingStatusText.style.left = "0";
6022
6402
  this.loadingStatusText.style.width = "100%";
6023
6403
  this.loadingStatusText.style.height = "100%";
6024
- this.loadingStatusText.style.color = "white";
6404
+ this.loadingStatusText.style.color = "rgba(200,200,200,0.9)";
6405
+ this.loadingStatusText.style.fontSize = "10px";
6025
6406
  this.loadingStatusText.style.textAlign = "center";
6026
6407
  this.loadingStatusText.style.verticalAlign = "middle";
6408
+ this.loadingStatusText.style.mixBlendMode = "difference";
6027
6409
  this.loadingStatusText.style.fontFamily = "sans-serif";
6028
6410
  this.loadingStatusText.style.fontWeight = "bold";
6411
+ this.loadingStatusText.style.userSelect = "none";
6029
6412
  this.loadingStatusText.textContent = "Loading...";
6030
6413
  this.progressBarBackground.append(this.loadingStatusText);
6031
6414
  this.loadingCallback = () => {
@@ -6040,7 +6423,7 @@ var LoadingScreen = class {
6040
6423
  this.loadingStatusText.textContent = "Completed";
6041
6424
  this.progressBar.style.width = "100%";
6042
6425
  } else {
6043
- this.loadingStatusText.textContent = `Loading... ${(loadingRatio * 100).toFixed(2)}%`;
6426
+ this.loadingStatusText.textContent = `${(loadingRatio * 100).toFixed(2)}%`;
6044
6427
  this.progressBar.style.width = `${loadingRatio * 100}%`;
6045
6428
  }
6046
6429
  this.progressDebugElement.textContent = LoadingProgressManager2.LoadingProgressSummaryToString(
@@ -6100,6 +6483,7 @@ export {
6100
6483
  Composer,
6101
6484
  ErrorScreen,
6102
6485
  GroundPlane,
6486
+ Key,
6103
6487
  KeyInputManager,
6104
6488
  LoadingScreen,
6105
6489
  MMLCompositionScene,