@mml-io/3d-web-client-core 0.0.0-experimental-e594824-20230925 → 0.0.0-experimental-aaef76d-20230925

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.
@@ -2,8 +2,10 @@ import { Color, Vector3 } from "three";
2
2
  import { CameraManager } from "../camera/CameraManager";
3
3
  import { CollisionsManager } from "../collisions/CollisionsManager";
4
4
  import { KeyInputManager } from "../input/KeyInputManager";
5
+ import { Composer } from "../rendering/composer";
5
6
  import { TimeManager } from "../time/TimeManager";
6
7
  import { CharacterModel } from "./CharacterModel";
8
+ import { CharacterSpeakingIndicator } from "./CharacterSpeakingIndicator";
7
9
  import { CharacterTooltip } from "./CharacterTooltip";
8
10
  import { LocalController } from "./LocalController";
9
11
  export type CharacterDescription = {
@@ -23,13 +25,15 @@ export declare class Character {
23
25
  private readonly keyInputManager;
24
26
  private readonly cameraManager;
25
27
  private readonly timeManager;
28
+ private readonly composer;
26
29
  controller: LocalController | null;
27
30
  name: string | null;
28
31
  model: CharacterModel | null;
29
32
  color: Color;
30
33
  position: Vector3;
31
34
  tooltip: CharacterTooltip | null;
32
- constructor(characterDescription: CharacterDescription, id: number, isLocal: boolean, modelLoadedCallback: () => void, collisionsManager: CollisionsManager, keyInputManager: KeyInputManager, cameraManager: CameraManager, timeManager: TimeManager);
35
+ speakingIndicator: CharacterSpeakingIndicator | null;
36
+ constructor(characterDescription: CharacterDescription, id: number, isLocal: boolean, modelLoadedCallback: () => void, collisionsManager: CollisionsManager, keyInputManager: KeyInputManager, cameraManager: CameraManager, timeManager: TimeManager, composer: Composer);
33
37
  private load;
34
38
  update(time: number): void;
35
39
  }
@@ -3,11 +3,13 @@ import { Group, Vector3 } from "three";
3
3
  import { CameraManager } from "../camera/CameraManager";
4
4
  import { CollisionsManager } from "../collisions/CollisionsManager";
5
5
  import { KeyInputManager } from "../input/KeyInputManager";
6
+ import { Composer } from "../rendering/composer";
6
7
  import { TimeManager } from "../time/TimeManager";
7
8
  import { Character, CharacterDescription } from "./Character";
8
9
  import { CharacterState } from "./CharacterState";
9
10
  import { RemoteController } from "./RemoteController";
10
11
  export declare class CharacterManager {
12
+ private readonly composer;
11
13
  private readonly collisionsManager;
12
14
  private readonly cameraManager;
13
15
  private readonly timeManager;
@@ -15,6 +17,7 @@ export declare class CharacterManager {
15
17
  private readonly clientStates;
16
18
  private readonly sendUpdate;
17
19
  private updateLocationHash;
20
+ private id;
18
21
  loadingCharacters: Map<number, Promise<Character>>;
19
22
  remoteCharacters: Map<number, Character>;
20
23
  remoteCharacterControllers: Map<number, RemoteController>;
@@ -22,10 +25,12 @@ export declare class CharacterManager {
22
25
  character: Character | null;
23
26
  private cameraOffsetTarget;
24
27
  private cameraOffset;
28
+ private speakingCharacters;
25
29
  readonly group: Group;
26
- constructor(collisionsManager: CollisionsManager, cameraManager: CameraManager, timeManager: TimeManager, inputManager: KeyInputManager, clientStates: Map<number, CharacterState>, sendUpdate: (update: CharacterState) => void);
30
+ constructor(composer: Composer, collisionsManager: CollisionsManager, cameraManager: CameraManager, timeManager: TimeManager, inputManager: KeyInputManager, clientStates: Map<number, CharacterState>, sendUpdate: (update: CharacterState) => void);
27
31
  spawnCharacter(characterDescription: CharacterDescription, id: number, isLocal?: boolean, spawnPosition?: Vector3): Promise<Character>;
28
32
  getLocalCharacterPositionAndRotation(): PositionAndRotation;
29
33
  clear(): void;
34
+ setSpeakingCharacter(id: number, value: boolean): void;
30
35
  update(): void;
31
36
  }
@@ -1,4 +1,4 @@
1
- import { AnimationAction, AnimationMixer, Object3D } from "three";
1
+ import { AnimationAction, AnimationMixer, Bone, Object3D } from "three";
2
2
  import { CharacterDescription } from "./Character";
3
3
  import { CharacterMaterial } from "./CharacterMaterial";
4
4
  import { AnimationState } from "./CharacterState";
@@ -7,6 +7,7 @@ export declare class CharacterModel {
7
7
  private modelLoader;
8
8
  mesh: Object3D | null;
9
9
  material: CharacterMaterial;
10
+ headBone: Bone | null;
10
11
  animations: Record<string, AnimationAction>;
11
12
  animationMixer: AnimationMixer | null;
12
13
  currentAnimation: AnimationState;
@@ -0,0 +1,17 @@
1
+ import { Camera, Object3D, Scene, Vector3 } from "three";
2
+ export declare class CharacterSpeakingIndicator {
3
+ private scene;
4
+ private vertexShader;
5
+ private fragmentShader;
6
+ private uniforms;
7
+ private geometry;
8
+ private material;
9
+ private mesh;
10
+ private currentAlpha;
11
+ private targetAlpha;
12
+ constructor(scene: Scene | Object3D);
13
+ setBillboarding(position: Vector3, camera: Camera): void;
14
+ setTime(value: number): void;
15
+ setSpeaking(value: boolean): void;
16
+ dispose(): void;
17
+ }
@@ -1,4 +1,6 @@
1
- import { Vector3 } from "three";
1
+ import { Quaternion, Vector3, Vector4 } from "three";
2
+ export declare const roundToDecimalPlaces: (value: number, decimalPlaces: number) => number;
3
+ export declare const toArray: (origin: Vector3 | Vector4 | Quaternion, precision?: number) => number[];
2
4
  export declare const getSpawnPositionInsideCircle: (radius: number, positions: number, id: number, yPos?: number) => Vector3;
3
5
  export declare const round: (n: number, digits: number) => number;
4
6
  export declare const ease: (target: number, n: number, factor: number) => number;
package/build/index.js CHANGED
@@ -2,7 +2,21 @@
2
2
  import { PerspectiveCamera, Raycaster, Vector3 as Vector32 } from "three";
3
3
 
4
4
  // src/helpers/math-helpers.ts
5
- import { Vector3 } from "three";
5
+ import { Quaternion, Vector3, Vector4 } from "three";
6
+ var roundToDecimalPlaces = (value, decimalPlaces) => {
7
+ const mult = 10 ** decimalPlaces;
8
+ return Math.round(value * mult) / mult;
9
+ };
10
+ var toArray = (origin, precision = 3) => {
11
+ const array = [];
12
+ array[0] = roundToDecimalPlaces(origin.x, precision);
13
+ array[1] = roundToDecimalPlaces(origin.y, precision);
14
+ array[2] = roundToDecimalPlaces(origin.z, precision);
15
+ if (origin instanceof Vector4 || origin instanceof Quaternion) {
16
+ array[3] = roundToDecimalPlaces(origin.w, precision);
17
+ }
18
+ return array;
19
+ };
6
20
  var getSpawnPositionInsideCircle = (radius, positions, id, yPos = 0) => {
7
21
  if (id > 0)
8
22
  id += 3;
@@ -163,7 +177,7 @@ var CameraManager = class {
163
177
  };
164
178
 
165
179
  // src/character/Character.ts
166
- import { Color as Color3, Vector3 as Vector34 } from "three";
180
+ import { Color as Color3, Vector3 as Vector35 } from "three";
167
181
 
168
182
  // src/character/CharacterModel.ts
169
183
  import {
@@ -668,6 +682,7 @@ var CharacterModel = class {
668
682
  this.modelLoader = ModelLoader_default;
669
683
  this.mesh = null;
670
684
  this.material = new CharacterMaterial();
685
+ this.headBone = null;
671
686
  this.animations = {};
672
687
  this.animationMixer = null;
673
688
  this.currentAnimation = 0 /* idle */;
@@ -703,6 +718,9 @@ var CharacterModel = class {
703
718
  if (!this.mesh)
704
719
  return;
705
720
  this.mesh.traverse((child) => {
721
+ if (child.type === "Bone" && child.name === "mixamorigHeadTop_End") {
722
+ this.headBone = child;
723
+ }
706
724
  if (child.type === "SkinnedMesh" && child.name === meshName) {
707
725
  child.material = new MeshStandardMaterial({
708
726
  color: 16711680,
@@ -786,12 +804,104 @@ var CharacterModel = class {
786
804
  }
787
805
  };
788
806
 
807
+ // src/character/CharacterSpeakingIndicator.ts
808
+ import {
809
+ CircleGeometry,
810
+ GLSL3,
811
+ Mesh as Mesh2,
812
+ RawShaderMaterial
813
+ } from "three";
814
+ var CharacterSpeakingIndicator = class {
815
+ constructor(scene) {
816
+ this.scene = scene;
817
+ this.vertexShader = /* glsl */
818
+ `
819
+ in vec3 position;
820
+ in vec2 uv;
821
+ uniform mat4 modelViewMatrix;
822
+ uniform mat4 projectionMatrix;
823
+ out vec2 vUv;
824
+ void main() {
825
+ vUv = uv;
826
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
827
+ }`;
828
+ this.fragmentShader = /* glsl */
829
+ `
830
+ precision highp float;
831
+
832
+ uniform float time;
833
+ uniform float alpha;
834
+ in vec2 vUv;
835
+ out vec4 fragColor;
836
+
837
+ const float size = 1.7;
838
+ const float distribution = 0.03;
839
+ const float speed = 0.2;
840
+ const float overdraw = 3.5;
841
+ const float shapeK = 0.25;
842
+
843
+ float sdHyperbola(vec2 p, float k, float wi) {
844
+ p = abs(p);
845
+ float k2 = k * k;
846
+ float a = p.x + p.y;
847
+ float i = 0.5 * (a - k2 / a) > wi ? -1.0 : 1.0;
848
+ float x = clamp(0.5 * (a - k2 / a), 0.0, wi);
849
+ vec2 q = vec2(x, sqrt(x * x + k2));
850
+ float s = sign(p.x * p.x - p.y * p.y + k2);
851
+ return s * length(p - q);
852
+ }
853
+
854
+ void main(void) {
855
+ vec2 uv = (vUv * 2.0 - 1.0);
856
+ float r = -(uv.x * uv.x + uv.y * uv.y);
857
+ float z = 0.5 + 0.5 * sin((r + time * speed) / distribution);
858
+ float a = clamp(smoothstep(-0.1, 0.2, size - length(uv * 2.0)), 0.0, 0.5);
859
+ float h = clamp(sdHyperbola(uv, shapeK, 1.0), 0.0, 1.0) * overdraw;
860
+ float fragAlpha = clamp(a * h, 0.0, 0.7);
861
+ fragColor = vec4(z * fragAlpha) * alpha;
862
+ }`;
863
+ this.uniforms = {
864
+ time: { value: 0 },
865
+ alpha: { value: 0 }
866
+ };
867
+ this.geometry = new CircleGeometry(0.35, 21);
868
+ this.material = new RawShaderMaterial({
869
+ vertexShader: this.vertexShader,
870
+ fragmentShader: this.fragmentShader,
871
+ uniforms: this.uniforms,
872
+ transparent: true,
873
+ glslVersion: GLSL3
874
+ });
875
+ this.mesh = new Mesh2(this.geometry, this.material);
876
+ this.currentAlpha = 0;
877
+ this.targetAlpha = 0;
878
+ this.scene.add(this.mesh);
879
+ }
880
+ setBillboarding(position, camera) {
881
+ this.mesh.position.set(position.x, position.y - 0.15, position.z);
882
+ this.mesh.lookAt(camera.position);
883
+ }
884
+ setTime(value) {
885
+ this.currentAlpha += ease(this.targetAlpha, this.currentAlpha, 0.06);
886
+ this.uniforms.time.value = value;
887
+ this.uniforms.alpha.value = this.currentAlpha;
888
+ }
889
+ setSpeaking(value) {
890
+ this.targetAlpha = value === true ? 1 : 0;
891
+ }
892
+ dispose() {
893
+ this.scene.remove(this.mesh);
894
+ this.mesh.material.dispose();
895
+ this.mesh.geometry.dispose();
896
+ }
897
+ };
898
+
789
899
  // src/character/CharacterTooltip.ts
790
900
  import {
791
901
  Color as Color2,
792
902
  FrontSide,
793
903
  LinearFilter as LinearFilter2,
794
- Mesh as Mesh2,
904
+ Mesh as Mesh3,
795
905
  MeshBasicMaterial as MeshBasicMaterial2,
796
906
  PlaneGeometry
797
907
  } from "three";
@@ -941,7 +1051,7 @@ var CharacterTooltip = class {
941
1051
  });
942
1052
  this.material.side = FrontSide;
943
1053
  this.geometry = new PlaneGeometry(1, 1, 1, 1);
944
- this.mesh = new Mesh2(this.geometry, this.material);
1054
+ this.mesh = new Mesh3(this.geometry, this.material);
945
1055
  this.mesh.position.set(0, 1.6, 0);
946
1056
  this.mesh.visible = false;
947
1057
  parentModel.add(this.mesh);
@@ -1024,7 +1134,7 @@ var CharacterTooltip = class {
1024
1134
  };
1025
1135
 
1026
1136
  // src/character/LocalController.ts
1027
- import { Line3, Matrix4, Quaternion, Raycaster as Raycaster2, Vector3 as Vector33 } from "three";
1137
+ import { Line3, Matrix4, Quaternion as Quaternion2, Raycaster as Raycaster2, Vector3 as Vector34 } from "three";
1028
1138
  var LocalController = class {
1029
1139
  constructor(model, id, collisionsManager, keyInputManager, cameraManager, timeManager) {
1030
1140
  this.model = model;
@@ -1036,7 +1146,7 @@ var LocalController = class {
1036
1146
  this.collisionDetectionSteps = 15;
1037
1147
  this.capsuleInfo = {
1038
1148
  radius: 0.4,
1039
- segment: new Line3(new Vector33(), new Vector33(0, 1.05, 0))
1149
+ segment: new Line3(new Vector34(), new Vector34(0, 1.05, 0))
1040
1150
  };
1041
1151
  this.maxWalkSpeed = 6;
1042
1152
  this.maxRunSpeed = 8.5;
@@ -1049,15 +1159,15 @@ var LocalController = class {
1049
1159
  this.characterWasOnGround = false;
1050
1160
  this.characterAirborneSince = 0;
1051
1161
  this.currentHeight = 0;
1052
- this.characterVelocity = new Vector33();
1053
- this.vectorUp = new Vector33(0, 1, 0);
1054
- this.vectorDown = new Vector33(0, -1, 0);
1162
+ this.characterVelocity = new Vector34();
1163
+ this.vectorUp = new Vector34(0, 1, 0);
1164
+ this.vectorDown = new Vector34(0, -1, 0);
1055
1165
  this.rotationOffset = 0;
1056
1166
  this.azimuthalAngle = 0;
1057
1167
  this.tempMatrix = new Matrix4();
1058
1168
  this.tempSegment = new Line3();
1059
- this.tempVector = new Vector33();
1060
- this.tempVector2 = new Vector33();
1169
+ this.tempVector = new Vector34();
1170
+ this.tempVector2 = new Vector34();
1061
1171
  this.rayCaster = new Raycaster2();
1062
1172
  this.thirdPersonCamera = null;
1063
1173
  this.speed = 0;
@@ -1145,7 +1255,7 @@ var LocalController = class {
1145
1255
  const camToModelDistance = this.thirdPersonCamera.position.distanceTo(this.model.mesh.position);
1146
1256
  const isCameraFirstPerson = camToModelDistance < 2;
1147
1257
  if (isCameraFirstPerson) {
1148
- const cameraForward = new Vector33(0, 0, 1).applyQuaternion(this.thirdPersonCamera.quaternion);
1258
+ const cameraForward = new Vector34(0, 0, 1).applyQuaternion(this.thirdPersonCamera.quaternion);
1149
1259
  this.azimuthalAngle = Math.atan2(cameraForward.x, cameraForward.z);
1150
1260
  } else {
1151
1261
  this.azimuthalAngle = Math.atan2(
@@ -1166,7 +1276,7 @@ var LocalController = class {
1166
1276
  return;
1167
1277
  this.updateRotationOffset();
1168
1278
  this.updateAzimuthalAngle();
1169
- const rotationQuaternion = new Quaternion();
1279
+ const rotationQuaternion = new Quaternion2();
1170
1280
  rotationQuaternion.setFromAxisAngle(this.vectorUp, this.azimuthalAngle + this.rotationOffset);
1171
1281
  const angularDifference = this.computeAngularDifference(rotationQuaternion);
1172
1282
  const desiredTime = 0.07;
@@ -1204,19 +1314,19 @@ var LocalController = class {
1204
1314
  this.model.mesh.position.addScaledVector(this.characterVelocity, deltaTime);
1205
1315
  this.tempVector.set(0, 0, 0);
1206
1316
  if (this.forward) {
1207
- const forward = new Vector33(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1317
+ const forward = new Vector34(0, 0, -1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1208
1318
  this.tempVector.add(forward);
1209
1319
  }
1210
1320
  if (this.backward) {
1211
- const backward = new Vector33(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1321
+ const backward = new Vector34(0, 0, 1).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1212
1322
  this.tempVector.add(backward);
1213
1323
  }
1214
1324
  if (this.left) {
1215
- const left = new Vector33(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1325
+ const left = new Vector34(-1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1216
1326
  this.tempVector.add(left);
1217
1327
  }
1218
1328
  if (this.right) {
1219
- const right = new Vector33(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1329
+ const right = new Vector34(1, 0, 0).applyAxisAngle(this.vectorUp, this.azimuthalAngle);
1220
1330
  this.tempVector.add(right);
1221
1331
  }
1222
1332
  if (this.tempVector.length() > 0) {
@@ -1253,13 +1363,13 @@ var LocalController = class {
1253
1363
  if (!((_a = this.model) == null ? void 0 : _a.mesh)) {
1254
1364
  this.networkState = {
1255
1365
  id: this.id,
1256
- position: new Vector33(),
1366
+ position: new Vector34(),
1257
1367
  rotation: { quaternionY: 0, quaternionW: 1 },
1258
1368
  state: 0 /* idle */
1259
1369
  };
1260
1370
  } else {
1261
- const characterQuaternion = this.model.mesh.getWorldQuaternion(new Quaternion());
1262
- const positionUpdate = new Vector33(
1371
+ const characterQuaternion = this.model.mesh.getWorldQuaternion(new Quaternion2());
1372
+ const positionUpdate = new Vector34(
1263
1373
  this.model.mesh.position.x,
1264
1374
  this.model.mesh.position.y,
1265
1375
  this.model.mesh.position.z
@@ -1284,7 +1394,7 @@ var LocalController = class {
1284
1394
 
1285
1395
  // src/character/Character.ts
1286
1396
  var Character = class {
1287
- constructor(characterDescription, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager) {
1397
+ constructor(characterDescription, id, isLocal, modelLoadedCallback, collisionsManager, keyInputManager, cameraManager, timeManager, composer) {
1288
1398
  this.characterDescription = characterDescription;
1289
1399
  this.id = id;
1290
1400
  this.isLocal = isLocal;
@@ -1293,12 +1403,14 @@ var Character = class {
1293
1403
  this.keyInputManager = keyInputManager;
1294
1404
  this.cameraManager = cameraManager;
1295
1405
  this.timeManager = timeManager;
1406
+ this.composer = composer;
1296
1407
  this.controller = null;
1297
1408
  this.name = null;
1298
1409
  this.model = null;
1299
1410
  this.color = new Color3();
1300
- this.position = new Vector34();
1411
+ this.position = new Vector35();
1301
1412
  this.tooltip = null;
1413
+ this.speakingIndicator = null;
1302
1414
  this.load();
1303
1415
  }
1304
1416
  async load() {
@@ -1307,6 +1419,9 @@ var Character = class {
1307
1419
  if (this.tooltip === null) {
1308
1420
  this.tooltip = new CharacterTooltip(this.model.mesh);
1309
1421
  }
1422
+ if (this.speakingIndicator === null) {
1423
+ this.speakingIndicator = new CharacterSpeakingIndicator(this.composer.postPostScene);
1424
+ }
1310
1425
  this.color = this.model.material.colorsCube216[this.id];
1311
1426
  if (this.isLocal) {
1312
1427
  this.controller = new LocalController(
@@ -1321,11 +1436,21 @@ var Character = class {
1321
1436
  this.modelLoadedCallback();
1322
1437
  }
1323
1438
  update(time) {
1439
+ var _a;
1324
1440
  if (!this.model)
1325
1441
  return;
1326
1442
  if (this.tooltip) {
1327
1443
  this.tooltip.update(this.cameraManager.camera);
1328
1444
  }
1445
+ if (this.speakingIndicator) {
1446
+ this.speakingIndicator.setTime(time);
1447
+ if (this.model.mesh && this.model.headBone) {
1448
+ this.speakingIndicator.setBillboarding(
1449
+ (_a = this.model.headBone) == null ? void 0 : _a.getWorldPosition(new Vector35()),
1450
+ this.cameraManager.camera
1451
+ );
1452
+ }
1453
+ }
1329
1454
  this.model.mesh.getWorldPosition(this.position);
1330
1455
  if (typeof this.model.material.uniforms.time !== "undefined") {
1331
1456
  this.model.material.uniforms.time.value = time;
@@ -1336,14 +1461,14 @@ var Character = class {
1336
1461
  };
1337
1462
 
1338
1463
  // src/character/CharacterManager.ts
1339
- import { Group, Vector3 as Vector36 } from "three";
1464
+ import { Group, Vector3 as Vector37 } from "three";
1340
1465
 
1341
1466
  // src/character/RemoteController.ts
1342
1467
  import {
1343
1468
  AnimationMixer as AnimationMixer2,
1344
- Object3D as Object3D4,
1345
- Quaternion as Quaternion2,
1346
- Vector3 as Vector35
1469
+ Object3D as Object3D5,
1470
+ Quaternion as Quaternion3,
1471
+ Vector3 as Vector36
1347
1472
  } from "three";
1348
1473
  var RemoteController = class {
1349
1474
  constructor(character, id) {
@@ -1351,7 +1476,7 @@ var RemoteController = class {
1351
1476
  this.id = id;
1352
1477
  this.modelLoader = ModelLoader_default;
1353
1478
  this.characterModel = null;
1354
- this.animationMixer = new AnimationMixer2(new Object3D4());
1479
+ this.animationMixer = new AnimationMixer2(new Object3D5());
1355
1480
  this.animations = /* @__PURE__ */ new Map();
1356
1481
  this.currentAnimation = 0 /* idle */;
1357
1482
  this.characterModel = this.character.model.mesh;
@@ -1399,8 +1524,8 @@ var RemoteController = class {
1399
1524
  if (!this.characterModel)
1400
1525
  return;
1401
1526
  const { position, rotation, state } = clientUpdate;
1402
- this.characterModel.position.lerp(new Vector35(position.x, position.y, position.z), 0.15);
1403
- const rotationQuaternion = new Quaternion2(0, rotation.quaternionY, 0, rotation.quaternionW);
1527
+ this.characterModel.position.lerp(new Vector36(position.x, position.y, position.z), 0.15);
1528
+ const rotationQuaternion = new Quaternion3(0, rotation.quaternionY, 0, rotation.quaternionW);
1404
1529
  this.characterModel.quaternion.slerp(rotationQuaternion, 0.6);
1405
1530
  if (state !== this.currentAnimation) {
1406
1531
  this.transitionToAnimation(state);
@@ -1411,10 +1536,10 @@ var RemoteController = class {
1411
1536
  // src/character/CharacterManager.ts
1412
1537
  function encodeCharacterAndCamera(character, camera) {
1413
1538
  return [
1414
- ...character.position.toArray(),
1415
- ...character.quaternion.toArray(),
1416
- ...camera.position.toArray(),
1417
- ...camera.quaternion.toArray()
1539
+ ...toArray(character.position),
1540
+ ...toArray(character.quaternion),
1541
+ ...toArray(camera.position),
1542
+ ...toArray(camera.quaternion)
1418
1543
  ].join(",");
1419
1544
  }
1420
1545
  function decodeCharacterAndCamera(hash, character, camera) {
@@ -1425,7 +1550,8 @@ function decodeCharacterAndCamera(hash, character, camera) {
1425
1550
  camera.quaternion.fromArray(values.slice(10, 14));
1426
1551
  }
1427
1552
  var CharacterManager = class {
1428
- constructor(collisionsManager, cameraManager, timeManager, inputManager, clientStates, sendUpdate) {
1553
+ constructor(composer, collisionsManager, cameraManager, timeManager, inputManager, clientStates, sendUpdate) {
1554
+ this.composer = composer;
1429
1555
  this.collisionsManager = collisionsManager;
1430
1556
  this.cameraManager = cameraManager;
1431
1557
  this.timeManager = timeManager;
@@ -1438,6 +1564,7 @@ var CharacterManager = class {
1438
1564
  can be trapped).
1439
1565
  */
1440
1566
  this.updateLocationHash = false;
1567
+ this.id = 0;
1441
1568
  this.loadingCharacters = /* @__PURE__ */ new Map();
1442
1569
  this.remoteCharacters = /* @__PURE__ */ new Map();
1443
1570
  this.remoteCharacterControllers = /* @__PURE__ */ new Map();
@@ -1445,6 +1572,7 @@ var CharacterManager = class {
1445
1572
  this.character = null;
1446
1573
  this.cameraOffsetTarget = 0;
1447
1574
  this.cameraOffset = 0;
1575
+ this.speakingCharacters = /* @__PURE__ */ new Map();
1448
1576
  this.group = new Group();
1449
1577
  }
1450
1578
  /* TODO:
@@ -1453,7 +1581,7 @@ var CharacterManager = class {
1453
1581
  the mesh loading async (would allow us to show a nameplate where a remote
1454
1582
  user is before the asset loads).
1455
1583
  */
1456
- spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector36()) {
1584
+ spawnCharacter(characterDescription, id, isLocal = false, spawnPosition = new Vector37()) {
1457
1585
  this.characterDescription = characterDescription;
1458
1586
  const characterLoadingPromise = new Promise((resolve) => {
1459
1587
  const character = new Character(
@@ -1491,6 +1619,7 @@ var CharacterManager = class {
1491
1619
  }
1492
1620
  this.group.add(character.model.mesh);
1493
1621
  if (isLocal) {
1622
+ this.id = id;
1494
1623
  this.character = character;
1495
1624
  (_e = this.character.tooltip) == null ? void 0 : _e.setText(`${id}`);
1496
1625
  } else {
@@ -1525,7 +1654,8 @@ var CharacterManager = class {
1525
1654
  this.collisionsManager,
1526
1655
  this.inputManager,
1527
1656
  this.cameraManager,
1528
- this.timeManager
1657
+ this.timeManager,
1658
+ this.composer
1529
1659
  );
1530
1660
  });
1531
1661
  this.loadingCharacters.set(id, characterLoadingPromise);
@@ -1555,14 +1685,20 @@ var CharacterManager = class {
1555
1685
  }
1556
1686
  this.loadingCharacters.clear();
1557
1687
  }
1688
+ setSpeakingCharacter(id, value) {
1689
+ this.speakingCharacters.set(id, value);
1690
+ }
1558
1691
  update() {
1559
- var _a;
1692
+ var _a, _b, _c, _d;
1560
1693
  if (this.character) {
1561
1694
  this.character.update(this.timeManager.time);
1562
- if ((_a = this.character.model) == null ? void 0 : _a.mesh) {
1695
+ if (this.speakingCharacters.has(this.id)) {
1696
+ (_a = this.character.speakingIndicator) == null ? void 0 : _a.setSpeaking(this.speakingCharacters.get(this.id));
1697
+ }
1698
+ if ((_b = this.character.model) == null ? void 0 : _b.mesh) {
1563
1699
  this.cameraOffsetTarget = this.cameraManager.targetDistance <= 0.4 ? 0.13 : 0;
1564
1700
  this.cameraOffset += ease(this.cameraOffsetTarget, this.cameraOffset, 0.1);
1565
- const targetOffset = new Vector36(0, 1.3, this.cameraOffset);
1701
+ const targetOffset = new Vector37(0, 1.3, this.cameraOffset);
1566
1702
  targetOffset.applyQuaternion(this.character.model.mesh.quaternion);
1567
1703
  this.cameraManager.setTarget(this.character.position.add(targetOffset));
1568
1704
  }
@@ -1573,13 +1709,17 @@ var CharacterManager = class {
1573
1709
  }
1574
1710
  }
1575
1711
  for (const [id, update] of this.clientStates) {
1712
+ if (this.remoteCharacters.has(id) && this.speakingCharacters.has(id)) {
1713
+ const character = this.remoteCharacters.get(id);
1714
+ (_c = character == null ? void 0 : character.speakingIndicator) == null ? void 0 : _c.setSpeaking(this.speakingCharacters.get(id));
1715
+ }
1576
1716
  const { position } = update;
1577
1717
  if (!this.remoteCharacters.has(id) && !this.loadingCharacters.has(id)) {
1578
1718
  this.spawnCharacter(
1579
1719
  this.characterDescription,
1580
1720
  id,
1581
1721
  false,
1582
- new Vector36(position.x, position.y, position.z)
1722
+ new Vector37(position.x, position.y, position.z)
1583
1723
  ).then((_character) => {
1584
1724
  this.loadingCharacters.delete(id);
1585
1725
  });
@@ -1591,6 +1731,7 @@ var CharacterManager = class {
1591
1731
  }
1592
1732
  for (const [id, character] of this.remoteCharacters) {
1593
1733
  if (!this.clientStates.has(id)) {
1734
+ (_d = character.speakingIndicator) == null ? void 0 : _d.dispose();
1594
1735
  this.group.remove(character.model.mesh);
1595
1736
  this.remoteCharacters.delete(id);
1596
1737
  this.remoteCharacterControllers.delete(id);
@@ -1752,13 +1893,14 @@ import {
1752
1893
  LinearSRGBColorSpace,
1753
1894
  LoadingManager as LoadingManager2,
1754
1895
  PMREMGenerator,
1896
+ Scene as Scene3,
1755
1897
  Vector2 as Vector22,
1756
1898
  WebGLRenderer as WebGLRenderer2
1757
1899
  } from "three";
1758
1900
  import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
1759
1901
 
1760
1902
  // src/sun/Sun.ts
1761
- import { CameraHelper, Color as Color4, DirectionalLight, Group as Group3, OrthographicCamera, Vector3 as Vector37 } from "three";
1903
+ import { CameraHelper, Color as Color4, DirectionalLight, Group as Group3, OrthographicCamera, Vector3 as Vector38 } from "three";
1762
1904
 
1763
1905
  // src/tweakpane/blades/environmentFolder.ts
1764
1906
  var sunValues = {
@@ -1920,7 +2062,7 @@ var Sun = class extends Group3 {
1920
2062
  constructor() {
1921
2063
  super();
1922
2064
  this.debug = false;
1923
- this.sunOffset = new Vector37(
2065
+ this.sunOffset = new Vector38(
1924
2066
  39 * (Math.PI / 180),
1925
2067
  50 * (Math.PI / 180),
1926
2068
  100
@@ -1947,7 +2089,7 @@ var Sun = class extends Group3 {
1947
2089
  this.directionalLight.shadow.mapSize.set(this.shadowResolution, this.shadowResolution);
1948
2090
  this.directionalLight.castShadow = true;
1949
2091
  this.setColor();
1950
- this.updateCharacterPosition(new Vector37(0, 0, 0));
2092
+ this.updateCharacterPosition(new Vector38(0, 0, 0));
1951
2093
  this.add(this.directionalLight);
1952
2094
  if (this.debug === true && this.camHelper instanceof CameraHelper) {
1953
2095
  this.add(this.camHelper);
@@ -1985,7 +2127,7 @@ var Sun = class extends Group3 {
1985
2127
  if (!this.target)
1986
2128
  return;
1987
2129
  const distance = this.sunOffset.z;
1988
- const sphericalPosition = new Vector37(
2130
+ const sphericalPosition = new Vector38(
1989
2131
  distance * Math.sin(polarAngle) * Math.cos(azimuthalAngle),
1990
2132
  distance * Math.cos(polarAngle),
1991
2133
  distance * Math.sin(polarAngle) * Math.sin(azimuthalAngle)
@@ -2896,6 +3038,7 @@ var Composer = class {
2896
3038
  this.ambientLight = null;
2897
3039
  this.sun = null;
2898
3040
  this.scene = scene;
3041
+ this.postPostScene = new Scene3();
2899
3042
  this.camera = camera;
2900
3043
  this.spawnSun = spawnSun;
2901
3044
  this.renderer = new WebGLRenderer2({
@@ -3054,6 +3197,7 @@ var Composer = class {
3054
3197
  this.gaussGrainEffect.uniforms.time.value = timeManager.time;
3055
3198
  this.gaussGrainEffect.uniforms.alpha.value = 1;
3056
3199
  this.composer.render();
3200
+ this.renderer.render(this.postPostScene, this.camera);
3057
3201
  if (this.tweakPane.guiVisible) {
3058
3202
  this.tweakPane.updateStats(timeManager);
3059
3203
  }
@@ -3192,10 +3336,10 @@ import {
3192
3336
  Group as Group4,
3193
3337
  Line3 as Line32,
3194
3338
  Matrix4 as Matrix42,
3195
- Mesh as Mesh3,
3339
+ Mesh as Mesh4,
3196
3340
  MeshBasicMaterial as MeshBasicMaterial3,
3197
3341
  Ray,
3198
- Vector3 as Vector38
3342
+ Vector3 as Vector39
3199
3343
  } from "three";
3200
3344
  import { VertexNormalsHelper } from "three/examples/jsm/helpers/VertexNormalsHelper.js";
3201
3345
  import * as BufferGeometryUtils from "three/examples/jsm/utils/BufferGeometryUtils.js";
@@ -3203,9 +3347,9 @@ import { MeshBVH, MeshBVHVisualizer } from "three-mesh-bvh";
3203
3347
  var CollisionsManager = class {
3204
3348
  constructor(scene) {
3205
3349
  this.debug = false;
3206
- this.tempVector = new Vector38();
3207
- this.tempVector2 = new Vector38();
3208
- this.tempVector3 = new Vector38();
3350
+ this.tempVector = new Vector39();
3351
+ this.tempVector2 = new Vector39();
3352
+ this.tempVector3 = new Vector39();
3209
3353
  this.tempRay = new Ray();
3210
3354
  this.tempMatrix = new Matrix42();
3211
3355
  this.tempMatrix2 = new Matrix42();
@@ -3271,7 +3415,7 @@ var CollisionsManager = class {
3271
3415
  };
3272
3416
  if (this.debug) {
3273
3417
  newBufferGeometry.boundsTree = meshBVH;
3274
- const wireframeMesh = new Mesh3(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
3418
+ const wireframeMesh = new Mesh4(newBufferGeometry, new MeshBasicMaterial3({ wireframe: true }));
3275
3419
  const normalsHelper = new VertexNormalsHelper(wireframeMesh, 0.25, 65280);
3276
3420
  const visualizer = new MeshBVHVisualizer(wireframeMesh, 4);
3277
3421
  visualizer.edgeMaterial.color = new Color7("blue");
@@ -3354,7 +3498,7 @@ var CollisionsManager = class {
3354
3498
  const realDistance = intersectionSegment.distance();
3355
3499
  if (realDistance < capsuleRadius) {
3356
3500
  if (!collisionPosition) {
3357
- collisionPosition = new Vector38().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
3501
+ collisionPosition = new Vector39().copy(closestPointOnSegment).applyMatrix4(meshState.matrix);
3358
3502
  }
3359
3503
  const ratio = realDistance / modelReferenceDistance;
3360
3504
  const realDepth = capsuleRadius - realDistance;