@mml-io/3d-web-client-core 0.0.0-experimental-aaef76d-20230925 → 0.0.0-experimental-87d19dc-20231016

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
@@ -41,6 +41,47 @@ var remap = (value, minValue, maxValue, minScaledValue, maxScaledValue) => {
41
41
  return minScaledValue + (maxScaledValue - minScaledValue) * (value - minValue) / (maxValue - minValue);
42
42
  };
43
43
 
44
+ // src/input/EventHandlerCollection.ts
45
+ var EventHandlerCollection = class _EventHandlerCollection {
46
+ constructor() {
47
+ this.eventsByTarget = /* @__PURE__ */ new Map();
48
+ }
49
+ add(target, key, listener, options) {
50
+ target.addEventListener(key, listener, options);
51
+ let existingTarget = this.eventsByTarget.get(target);
52
+ if (existingTarget === void 0) {
53
+ existingTarget = /* @__PURE__ */ new Map();
54
+ this.eventsByTarget.set(target, existingTarget);
55
+ }
56
+ let existingKey = existingTarget.get(key);
57
+ if (existingKey === void 0) {
58
+ existingKey = /* @__PURE__ */ new Set();
59
+ existingTarget.set(key, existingKey);
60
+ }
61
+ existingKey.add(listener);
62
+ return this;
63
+ }
64
+ clear() {
65
+ this.eventsByTarget.forEach((keyMap, target) => {
66
+ keyMap.forEach((listenerSet, key) => {
67
+ listenerSet.forEach((listenerFunc) => {
68
+ target.removeEventListener(key, listenerFunc);
69
+ });
70
+ });
71
+ });
72
+ this.eventsByTarget.clear();
73
+ }
74
+ static create(initial) {
75
+ const instance = new _EventHandlerCollection();
76
+ if (initial !== void 0) {
77
+ initial.forEach(([target, key, listenerFunc, options]) => {
78
+ instance.add(target, key, listenerFunc, options);
79
+ });
80
+ }
81
+ return instance;
82
+ }
83
+ };
84
+
44
85
  // src/tweakpane/tweakPaneActivity.ts
45
86
  var isTweakpaneActive = false;
46
87
  function setTweakpaneActive(status) {
@@ -52,7 +93,7 @@ function getTweakpaneActive() {
52
93
 
53
94
  // src/camera/CameraManager.ts
54
95
  var CameraManager = class {
55
- constructor(collisionsManager) {
96
+ constructor(targetElement, collisionsManager, initialPhi = Math.PI / 2, initialTheta = -Math.PI / 2) {
56
97
  this.collisionsManager = collisionsManager;
57
98
  this.initialDistance = 3.3;
58
99
  this.minDistance = 0.1;
@@ -68,42 +109,38 @@ var CameraManager = class {
68
109
  this.targetDistance = this.initialDistance;
69
110
  this.distance = this.initialDistance;
70
111
  this.desiredDistance = this.initialDistance;
71
- this.targetPhi = Math.PI / 2;
72
- this.phi = Math.PI / 2;
73
- this.targetTheta = -Math.PI / 2;
74
- this.theta = -Math.PI / 2;
75
112
  this.dragging = false;
76
113
  this.target = new Vector32(0, 1.55, 0);
77
114
  this.hadTarget = false;
115
+ this.phi = initialPhi;
116
+ this.targetPhi = initialPhi;
117
+ this.theta = initialTheta;
118
+ this.targetTheta = initialTheta;
78
119
  this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
79
120
  this.camera.position.set(0, 1.4, -this.initialDistance);
80
121
  this.rayCaster = new Raycaster();
81
- document.addEventListener("mousedown", this.onMouseDown.bind(this));
82
- document.addEventListener("mouseup", this.onMouseUp.bind(this));
83
- document.addEventListener("mousemove", this.onMouseMove.bind(this));
84
- document.addEventListener("wheel", this.onMouseWheel.bind(this));
85
- window.addEventListener("resize", this.onResize.bind(this));
86
- }
87
- onResize() {
88
- const width = window.innerWidth;
89
- const height = window.innerHeight;
90
- this.camera.aspect = width / height;
91
- this.camera.updateProjectionMatrix();
92
- }
93
- onMouseDown(_event) {
122
+ this.eventHandlerCollection = EventHandlerCollection.create([
123
+ [targetElement, "mousedown", this.onMouseDown.bind(this)],
124
+ [document, "mouseup", this.onMouseUp.bind(this)],
125
+ [document, "mousemove", this.onMouseMove.bind(this)],
126
+ [targetElement, "wheel", this.onMouseWheel.bind(this)]
127
+ ]);
128
+ }
129
+ onMouseDown() {
94
130
  this.dragging = true;
95
131
  }
96
132
  onMouseUp(_event) {
97
133
  this.dragging = false;
98
134
  }
99
135
  onMouseMove(event) {
100
- if (!this.dragging || getTweakpaneActive() === true)
136
+ if (!this.dragging || getTweakpaneActive())
101
137
  return;
102
138
  if (this.targetTheta === null || this.targetPhi === null)
103
139
  return;
104
140
  this.targetTheta += event.movementX * 0.01;
105
141
  this.targetPhi -= event.movementY * 0.01;
106
142
  this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
143
+ event.preventDefault();
107
144
  }
108
145
  onMouseWheel(event) {
109
146
  const scrollAmount = event.deltaY * 1e-3;
@@ -113,6 +150,7 @@ var CameraManager = class {
113
150
  Math.min(this.maxDistance, this.targetDistance)
114
151
  );
115
152
  this.desiredDistance = this.targetDistance;
153
+ event.preventDefault();
116
154
  }
117
155
  setTarget(target) {
118
156
  this.target.copy(target);
@@ -148,6 +186,9 @@ var CameraManager = class {
148
186
  this.targetDistance += (this.desiredDistance - this.targetDistance) * this.dampingFactor * 4;
149
187
  }
150
188
  }
189
+ dispose() {
190
+ this.eventHandlerCollection.clear();
191
+ }
151
192
  update() {
152
193
  if (this.target === null)
153
194
  return;
@@ -181,11 +222,11 @@ import { Color as Color3, Vector3 as Vector35 } from "three";
181
222
 
182
223
  // src/character/CharacterModel.ts
183
224
  import {
184
- AnimationClip as AnimationClip2,
225
+ AnimationClip,
185
226
  AnimationMixer,
186
227
  LoopRepeat,
187
228
  MeshStandardMaterial,
188
- Object3D as Object3D2
229
+ Object3D
189
230
  } from "three";
190
231
 
191
232
  // src/character/CharacterMaterial.ts
@@ -560,126 +601,11 @@ var AnimationState = /* @__PURE__ */ ((AnimationState2) => {
560
601
  return AnimationState2;
561
602
  })(AnimationState || {});
562
603
 
563
- // src/character/ModelLoader.ts
564
- import { LoadingManager } from "three";
565
- import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
566
- var CachedGLTFLoader = class extends ThreeGLTFLoader {
567
- constructor(manager) {
568
- super(manager);
569
- this.blobCache = /* @__PURE__ */ new Map();
570
- }
571
- setBlobUrl(originalUrl, blobUrl) {
572
- this.blobCache.set(originalUrl, blobUrl);
573
- }
574
- getBlobUrl(originalUrl) {
575
- return this.blobCache.get(originalUrl);
576
- }
577
- load(url, onLoad, onProgress, onError) {
578
- const blobUrl = this.getBlobUrl(url);
579
- if (blobUrl) {
580
- console.log(`Loading cached ${url.split("/").pop()}`);
581
- super.load(blobUrl, onLoad, onProgress, onError);
582
- } else {
583
- super.load(url, onLoad, onProgress, onError);
584
- }
585
- }
586
- };
587
- var LRUCache = class {
588
- constructor(maxSize = 100) {
589
- this.maxSize = maxSize;
590
- this.cache = /* @__PURE__ */ new Map();
591
- }
592
- get(key) {
593
- const item = this.cache.get(key);
594
- if (item) {
595
- this.cache.delete(key);
596
- this.cache.set(key, item);
597
- }
598
- return item;
599
- }
600
- set(key, value) {
601
- if (this.cache.size >= this.maxSize) {
602
- const oldestKey = this.cache.keys().next().value;
603
- this.cache.delete(oldestKey);
604
- }
605
- this.cache.set(key, value);
606
- }
607
- };
608
- var _ModelLoader = class _ModelLoader {
609
- constructor(maxCacheSize = 100) {
610
- this.ongoingLoads = /* @__PURE__ */ new Map();
611
- this.loadingManager = new LoadingManager();
612
- this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
613
- this.modelCache = new LRUCache(maxCacheSize);
614
- }
615
- /* TODO: decide between below lazy initialization or eager on this file's bottom export */
616
- static getInstance() {
617
- if (!_ModelLoader.instance) {
618
- _ModelLoader.instance = new _ModelLoader();
619
- }
620
- return _ModelLoader.instance;
621
- }
622
- async load(fileUrl, fileType) {
623
- const cachedModel = this.modelCache.get(fileUrl);
624
- if (cachedModel) {
625
- const blobURL = URL.createObjectURL(cachedModel.blob);
626
- this.gltfLoader.setBlobUrl(fileUrl, blobURL);
627
- return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
628
- } else {
629
- console.log(`Loading ${fileUrl} from server`);
630
- const ongoingLoad = this.ongoingLoads.get(fileUrl);
631
- if (ongoingLoad)
632
- return ongoingLoad;
633
- const loadPromise = fetch(fileUrl).then((response) => response.blob()).then((blob) => {
634
- const originalExtension = fileUrl.split(".").pop() || "";
635
- this.modelCache.set(fileUrl, { blob, originalExtension });
636
- const blobURL = URL.createObjectURL(blob);
637
- this.ongoingLoads.delete(fileUrl);
638
- return this.loadFromUrl(blobURL, fileType, originalExtension);
639
- });
640
- this.ongoingLoads.set(fileUrl, loadPromise);
641
- return loadPromise;
642
- }
643
- }
644
- async loadFromUrl(url, fileType, extension) {
645
- if (["gltf", "glb"].includes(extension)) {
646
- return new Promise((resolve, reject) => {
647
- this.gltfLoader.load(
648
- url,
649
- (object) => {
650
- if (fileType === "model") {
651
- resolve(object.scene);
652
- } else if (fileType === "animation") {
653
- resolve(object.animations[0]);
654
- } else {
655
- const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
656
- console.error(error);
657
- reject(error);
658
- }
659
- },
660
- void 0,
661
- (error) => {
662
- console.error(`Error loading GL(B|TF) from ${url}: ${error}`);
663
- reject(error);
664
- }
665
- );
666
- });
667
- } else {
668
- console.error(`Error: can't recognize ${url} extension: ${extension}`);
669
- }
670
- }
671
- };
672
- _ModelLoader.instance = null;
673
- var ModelLoader = _ModelLoader;
674
- var MODEL_LOADER = ModelLoader.getInstance();
675
- var ModelLoader_default = MODEL_LOADER;
676
-
677
604
  // src/character/CharacterModel.ts
678
605
  var CharacterModel = class {
679
- constructor(characterDescription) {
606
+ constructor(characterDescription, characterModelLoader) {
680
607
  this.characterDescription = characterDescription;
681
- /* TODO: pick between below eager instantiation or ModelLoader.getInstance() lazy one */
682
- this.modelLoader = ModelLoader_default;
608
+ this.characterModelLoader = characterModelLoader;
683
609
  this.mesh = null;
684
610
  this.material = new CharacterMaterial();
685
611
  this.headBone = null;
@@ -757,9 +683,9 @@ var CharacterModel = class {
757
683
  const scale = this.characterDescription.modelScale;
758
684
  const extension = mainMeshUrl.split(".").pop();
759
685
  const name = mainMeshUrl.split("/").pop().replace(`.${extension}`, "");
760
- const mainMesh = await this.modelLoader.load(mainMeshUrl, "model");
686
+ const mainMesh = await this.characterModelLoader.load(mainMeshUrl, "model");
761
687
  if (typeof mainMesh !== "undefined") {
762
- this.mesh = new Object3D2();
688
+ this.mesh = new Object3D();
763
689
  const model = mainMesh;
764
690
  model.position.set(0, -0.4, 0);
765
691
  this.mesh.add(model);
@@ -771,8 +697,8 @@ var CharacterModel = class {
771
697
  async setAnimationFromFile(animationFileUrl, animationType) {
772
698
  return new Promise(async (resolve, reject) => {
773
699
  this.initAnimationMixer();
774
- const animation = await this.modelLoader.load(animationFileUrl, "animation");
775
- if (typeof animation !== "undefined" && animation instanceof AnimationClip2) {
700
+ const animation = await this.characterModelLoader.load(animationFileUrl, "animation");
701
+ if (typeof animation !== "undefined" && animation instanceof AnimationClip) {
776
702
  this.animations[animationType] = this.animationMixer.clipAction(animation);
777
703
  this.animations[animationType].stop();
778
704
  if (animationType === 0 /* idle */) {
@@ -1304,7 +1230,6 @@ var LocalController = class {
1304
1230
  this.characterVelocity.y = deltaTime * this.gravity;
1305
1231
  }
1306
1232
  } else if (this.jump && this.coyoteTime) {
1307
- console.log("coyoteJump");
1308
1233
  this.characterVelocity.y = this.jumpForce;
1309
1234
  this.canJump = false;
1310
1235
  } else {
@@ -1394,8 +1319,9 @@ var LocalController = class {
1394
1319
 
1395
1320
  // src/character/Character.ts
1396
1321
  var Character = class {
1397
- constructor(characterDescription, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager, composer) {
1322
+ constructor(characterDescription, characterModelLoader, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager, composer) {
1398
1323
  this.characterDescription = characterDescription;
1324
+ this.characterModelLoader = characterModelLoader;
1399
1325
  this.id = id;
1400
1326
  this.isLocal = isLocal;
1401
1327
  this.modelLoadedCallback = modelLoadedCallback;
@@ -1414,7 +1340,7 @@ var Character = class {
1414
1340
  this.load();
1415
1341
  }
1416
1342
  async load() {
1417
- this.model = new CharacterModel(this.characterDescription);
1343
+ this.model = new CharacterModel(this.characterDescription, this.characterModelLoader);
1418
1344
  await this.model.init();
1419
1345
  if (this.tooltip === null) {
1420
1346
  this.tooltip = new CharacterTooltip(this.model.mesh);
@@ -1461,22 +1387,22 @@ var Character = class {
1461
1387
  };
1462
1388
 
1463
1389
  // src/character/CharacterManager.ts
1464
- import { Group, Vector3 as Vector37 } from "three";
1390
+ import { Euler, Group, Quaternion as Quaternion4, Vector3 as Vector37 } from "three";
1465
1391
 
1466
1392
  // src/character/RemoteController.ts
1467
1393
  import {
1468
1394
  AnimationMixer as AnimationMixer2,
1469
- Object3D as Object3D5,
1395
+ Object3D as Object3D4,
1470
1396
  Quaternion as Quaternion3,
1471
1397
  Vector3 as Vector36
1472
1398
  } from "three";
1473
1399
  var RemoteController = class {
1474
- constructor(character, id) {
1400
+ constructor(character, characterModelLoader, id) {
1475
1401
  this.character = character;
1402
+ this.characterModelLoader = characterModelLoader;
1476
1403
  this.id = id;
1477
- this.modelLoader = ModelLoader_default;
1478
1404
  this.characterModel = null;
1479
- this.animationMixer = new AnimationMixer2(new Object3D5());
1405
+ this.animationMixer = new AnimationMixer2(new Object3D4());
1480
1406
  this.animations = /* @__PURE__ */ new Map();
1481
1407
  this.currentAnimation = 0 /* idle */;
1482
1408
  this.characterModel = this.character.model.mesh;
@@ -1497,7 +1423,7 @@ var RemoteController = class {
1497
1423
  this.animationMixer.update(deltaTime);
1498
1424
  }
1499
1425
  async setAnimationFromFile(animationType, fileName) {
1500
- const animation = await this.modelLoader.load(fileName, "animation");
1426
+ const animation = await this.characterModelLoader.load(fileName, "animation");
1501
1427
  const animationAction = this.animationMixer.clipAction(animation);
1502
1428
  this.animations.set(animationType, animationAction);
1503
1429
  if (animationType === 0 /* idle */) {
@@ -1550,8 +1476,9 @@ function decodeCharacterAndCamera(hash, character, camera) {
1550
1476
  camera.quaternion.fromArray(values.slice(10, 14));
1551
1477
  }
1552
1478
  var CharacterManager = class {
1553
- constructor(composer, collisionsManager, cameraManager, timeManager, inputManager, clientStates, sendUpdate) {
1479
+ constructor(composer, characterModelLoader, collisionsManager, cameraManager, timeManager, inputManager, clientStates, sendUpdate) {
1554
1480
  this.composer = composer;
1481
+ this.characterModelLoader = characterModelLoader;
1555
1482
  this.collisionsManager = collisionsManager;
1556
1483
  this.cameraManager = cameraManager;
1557
1484
  this.timeManager = timeManager;
@@ -1581,11 +1508,12 @@ var CharacterManager = class {
1581
1508
  the mesh loading async (would allow us to show a nameplate where a remote
1582
1509
  user is before the asset loads).
1583
1510
  */
1584
- spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector37()) {
1511
+ spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector37(), spawnRotation = new Euler()) {
1585
1512
  this.characterDescription = characterDescription;
1586
1513
  const characterLoadingPromise = new Promise((resolve) => {
1587
1514
  const character = new Character(
1588
1515
  characterDescription,
1516
+ this.characterModelLoader,
1589
1517
  id,
1590
1518
  isLocal,
1591
1519
  () => {
@@ -1597,9 +1525,12 @@ var CharacterManager = class {
1597
1525
  this.cameraManager.camera
1598
1526
  );
1599
1527
  } else {
1600
- spawnPosition = getSpawnPositionInsideCircle(3, 30, id, 0.4);
1528
+ spawnPosition = spawnPosition || getSpawnPositionInsideCircle(3, 30, id, 0.4);
1601
1529
  character.model.mesh.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1530
+ character.model.mesh.rotation.set(spawnRotation.x, spawnRotation.y, spawnRotation.z);
1531
+ character.position.set(spawnPosition.x, spawnPosition.y, spawnPosition.z);
1602
1532
  character.model.mesh.updateMatrixWorld();
1533
+ const quaternion = new Quaternion4().setFromEuler(character.model.mesh.rotation);
1603
1534
  this.sendUpdate({
1604
1535
  id,
1605
1536
  position: {
@@ -1607,7 +1538,7 @@ var CharacterManager = class {
1607
1538
  y: spawnPosition.y,
1608
1539
  z: spawnPosition.z
1609
1540
  },
1610
- rotation: { quaternionY: 0, quaternionW: 1 },
1541
+ rotation: { quaternionY: quaternion.y, quaternionW: quaternion.w },
1611
1542
  state: 0 /* idle */
1612
1543
  });
1613
1544
  }
@@ -1624,7 +1555,7 @@ var CharacterManager = class {
1624
1555
  (_e = this.character.tooltip) == null ? void 0 : _e.setText(`${id}`);
1625
1556
  } else {
1626
1557
  this.remoteCharacters.set(id, character);
1627
- const remoteController = new RemoteController(character, id);
1558
+ const remoteController = new RemoteController(character, this.characterModelLoader, id);
1628
1559
  remoteController.setAnimationFromFile(
1629
1560
  0 /* idle */,
1630
1561
  characterDescription.idleAnimationFileUrl
@@ -1747,19 +1678,137 @@ var CharacterManager = class {
1747
1678
  }
1748
1679
  };
1749
1680
 
1681
+ // src/character/CharacterModelLoader.ts
1682
+ import { LoadingManager } from "three";
1683
+ import { GLTFLoader as ThreeGLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
1684
+ var CachedGLTFLoader = class extends ThreeGLTFLoader {
1685
+ constructor(manager) {
1686
+ super(manager);
1687
+ this.blobCache = /* @__PURE__ */ new Map();
1688
+ }
1689
+ setBlobUrl(originalUrl, blobUrl) {
1690
+ this.blobCache.set(originalUrl, blobUrl);
1691
+ }
1692
+ getBlobUrl(originalUrl) {
1693
+ return this.blobCache.get(originalUrl);
1694
+ }
1695
+ load(url, onLoad, onProgress, onError) {
1696
+ const blobUrl = this.getBlobUrl(url);
1697
+ if (blobUrl) {
1698
+ console.log(`Loading cached ${url.split("/").pop()}`);
1699
+ super.load(blobUrl, onLoad, onProgress, onError);
1700
+ } else {
1701
+ super.load(url, onLoad, onProgress, onError);
1702
+ }
1703
+ }
1704
+ };
1705
+ var LRUCache = class {
1706
+ constructor(maxSize = 100) {
1707
+ this.maxSize = maxSize;
1708
+ this.cache = /* @__PURE__ */ new Map();
1709
+ }
1710
+ get(key) {
1711
+ const item = this.cache.get(key);
1712
+ if (item) {
1713
+ this.cache.delete(key);
1714
+ this.cache.set(key, item);
1715
+ }
1716
+ return item;
1717
+ }
1718
+ set(key, value) {
1719
+ if (this.cache.size >= this.maxSize) {
1720
+ const oldestKey = this.cache.keys().next().value;
1721
+ this.cache.delete(oldestKey);
1722
+ }
1723
+ this.cache.set(key, value);
1724
+ }
1725
+ };
1726
+ var _CharacterModelLoader = class _CharacterModelLoader {
1727
+ constructor(maxCacheSize = 100) {
1728
+ this.ongoingLoads = /* @__PURE__ */ new Map();
1729
+ this.loadingManager = new LoadingManager();
1730
+ this.gltfLoader = new CachedGLTFLoader(this.loadingManager);
1731
+ this.modelCache = new LRUCache(maxCacheSize);
1732
+ }
1733
+ /* TODO: decide between below lazy initialization or eager on this file's bottom export */
1734
+ static getInstance() {
1735
+ if (!_CharacterModelLoader.instance) {
1736
+ _CharacterModelLoader.instance = new _CharacterModelLoader();
1737
+ }
1738
+ return _CharacterModelLoader.instance;
1739
+ }
1740
+ async load(fileUrl, fileType) {
1741
+ const cachedModel = this.modelCache.get(fileUrl);
1742
+ if (cachedModel) {
1743
+ const blobURL = URL.createObjectURL(cachedModel.blob);
1744
+ this.gltfLoader.setBlobUrl(fileUrl, blobURL);
1745
+ return this.loadFromUrl(fileUrl, fileType, cachedModel.originalExtension);
1746
+ } else {
1747
+ console.log(`Loading ${fileUrl} from server`);
1748
+ const ongoingLoad = this.ongoingLoads.get(fileUrl);
1749
+ if (ongoingLoad)
1750
+ return ongoingLoad;
1751
+ const loadPromise = fetch(fileUrl).then((response) => response.blob()).then((blob) => {
1752
+ const originalExtension = fileUrl.split(".").pop() || "";
1753
+ this.modelCache.set(fileUrl, { blob, originalExtension });
1754
+ const blobURL = URL.createObjectURL(blob);
1755
+ this.ongoingLoads.delete(fileUrl);
1756
+ return this.loadFromUrl(blobURL, fileType, originalExtension);
1757
+ });
1758
+ this.ongoingLoads.set(fileUrl, loadPromise);
1759
+ return loadPromise;
1760
+ }
1761
+ }
1762
+ async loadFromUrl(url, fileType, extension) {
1763
+ if (["gltf", "glb"].includes(extension)) {
1764
+ return new Promise((resolve, reject) => {
1765
+ this.gltfLoader.load(
1766
+ url,
1767
+ (object) => {
1768
+ if (fileType === "model") {
1769
+ resolve(object.scene);
1770
+ } else if (fileType === "animation") {
1771
+ resolve(object.animations[0]);
1772
+ } else {
1773
+ const error = `Trying to load unknown ${fileType} type of element from file ${url}`;
1774
+ console.error(error);
1775
+ reject(error);
1776
+ }
1777
+ },
1778
+ void 0,
1779
+ (error) => {
1780
+ console.error(`Error loading GL(B|TF) from ${url}: ${error}`);
1781
+ reject(error);
1782
+ }
1783
+ );
1784
+ });
1785
+ } else {
1786
+ console.error(`Error: can't recognize ${url} extension: ${extension}`);
1787
+ }
1788
+ }
1789
+ };
1790
+ _CharacterModelLoader.instance = null;
1791
+ var CharacterModelLoader = _CharacterModelLoader;
1792
+ var MODEL_LOADER = CharacterModelLoader.getInstance();
1793
+
1750
1794
  // src/input/KeyInputManager.ts
1751
1795
  var KeyInputManager = class {
1752
- constructor() {
1796
+ constructor(shouldCaptureKeyPress = () => true) {
1797
+ this.shouldCaptureKeyPress = shouldCaptureKeyPress;
1753
1798
  this.keys = /* @__PURE__ */ new Map();
1754
- document.addEventListener("keydown", this.onKeyDown.bind(this));
1755
- document.addEventListener("keyup", this.onKeyUp.bind(this));
1756
- window.addEventListener("blur", this.handleUnfocus.bind(this));
1799
+ this.eventHandlerCollection = new EventHandlerCollection();
1800
+ this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
1801
+ this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
1802
+ this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this));
1757
1803
  }
1758
1804
  handleUnfocus(_event) {
1759
1805
  this.keys.clear();
1760
1806
  }
1761
1807
  onKeyDown(event) {
1762
- this.keys.set(event.key.toLowerCase(), true);
1808
+ if (this.shouldCaptureKeyPress()) {
1809
+ this.keys.set(event.key.toLowerCase(), true);
1810
+ event.preventDefault();
1811
+ }
1763
1812
  }
1764
1813
  onKeyUp(event) {
1765
1814
  this.keys.set(event.key.toLowerCase(), false);
@@ -1795,9 +1844,7 @@ var KeyInputManager = class {
1795
1844
  return this.isKeyPressed("w") && this.isKeyPressed("s") || this.isKeyPressed("a") && this.isKeyPressed("d");
1796
1845
  }
1797
1846
  dispose() {
1798
- document.removeEventListener("keydown", this.onKeyDown.bind(this));
1799
- document.removeEventListener("keyup", this.onKeyDown.bind(this));
1800
- window.removeEventListener("blur", this.handleUnfocus.bind(this));
1847
+ this.eventHandlerCollection.clear();
1801
1848
  }
1802
1849
  };
1803
1850
 
@@ -1805,23 +1852,25 @@ var KeyInputManager = class {
1805
1852
  import {
1806
1853
  InteractionManager,
1807
1854
  MMLClickTrigger,
1808
- PromptManager,
1809
- registerCustomElementsToWindow,
1810
- setGlobalMScene
1855
+ PromptManager
1811
1856
  } from "mml-web";
1812
1857
  import { Group as Group2 } from "three";
1813
1858
  var MMLCompositionScene = class {
1814
- constructor(renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation, documentAddresses) {
1859
+ constructor(targetElement, renderer, scene, camera, audioListener, collisionsManager, getUserPositionAndRotation) {
1815
1860
  this.renderer = renderer;
1816
1861
  this.scene = scene;
1817
1862
  this.camera = camera;
1818
1863
  this.audioListener = audioListener;
1819
1864
  this.collisionsManager = collisionsManager;
1820
1865
  this.getUserPositionAndRotation = getUserPositionAndRotation;
1821
- this.debug = false;
1822
1866
  this.group = new Group2();
1823
- this.promptManager = PromptManager.init(document.body);
1824
- const { interactionListener } = InteractionManager.init(document.body, this.camera, this.scene);
1867
+ this.promptManager = PromptManager.init(targetElement);
1868
+ const { interactionListener, interactionManager } = InteractionManager.init(
1869
+ targetElement,
1870
+ this.camera,
1871
+ this.scene
1872
+ );
1873
+ this.interactionManager = interactionManager;
1825
1874
  this.interactionListener = interactionListener;
1826
1875
  this.mmlScene = {
1827
1876
  getAudioListener: () => this.audioListener,
@@ -1852,55 +1901,65 @@ var MMLCompositionScene = class {
1852
1901
  this.promptManager.prompt(promptProps, callback);
1853
1902
  }
1854
1903
  };
1855
- setGlobalMScene(this.mmlScene);
1856
- registerCustomElementsToWindow(window);
1857
- this.clickTrigger = MMLClickTrigger.init(document, this.mmlScene);
1858
- if (this.debug) {
1859
- console.log(this.clickTrigger);
1860
- }
1861
- for (const address of documentAddresses) {
1862
- const frameElement = document.createElement("m-frame");
1863
- frameElement.setAttribute("src", address);
1864
- document.body.appendChild(frameElement);
1865
- }
1904
+ this.clickTrigger = MMLClickTrigger.init(targetElement, this.mmlScene);
1905
+ }
1906
+ dispose() {
1907
+ this.promptManager.dispose();
1908
+ this.clickTrigger.dispose();
1909
+ this.interactionManager.dispose();
1866
1910
  }
1867
1911
  };
1868
1912
 
1869
- // src/rendering/composer.ts
1870
- import { N8AOPostPass } from "n8ao";
1871
- import {
1872
- EffectComposer as EffectComposer2,
1873
- RenderPass,
1874
- EffectPass as EffectPass2,
1875
- FXAAEffect,
1876
- ShaderPass,
1877
- BloomEffect,
1878
- SSAOEffect as SSAOEffect2,
1879
- BlendFunction as BlendFunction2,
1880
- TextureEffect,
1881
- ToneMappingEffect,
1882
- SMAAEffect,
1883
- SMAAPreset,
1884
- EdgeDetectionMode,
1885
- PredicationMode,
1886
- NormalPass as NormalPass2
1887
- } from "postprocessing";
1888
- import {
1889
- AmbientLight,
1890
- Color as Color6,
1891
- Fog,
1892
- HalfFloatType,
1893
- LinearSRGBColorSpace,
1894
- LoadingManager as LoadingManager2,
1895
- PMREMGenerator,
1896
- Scene as Scene3,
1897
- Vector2 as Vector22,
1898
- WebGLRenderer as WebGLRenderer2
1899
- } from "three";
1900
- import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
1913
+ // src/tweakpane/TweakPane.ts
1914
+ import * as EssentialsPlugin from "@tweakpane/plugin-essentials";
1915
+ import { Pane } from "tweakpane";
1901
1916
 
1902
- // src/sun/Sun.ts
1903
- import { CameraHelper, Color as Color4, DirectionalLight, Group as Group3, OrthographicCamera, Vector3 as Vector38 } from "three";
1917
+ // src/tweakpane/blades/bcsFolder.ts
1918
+ var bcsValues = {
1919
+ brightness: 0,
1920
+ contrast: 1.25,
1921
+ saturation: 1
1922
+ };
1923
+ var bcsOptions = {
1924
+ brightness: {
1925
+ amount: { min: -1, max: 1, step: 0.01 }
1926
+ },
1927
+ contrast: {
1928
+ amount: { min: 0, max: 2, step: 0.01 }
1929
+ },
1930
+ saturation: {
1931
+ amount: { min: 0, max: 2, step: 0.01 }
1932
+ }
1933
+ };
1934
+ var BrightnessContrastSaturationFolder = class {
1935
+ constructor(parentFolder, expand = false) {
1936
+ this.folder = parentFolder.addFolder({
1937
+ title: "brightness / contrast / sat",
1938
+ expanded: expand
1939
+ });
1940
+ this.folder.addBinding(bcsValues, "brightness", bcsOptions.brightness.amount);
1941
+ this.folder.addBinding(bcsValues, "contrast", bcsOptions.contrast.amount);
1942
+ this.folder.addBinding(bcsValues, "saturation", bcsOptions.saturation.amount);
1943
+ }
1944
+ setupChangeEvent(brightnessContrastSaturation) {
1945
+ this.folder.on("change", (e) => {
1946
+ const target = e.target.key;
1947
+ if (!target)
1948
+ return;
1949
+ switch (target) {
1950
+ case "brightness":
1951
+ brightnessContrastSaturation.uniforms.brightness.value = e.value;
1952
+ break;
1953
+ case "contrast":
1954
+ brightnessContrastSaturation.uniforms.contrast.value = e.value;
1955
+ break;
1956
+ case "saturation":
1957
+ brightnessContrastSaturation.uniforms.saturation.value = e.value;
1958
+ break;
1959
+ }
1960
+ });
1961
+ }
1962
+ };
1904
1963
 
1905
1964
  // src/tweakpane/blades/environmentFolder.ts
1906
1965
  var sunValues = {
@@ -2057,135 +2116,6 @@ var EnvironmentFolder = class {
2057
2116
  }
2058
2117
  };
2059
2118
 
2060
- // src/sun/Sun.ts
2061
- var Sun = class extends Group3 {
2062
- constructor() {
2063
- super();
2064
- this.debug = false;
2065
- this.sunOffset = new Vector38(
2066
- 39 * (Math.PI / 180),
2067
- 50 * (Math.PI / 180),
2068
- 100
2069
- );
2070
- this.shadowResolution = 8192;
2071
- this.shadowCamFrustum = 50;
2072
- this.camHelper = null;
2073
- this.target = null;
2074
- this.shadowCamera = new OrthographicCamera(
2075
- -this.shadowCamFrustum,
2076
- this.shadowCamFrustum,
2077
- this.shadowCamFrustum,
2078
- -this.shadowCamFrustum,
2079
- 0.1,
2080
- 200
2081
- );
2082
- if (this.debug === true) {
2083
- this.camHelper = new CameraHelper(this.shadowCamera);
2084
- }
2085
- this.directionalLight = new DirectionalLight(16777215, 0.5);
2086
- this.directionalLight.shadow.normalBias = 0.05;
2087
- this.directionalLight.shadow.radius = 1.5;
2088
- this.directionalLight.shadow.camera = this.shadowCamera;
2089
- this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
2090
- this.directionalLight.castShadow = true;
2091
- this.setColor();
2092
- this.updateCharacterPosition(new Vector38(0, 0, 0));
2093
- this.add(this.directionalLight);
2094
- if (this.debug === true && this.camHelper instanceof CameraHelper) {
2095
- this.add(this.camHelper);
2096
- }
2097
- }
2098
- updateCharacterPosition(position) {
2099
- if (!position)
2100
- return;
2101
- this.target = position;
2102
- this.setSunPosition(this.sunOffset.x, this.sunOffset.y);
2103
- }
2104
- setAzimuthalAngle(angle) {
2105
- if (this.sunOffset)
2106
- this.sunOffset.x = angle;
2107
- if (this.target)
2108
- this.updateCharacterPosition(this.target);
2109
- }
2110
- setPolarAngle(angle) {
2111
- if (this.sunOffset)
2112
- this.sunOffset.y = angle;
2113
- if (this.target)
2114
- this.updateCharacterPosition(this.target);
2115
- }
2116
- setIntensity(intensity) {
2117
- this.directionalLight.intensity = intensity;
2118
- }
2119
- setColor() {
2120
- this.directionalLight.color = new Color4().setRGB(
2121
- sunValues.sunColor.r,
2122
- sunValues.sunColor.g,
2123
- sunValues.sunColor.b
2124
- );
2125
- }
2126
- setSunPosition(azimuthalAngle, polarAngle) {
2127
- if (!this.target)
2128
- return;
2129
- const distance = this.sunOffset.z;
2130
- const sphericalPosition = new Vector38(
2131
- distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
2132
- distance * Math.cos(polarAngle),
2133
- distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
2134
- );
2135
- const newSunPosition = this.target.clone().add(sphericalPosition);
2136
- this.directionalLight.position.set(newSunPosition.x, newSunPosition.y, newSunPosition.z);
2137
- this.directionalLight.target.position.copy(this.target.clone());
2138
- this.directionalLight.target.updateMatrixWorld();
2139
- }
2140
- };
2141
-
2142
- // src/tweakpane/blades/bcsFolder.ts
2143
- var bcsValues = {
2144
- brightness: 0,
2145
- contrast: 1.25,
2146
- saturation: 1
2147
- };
2148
- var bcsOptions = {
2149
- brightness: {
2150
- amount: { min: -1, max: 1, step: 0.01 }
2151
- },
2152
- contrast: {
2153
- amount: { min: 0, max: 2, step: 0.01 }
2154
- },
2155
- saturation: {
2156
- amount: { min: 0, max: 2, step: 0.01 }
2157
- }
2158
- };
2159
- var BrightnessContrastSaturationFolder = class {
2160
- constructor(parentFolder, expand = false) {
2161
- this.folder = parentFolder.addFolder({
2162
- title: "brightness / contrast / sat",
2163
- expanded: expand
2164
- });
2165
- this.folder.addBinding(bcsValues, "brightness", bcsOptions.brightness.amount);
2166
- this.folder.addBinding(bcsValues, "contrast", bcsOptions.contrast.amount);
2167
- this.folder.addBinding(bcsValues, "saturation", bcsOptions.saturation.amount);
2168
- }
2169
- setupChangeEvent(brightnessContrastSaturation) {
2170
- this.folder.on("change", (e) => {
2171
- const target = e.target.key;
2172
- if (!target)
2173
- return;
2174
- switch (target) {
2175
- case "brightness":
2176
- brightnessContrastSaturation.uniforms.brightness.value = e.value;
2177
- break;
2178
- case "contrast":
2179
- brightnessContrastSaturation.uniforms.contrast.value = e.value;
2180
- break;
2181
- case "saturation":
2182
- brightnessContrastSaturation.uniforms.saturation.value = e.value;
2183
- break;
2184
- }
2185
- });
2186
- }
2187
- };
2188
-
2189
2119
  // src/tweakpane/blades/postExtrasFolder.ts
2190
2120
  var extrasValues = {
2191
2121
  grain: 0.055,
@@ -2310,9 +2240,52 @@ var RendererFolder = class {
2310
2240
  }
2311
2241
  };
2312
2242
 
2243
+ // src/tweakpane/blades/rendererStatsFolder.ts
2244
+ var RendererStatsFolder = class {
2245
+ constructor(parentFolder, expanded = true) {
2246
+ this.statsData = {
2247
+ triangles: "0",
2248
+ geometries: "0",
2249
+ textures: "0",
2250
+ shaders: "0",
2251
+ postPasses: "0",
2252
+ drawCalls: "0",
2253
+ rawDeltaTime: "0",
2254
+ deltaTime: "0",
2255
+ FPS: "0"
2256
+ };
2257
+ this.folder = parentFolder.addFolder({ title: "renderStats", expanded });
2258
+ this.performance = this.folder.addFolder({ title: "performance", expanded: true });
2259
+ this.defails = this.folder.addFolder({ title: "pipeline details", expanded: false });
2260
+ this.folder.addBlade({ view: "separator" });
2261
+ this.performance.addBinding(this.statsData, "FPS", { readonly: true });
2262
+ this.performance.addBinding(this.statsData, "deltaTime", { readonly: true });
2263
+ this.performance.addBinding(this.statsData, "rawDeltaTime", { readonly: true });
2264
+ this.defails.addBinding(this.statsData, "triangles", { readonly: true });
2265
+ this.defails.addBinding(this.statsData, "geometries", { readonly: true });
2266
+ this.defails.addBinding(this.statsData, "textures", { readonly: true });
2267
+ this.defails.addBinding(this.statsData, "shaders", { readonly: true });
2268
+ this.defails.addBinding(this.statsData, "postPasses", { readonly: true });
2269
+ this.defails.addBinding(this.statsData, "drawCalls", { readonly: true });
2270
+ }
2271
+ update(renderer, composer, timeManager) {
2272
+ const { geometries, textures } = renderer.info.memory;
2273
+ const { triangles, calls } = renderer.info.render;
2274
+ this.statsData.triangles = triangles.toString();
2275
+ this.statsData.geometries = geometries.toString();
2276
+ this.statsData.textures = textures.toString();
2277
+ this.statsData.shaders = renderer.info.programs.length.toString();
2278
+ this.statsData.postPasses = composer.passes.length.toString();
2279
+ this.statsData.drawCalls = calls.toString();
2280
+ this.statsData.rawDeltaTime = (Math.round(timeManager.rawDeltaTime * 1e5) / 1e5).toString();
2281
+ this.statsData.deltaTime = (Math.round(timeManager.deltaTime * 1e5) / 1e5).toString();
2282
+ this.statsData.FPS = timeManager.fps.toString();
2283
+ }
2284
+ };
2285
+
2313
2286
  // src/tweakpane/blades/ssaoFolder.ts
2314
2287
  import { BlendFunction } from "postprocessing";
2315
- import { Color as Color5 } from "three";
2288
+ import { Color as Color4 } from "three";
2316
2289
  var ppssaoValues = {
2317
2290
  enabled: false,
2318
2291
  blendFunction: BlendFunction.MULTIPLY,
@@ -2504,7 +2477,7 @@ var SSAOFolder = class {
2504
2477
  }
2505
2478
  case "color": {
2506
2479
  const value = e.value;
2507
- ppssaoEffect.color = new Color5().setRGB(value.r, value.g, value.b);
2480
+ ppssaoEffect.color = new Color4().setRGB(value.r, value.g, value.b);
2508
2481
  break;
2509
2482
  }
2510
2483
  default: {
@@ -2544,7 +2517,7 @@ var SSAOFolder = class {
2544
2517
  break;
2545
2518
  case "color":
2546
2519
  const value = e.value;
2547
- n8aopass.configuration.color = new Color5().setRGB(value.r, value.g, value.b);
2520
+ n8aopass.configuration.color = new Color4().setRGB(value.r, value.g, value.b);
2548
2521
  break;
2549
2522
  default:
2550
2523
  break;
@@ -2637,53 +2610,6 @@ var ToneMappingFolder = class {
2637
2610
  }
2638
2611
  };
2639
2612
 
2640
- // src/tweakpane/TweakPane.ts
2641
- import * as EssentialsPlugin from "@tweakpane/plugin-essentials";
2642
- import { Pane } from "tweakpane";
2643
-
2644
- // src/tweakpane/blades/rendererStatsFolder.ts
2645
- var RendererStatsFolder = class {
2646
- constructor(parentFolder, expanded = true) {
2647
- this.statsData = {
2648
- triangles: "0",
2649
- geometries: "0",
2650
- textures: "0",
2651
- shaders: "0",
2652
- postPasses: "0",
2653
- drawCalls: "0",
2654
- rawDeltaTime: "0",
2655
- deltaTime: "0",
2656
- FPS: "0"
2657
- };
2658
- this.folder = parentFolder.addFolder({ title: "renderStats", expanded });
2659
- this.performance = this.folder.addFolder({ title: "performance", expanded: true });
2660
- this.defails = this.folder.addFolder({ title: "pipeline details", expanded: false });
2661
- this.folder.addBlade({ view: "separator" });
2662
- this.performance.addBinding(this.statsData, "FPS", { readonly: true });
2663
- this.performance.addBinding(this.statsData, "deltaTime", { readonly: true });
2664
- this.performance.addBinding(this.statsData, "rawDeltaTime", { readonly: true });
2665
- this.defails.addBinding(this.statsData, "triangles", { readonly: true });
2666
- this.defails.addBinding(this.statsData, "geometries", { readonly: true });
2667
- this.defails.addBinding(this.statsData, "textures", { readonly: true });
2668
- this.defails.addBinding(this.statsData, "shaders", { readonly: true });
2669
- this.defails.addBinding(this.statsData, "postPasses", { readonly: true });
2670
- this.defails.addBinding(this.statsData, "drawCalls", { readonly: true });
2671
- }
2672
- update(renderer, composer, timeManager) {
2673
- const { geometries, textures } = renderer.info.memory;
2674
- const { triangles, calls } = renderer.info.render;
2675
- this.statsData.triangles = triangles.toString();
2676
- this.statsData.geometries = geometries.toString();
2677
- this.statsData.textures = textures.toString();
2678
- this.statsData.shaders = renderer.info.programs.length.toString();
2679
- this.statsData.postPasses = composer.passes.length.toString();
2680
- this.statsData.drawCalls = calls.toString();
2681
- this.statsData.rawDeltaTime = (Math.round(timeManager.rawDeltaTime * 1e5) / 1e5).toString();
2682
- this.statsData.deltaTime = (Math.round(timeManager.deltaTime * 1e5) / 1e5).toString();
2683
- this.statsData.FPS = timeManager.fps.toString();
2684
- }
2685
- };
2686
-
2687
2613
  // src/tweakpane/tweakPaneStyle.ts
2688
2614
  var tweakPaneStyle = `
2689
2615
  :root {
@@ -2882,6 +2808,122 @@ var TweakPane = class {
2882
2808
  }
2883
2809
  };
2884
2810
 
2811
+ // src/rendering/composer.ts
2812
+ import { N8AOPostPass } from "n8ao";
2813
+ import {
2814
+ EffectComposer as EffectComposer2,
2815
+ RenderPass,
2816
+ EffectPass as EffectPass2,
2817
+ FXAAEffect,
2818
+ ShaderPass,
2819
+ BloomEffect,
2820
+ SSAOEffect as SSAOEffect2,
2821
+ BlendFunction as BlendFunction2,
2822
+ TextureEffect,
2823
+ ToneMappingEffect,
2824
+ SMAAEffect,
2825
+ SMAAPreset,
2826
+ EdgeDetectionMode,
2827
+ PredicationMode,
2828
+ NormalPass as NormalPass2
2829
+ } from "postprocessing";
2830
+ import {
2831
+ AmbientLight,
2832
+ Color as Color6,
2833
+ Fog,
2834
+ HalfFloatType,
2835
+ LinearSRGBColorSpace,
2836
+ LoadingManager as LoadingManager2,
2837
+ PMREMGenerator,
2838
+ Scene as Scene3,
2839
+ Vector2 as Vector22,
2840
+ WebGLRenderer as WebGLRenderer2
2841
+ } from "three";
2842
+ import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
2843
+
2844
+ // src/sun/Sun.ts
2845
+ import { CameraHelper, Color as Color5, DirectionalLight, Group as Group3, OrthographicCamera, Vector3 as Vector38 } from "three";
2846
+ var Sun = class extends Group3 {
2847
+ constructor() {
2848
+ super();
2849
+ this.debug = false;
2850
+ this.sunOffset = new Vector38(
2851
+ 39 * (Math.PI / 180),
2852
+ 50 * (Math.PI / 180),
2853
+ 100
2854
+ );
2855
+ this.shadowResolution = 8192;
2856
+ this.shadowCamFrustum = 50;
2857
+ this.camHelper = null;
2858
+ this.target = null;
2859
+ this.shadowCamera = new OrthographicCamera(
2860
+ -this.shadowCamFrustum,
2861
+ this.shadowCamFrustum,
2862
+ this.shadowCamFrustum,
2863
+ -this.shadowCamFrustum,
2864
+ 0.1,
2865
+ 200
2866
+ );
2867
+ if (this.debug === true) {
2868
+ this.camHelper = new CameraHelper(this.shadowCamera);
2869
+ }
2870
+ this.directionalLight = new DirectionalLight(16777215, 0.5);
2871
+ this.directionalLight.shadow.normalBias = 0.05;
2872
+ this.directionalLight.shadow.radius = 1.5;
2873
+ this.directionalLight.shadow.camera = this.shadowCamera;
2874
+ this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
2875
+ this.directionalLight.castShadow = true;
2876
+ this.setColor();
2877
+ this.updateCharacterPosition(new Vector38(0, 0, 0));
2878
+ this.add(this.directionalLight);
2879
+ if (this.debug === true && this.camHelper instanceof CameraHelper) {
2880
+ this.add(this.camHelper);
2881
+ }
2882
+ }
2883
+ updateCharacterPosition(position) {
2884
+ if (!position)
2885
+ return;
2886
+ this.target = position;
2887
+ this.setSunPosition(this.sunOffset.x, this.sunOffset.y);
2888
+ }
2889
+ setAzimuthalAngle(angle) {
2890
+ if (this.sunOffset)
2891
+ this.sunOffset.x = angle;
2892
+ if (this.target)
2893
+ this.updateCharacterPosition(this.target);
2894
+ }
2895
+ setPolarAngle(angle) {
2896
+ if (this.sunOffset)
2897
+ this.sunOffset.y = angle;
2898
+ if (this.target)
2899
+ this.updateCharacterPosition(this.target);
2900
+ }
2901
+ setIntensity(intensity) {
2902
+ this.directionalLight.intensity = intensity;
2903
+ }
2904
+ setColor() {
2905
+ this.directionalLight.color = new Color5().setRGB(
2906
+ sunValues.sunColor.r,
2907
+ sunValues.sunColor.g,
2908
+ sunValues.sunColor.b
2909
+ );
2910
+ }
2911
+ setSunPosition(azimuthalAngle, polarAngle) {
2912
+ if (!this.target)
2913
+ return;
2914
+ const distance = this.sunOffset.z;
2915
+ const sphericalPosition = new Vector38(
2916
+ distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
2917
+ distance * Math.cos(polarAngle),
2918
+ distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
2919
+ );
2920
+ const newSunPosition = this.target.clone().add(sphericalPosition);
2921
+ this.directionalLight.position.set(newSunPosition.x, newSunPosition.y, newSunPosition.z);
2922
+ this.directionalLight.target.position.copy(this.target.clone());
2923
+ this.directionalLight.target.updateMatrixWorld();
2924
+ }
2925
+ };
2926
+
2885
2927
  // src/rendering/post-effects/bright-contrast-sat.ts
2886
2928
  import { ShaderMaterial, Uniform } from "three";
2887
2929
 
@@ -3029,8 +3071,8 @@ var GaussGrainEffect = new ShaderMaterial2({
3029
3071
  // src/rendering/composer.ts
3030
3072
  var Composer = class {
3031
3073
  constructor(scene, camera, spawnSun = false) {
3032
- this.width = window.innerWidth;
3033
- this.height = window.innerHeight;
3074
+ this.width = 1;
3075
+ this.height = 1;
3034
3076
  this.resolution = new Vector22(this.width, this.height);
3035
3077
  this.isEnvHDRI = false;
3036
3078
  this.bcs = BrightnessContrastSaturation;
@@ -3055,11 +3097,9 @@ var Composer = class {
3055
3097
  this.renderer.toneMappingExposure = rendererValues.exposure;
3056
3098
  this.setAmbientLight();
3057
3099
  this.setFog();
3058
- document.body.appendChild(this.renderer.domElement);
3059
- this.composer = new EffectComposer2(this.renderer, {
3100
+ this.effectComposer = new EffectComposer2(this.renderer, {
3060
3101
  frameBufferType: HalfFloatType
3061
3102
  });
3062
- this.tweakPane = new TweakPane(this.renderer, this.scene, this.composer);
3063
3103
  this.renderPass = new RenderPass(this.scene, this.camera);
3064
3104
  this.normalPass = new NormalPass2(this.scene, this.camera);
3065
3105
  this.normalPass.enabled = ppssaoValues.enabled;
@@ -3128,26 +3168,33 @@ var Composer = class {
3128
3168
  this.bcs.uniforms.saturation.value = bcsValues.saturation;
3129
3169
  this.gaussGrainPass = new ShaderPass(this.gaussGrainEffect, "tDiffuse");
3130
3170
  this.smaaPass = new EffectPass2(this.camera, this.smaaEffect);
3131
- this.composer.addPass(this.renderPass);
3171
+ this.effectComposer.addPass(this.renderPass);
3132
3172
  if (ppssaoValues.enabled) {
3133
- this.composer.addPass(this.normalPass);
3134
- this.composer.addPass(this.ppssaoPass);
3173
+ this.effectComposer.addPass(this.normalPass);
3174
+ this.effectComposer.addPass(this.ppssaoPass);
3135
3175
  }
3136
3176
  if (n8ssaoValues.enabled) {
3137
- this.composer.addPass(this.n8aopass);
3138
- }
3139
- this.composer.addPass(this.fxaaPass);
3140
- this.composer.addPass(this.smaaPass);
3141
- this.composer.addPass(this.bloomPass);
3142
- this.composer.addPass(this.toneMappingPass);
3143
- this.composer.addPass(this.bcsPass);
3144
- this.composer.addPass(this.gaussGrainPass);
3177
+ this.effectComposer.addPass(this.n8aopass);
3178
+ }
3179
+ this.effectComposer.addPass(this.fxaaPass);
3180
+ this.effectComposer.addPass(this.smaaPass);
3181
+ this.effectComposer.addPass(this.bloomPass);
3182
+ this.effectComposer.addPass(this.toneMappingPass);
3183
+ this.effectComposer.addPass(this.bcsPass);
3184
+ this.effectComposer.addPass(this.gaussGrainPass);
3145
3185
  if (this.spawnSun === true) {
3146
3186
  this.sun = new Sun();
3147
3187
  this.scene.add(this.sun);
3148
3188
  }
3149
- this.tweakPane.setupRenderPane(
3150
- this.composer,
3189
+ this.resizeListener = () => {
3190
+ this.fitContainer();
3191
+ };
3192
+ window.addEventListener("resize", this.resizeListener, false);
3193
+ this.fitContainer();
3194
+ }
3195
+ setupTweakPane(tweakPane) {
3196
+ tweakPane.setupRenderPane(
3197
+ this.effectComposer,
3151
3198
  this.normalPass,
3152
3199
  this.ppssaoEffect,
3153
3200
  this.ppssaoPass,
@@ -3163,14 +3210,32 @@ var Composer = class {
3163
3210
  this.setAmbientLight.bind(this),
3164
3211
  this.setFog.bind(this)
3165
3212
  );
3166
- window.addEventListener("resize", () => this.updateProjection());
3167
- this.updateProjection();
3168
3213
  }
3169
- updateProjection() {
3170
- this.width = window.innerWidth;
3171
- this.height = innerHeight;
3172
- this.resolution = new Vector22(this.width, this.height);
3173
- this.composer.setSize(this.width, this.height);
3214
+ dispose() {
3215
+ window.removeEventListener("resize", this.resizeListener);
3216
+ }
3217
+ fitContainer() {
3218
+ if (!this) {
3219
+ console.error("Composer not initialized");
3220
+ return;
3221
+ }
3222
+ const parentElement = this.renderer.domElement.parentNode;
3223
+ if (!parentElement) {
3224
+ return;
3225
+ }
3226
+ this.width = parentElement.clientWidth;
3227
+ this.height = parentElement.clientHeight;
3228
+ this.camera.aspect = this.width / this.height;
3229
+ this.camera.updateProjectionMatrix();
3230
+ this.renderer.setPixelRatio(window.devicePixelRatio);
3231
+ this.resolution.set(
3232
+ this.width * window.devicePixelRatio,
3233
+ this.height * window.devicePixelRatio
3234
+ );
3235
+ this.effectComposer.setSize(
3236
+ this.width / window.devicePixelRatio,
3237
+ this.height / window.devicePixelRatio
3238
+ );
3174
3239
  this.renderPass.setSize(this.width, this.height);
3175
3240
  if (ppssaoValues.enabled) {
3176
3241
  this.normalPass.setSize(this.width, this.height);
@@ -3187,20 +3252,14 @@ var Composer = class {
3187
3252
  this.gaussGrainPass.setSize(this.width, this.height);
3188
3253
  this.renderer.setSize(this.width, this.height);
3189
3254
  }
3190
- isTweakPaneVisible() {
3191
- return this.tweakPane.guiVisible;
3192
- }
3193
3255
  render(timeManager) {
3194
3256
  this.renderer.info.reset();
3195
3257
  this.normalPass.texture.needsUpdate = true;
3196
3258
  this.gaussGrainEffect.uniforms.resolution.value = this.resolution;
3197
3259
  this.gaussGrainEffect.uniforms.time.value = timeManager.time;
3198
3260
  this.gaussGrainEffect.uniforms.alpha.value = 1;
3199
- this.composer.render();
3261
+ this.effectComposer.render();
3200
3262
  this.renderer.render(this.postPostScene, this.camera);
3201
- if (this.tweakPane.guiVisible) {
3202
- this.tweakPane.updateStats(timeManager);
3203
- }
3204
3263
  }
3205
3264
  useHDRI(url, fromFile = false) {
3206
3265
  if (this.isEnvHDRI && fromFile === false || !this.renderer)
@@ -3332,7 +3391,7 @@ import {
3332
3391
  Box3,
3333
3392
  Color as Color7,
3334
3393
  DoubleSide,
3335
- Euler,
3394
+ Euler as Euler2,
3336
3395
  Group as Group4,
3337
3396
  Line3 as Line32,
3338
3397
  Matrix4 as Matrix42,
@@ -3354,7 +3413,7 @@ var CollisionsManager = class {
3354
3413
  this.tempMatrix = new Matrix42();
3355
3414
  this.tempMatrix2 = new Matrix42();
3356
3415
  this.tempBox = new Box3();
3357
- this.tempEuler = new Euler();
3416
+ this.tempEuler = new Euler2();
3358
3417
  this.tempSegment = new Line32();
3359
3418
  this.tempSegment2 = new Line32();
3360
3419
  this.collisionMeshState = /* @__PURE__ */ new Map();
@@ -3547,11 +3606,13 @@ export {
3547
3606
  AnimationState,
3548
3607
  CameraManager,
3549
3608
  CharacterManager,
3609
+ CharacterModelLoader,
3550
3610
  CollisionsManager,
3551
3611
  Composer,
3552
3612
  KeyInputManager,
3553
3613
  MMLCompositionScene,
3554
3614
  Sun,
3555
- TimeManager
3615
+ TimeManager,
3616
+ TweakPane
3556
3617
  };
3557
3618
  //# sourceMappingURL=index.js.map