@mml-io/3d-web-client-core 0.0.0-experimental-78df22f-20230814 → 0.0.0-experimental-41e9cfc-20230816

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.
@@ -0,0 +1,32 @@
1
+ import * as THREE from "three";
2
+ type RGBA = {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ a: number;
7
+ };
8
+ type CanvasTextOptions = {
9
+ fontSize: number;
10
+ textColorRGB255A1: RGBA;
11
+ backgroundColorRGB255A1?: RGBA;
12
+ font?: string;
13
+ bold?: boolean;
14
+ paddingPx?: number;
15
+ alignment?: string;
16
+ dimensions?: {
17
+ width: number;
18
+ height: number;
19
+ };
20
+ };
21
+ export declare function CanvasText(message: string, options: CanvasTextOptions): HTMLCanvasElement;
22
+ export declare function THREECanvasTextTexture(text: string, options: CanvasTextOptions): {
23
+ texture: THREE.Texture;
24
+ width: number;
25
+ height: number;
26
+ };
27
+ export declare function THREECanvasTextMaterial(text: string, options: CanvasTextOptions): {
28
+ material: THREE.MeshBasicMaterial;
29
+ width: number;
30
+ height: number;
31
+ };
32
+ export {};
@@ -4,6 +4,7 @@ import { CollisionsManager } from "../collisions/CollisionsManager";
4
4
  import { KeyInputManager } from "../input/KeyInputManager";
5
5
  import { TimeManager } from "../time/TimeManager";
6
6
  import { CharacterModel } from "./CharacterModel";
7
+ import { CharacterTooltip } from "./CharacterTooltip";
7
8
  import { LocalController } from "./LocalController";
8
9
  export type CharacterDescription = {
9
10
  meshFileUrl: string;
@@ -27,6 +28,7 @@ export declare class Character {
27
28
  model: CharacterModel | null;
28
29
  color: Color;
29
30
  position: Vector3;
31
+ tooltip: CharacterTooltip | null;
30
32
  constructor(characterDescription: CharacterDescription, id: number, isLocal: boolean, modelLoadedCallback: () => void, collisionsManager: CollisionsManager, keyInputManager: KeyInputManager, cameraManager: CameraManager, timeManager: TimeManager);
31
33
  private load;
32
34
  update(time: number): void;
@@ -0,0 +1,17 @@
1
+ import { Camera, Object3D } from "three";
2
+ export declare class CharacterTooltip {
3
+ private texture;
4
+ private geometry;
5
+ private material;
6
+ private mesh;
7
+ private visibleOpacity;
8
+ private targetOpacity;
9
+ private fadingSpeed;
10
+ private secondsToFadeOut;
11
+ private props;
12
+ constructor(parentModel: Object3D);
13
+ private redrawText;
14
+ setText(text: string, temporary?: boolean): void;
15
+ hide(): void;
16
+ update(camera: Camera): void;
17
+ }
package/build/index.js CHANGED
@@ -168,7 +168,7 @@ var CameraManager = class {
168
168
  };
169
169
 
170
170
  // src/character/Character.ts
171
- import { Color as Color2, Vector3 as Vector34 } from "three";
171
+ import { Color as Color3, Vector3 as Vector34 } from "three";
172
172
 
173
173
  // src/character/CharacterModel.ts
174
174
  import {
@@ -724,6 +724,247 @@ var CharacterModel = class {
724
724
  }
725
725
  };
726
726
 
727
+ // src/character/CharacterTooltip.ts
728
+ import {
729
+ Color as Color2,
730
+ FrontSide,
731
+ LinearFilter as LinearFilter2,
732
+ Mesh as Mesh2,
733
+ MeshBasicMaterial as MeshBasicMaterial2,
734
+ PlaneGeometry
735
+ } from "three";
736
+
737
+ // src/character/CanvasText.ts
738
+ import * as THREE from "three";
739
+ function getTextAlignOffset(textAlign, width) {
740
+ switch (textAlign) {
741
+ case "center":
742
+ return width / 2;
743
+ case "right":
744
+ return width;
745
+ default:
746
+ return 0;
747
+ }
748
+ }
749
+ function printAtWordWrap(context, fullText, x, y, lineHeight, fitWidth, padding, alignment) {
750
+ const lines = fullText.split("\n");
751
+ let currentLine = 0;
752
+ for (const text of lines) {
753
+ fitWidth = fitWidth || 0;
754
+ if (fitWidth <= 0) {
755
+ context.fillText(text, x, y + lineHeight * currentLine);
756
+ currentLine++;
757
+ continue;
758
+ }
759
+ let words = text.split(" ");
760
+ let lastWordIndex = 1;
761
+ while (words.length > 0 && lastWordIndex <= words.length) {
762
+ const str = words.slice(0, lastWordIndex).join(" ");
763
+ const textWidth = context.measureText(str).width;
764
+ if (textWidth + padding * 2 > fitWidth) {
765
+ if (lastWordIndex === 1) {
766
+ lastWordIndex = 2;
767
+ }
768
+ context.fillText(
769
+ words.slice(0, lastWordIndex - 1).join(" "),
770
+ x + padding,
771
+ y + lineHeight * currentLine + padding
772
+ );
773
+ currentLine++;
774
+ words = words.splice(lastWordIndex - 1);
775
+ lastWordIndex = 1;
776
+ } else {
777
+ lastWordIndex++;
778
+ }
779
+ }
780
+ if (lastWordIndex > 0 && words.length > 0) {
781
+ const xOffset = alignment === "center" ? 0 : padding;
782
+ context.fillText(words.join(" "), x + xOffset, y + lineHeight * currentLine + padding);
783
+ currentLine++;
784
+ }
785
+ }
786
+ }
787
+ function CanvasText(message, options) {
788
+ const fontsize = options.fontSize;
789
+ const textColor = options.textColorRGB255A1;
790
+ const backgroundColor = options.backgroundColorRGB255A1 || { r: 255, g: 255, b: 255, a: 1 };
791
+ const padding = options.paddingPx || 0;
792
+ const font = options.font || "Arial";
793
+ const fontString = (options.bold ? "bold " : "") + fontsize + "px " + font;
794
+ const canvas = document.createElement("canvas");
795
+ const ct = canvas.getContext("2d");
796
+ const textAlign = options.alignment ?? "left";
797
+ if (options.dimensions) {
798
+ canvas.width = options.dimensions.width;
799
+ canvas.height = options.dimensions.height;
800
+ ct.clearRect(0, 0, canvas.width, canvas.height);
801
+ ct.font = fontString;
802
+ ct.textAlign = textAlign;
803
+ ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
804
+ ct.lineWidth = 0;
805
+ ct.fillRect(0, 0, canvas.width, canvas.height);
806
+ ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
807
+ ct.font = fontString;
808
+ printAtWordWrap(
809
+ ct,
810
+ message,
811
+ getTextAlignOffset(textAlign, canvas.width),
812
+ fontsize,
813
+ fontsize,
814
+ canvas.width,
815
+ padding,
816
+ textAlign
817
+ );
818
+ } else {
819
+ ct.font = fontString;
820
+ const metrics = ct.measureText(message);
821
+ const textWidth = metrics.width;
822
+ const textHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
823
+ canvas.width = textWidth + padding * 2;
824
+ canvas.height = textHeight + padding;
825
+ ct.clearRect(0, 0, canvas.width, canvas.height);
826
+ ct.font = fontString;
827
+ ct.textAlign = textAlign;
828
+ ct.fillStyle = `rgba(${backgroundColor.r}, ${backgroundColor.g}, ${backgroundColor.b}, ${backgroundColor.a})`;
829
+ ct.lineWidth = 0;
830
+ ct.fillRect(0, 0, canvas.width, canvas.height);
831
+ ct.fillStyle = `rgba(${textColor.r}, ${textColor.g}, ${textColor.b}, ${textColor.a})`;
832
+ ct.font = fontString;
833
+ ct.fillText(message, padding + getTextAlignOffset(textAlign, textWidth), textHeight);
834
+ }
835
+ return canvas;
836
+ }
837
+ function THREECanvasTextTexture(text, options) {
838
+ const canvas = CanvasText(text, options);
839
+ const texture = new THREE.Texture(canvas);
840
+ texture.minFilter = THREE.LinearFilter;
841
+ texture.magFilter = THREE.LinearFilter;
842
+ texture.format = THREE.RGBAFormat;
843
+ texture.needsUpdate = true;
844
+ return { texture, width: canvas.width, height: canvas.height };
845
+ }
846
+
847
+ // src/character/CharacterTooltip.ts
848
+ var fontScale = 5;
849
+ var defaultLabelColor = new Color2(0);
850
+ var defaultFontColor = new Color2(16777215);
851
+ var defaultLabelAlignment = "center" /* center */;
852
+ var defaultLabelFontSize = 9;
853
+ var defaultLabelPadding = 0;
854
+ var defaultLabelWidth = 0.25;
855
+ var defaultLabelHeight = 0.125;
856
+ var defaultLabelCastShadows = true;
857
+ var CharacterTooltip = class {
858
+ constructor(parentModel) {
859
+ __publicField(this, "texture");
860
+ __publicField(this, "geometry");
861
+ __publicField(this, "material");
862
+ __publicField(this, "mesh");
863
+ __publicField(this, "visibleOpacity", 0.85);
864
+ __publicField(this, "targetOpacity", 0);
865
+ __publicField(this, "fadingSpeed", 0.02);
866
+ __publicField(this, "secondsToFadeOut", 15);
867
+ __publicField(this, "props", {
868
+ content: "",
869
+ alignment: defaultLabelAlignment,
870
+ width: defaultLabelWidth,
871
+ height: defaultLabelHeight,
872
+ fontSize: defaultLabelFontSize,
873
+ padding: defaultLabelPadding,
874
+ color: defaultLabelColor,
875
+ fontColor: defaultFontColor,
876
+ castShadows: defaultLabelCastShadows
877
+ });
878
+ this.setText = this.setText.bind(this);
879
+ this.material = new MeshBasicMaterial2({
880
+ map: this.texture,
881
+ transparent: true,
882
+ opacity: 0
883
+ });
884
+ this.material.side = FrontSide;
885
+ this.geometry = new PlaneGeometry(1, 1, 1, 1);
886
+ this.mesh = new Mesh2(this.geometry, this.material);
887
+ this.mesh.position.set(0, 1.6, 0);
888
+ this.mesh.visible = false;
889
+ parentModel.add(this.mesh);
890
+ }
891
+ redrawText(content) {
892
+ if (!this.material) {
893
+ return;
894
+ }
895
+ if (this.material.map) {
896
+ this.material.map.dispose();
897
+ }
898
+ const { texture, width, height } = THREECanvasTextTexture(content, {
899
+ bold: true,
900
+ fontSize: this.props.fontSize * fontScale,
901
+ paddingPx: this.props.padding,
902
+ textColorRGB255A1: {
903
+ r: this.props.fontColor.r * 255,
904
+ g: this.props.fontColor.g * 255,
905
+ b: this.props.fontColor.b * 255,
906
+ a: 1
907
+ },
908
+ backgroundColorRGB255A1: {
909
+ r: this.props.color.r * 255,
910
+ g: this.props.color.g * 255,
911
+ b: this.props.color.b * 255,
912
+ a: 1
913
+ },
914
+ dimensions: {
915
+ width: this.props.width * (100 * fontScale),
916
+ height: this.props.height * (100 * fontScale)
917
+ },
918
+ alignment: this.props.alignment
919
+ });
920
+ this.material.map = texture;
921
+ this.material.map.magFilter = LinearFilter2;
922
+ this.material.map.minFilter = LinearFilter2;
923
+ this.material.needsUpdate = true;
924
+ this.mesh.scale.x = width / (100 * fontScale);
925
+ this.mesh.scale.y = height / (100 * fontScale);
926
+ this.mesh.position.y = 1.6;
927
+ }
928
+ setText(text, temporary = false) {
929
+ this.redrawText(text);
930
+ this.mesh.visible = true;
931
+ this.targetOpacity = this.visibleOpacity;
932
+ if (temporary) {
933
+ setTimeout(() => {
934
+ this.hide();
935
+ }, this.secondsToFadeOut * 1e3);
936
+ }
937
+ }
938
+ hide() {
939
+ this.targetOpacity = 0;
940
+ }
941
+ update(camera) {
942
+ this.mesh.lookAt(camera.position);
943
+ const opacity = this.mesh.material.opacity;
944
+ if (opacity < this.targetOpacity) {
945
+ this.mesh.material.opacity = Math.min(
946
+ this.mesh.material.opacity + this.fadingSpeed,
947
+ this.targetOpacity
948
+ );
949
+ } else if (opacity > this.targetOpacity) {
950
+ this.mesh.material.opacity = Math.max(
951
+ this.mesh.material.opacity - this.fadingSpeed,
952
+ this.targetOpacity
953
+ );
954
+ if (opacity >= 1 && this.mesh.material.transparent === true) {
955
+ this.mesh.material.transparent = false;
956
+ this.mesh.material.needsUpdate = true;
957
+ } else if (opacity > 0 && opacity < 1 && this.mesh.material.transparent === false) {
958
+ this.mesh.material.transparent = true;
959
+ this.mesh.material.needsUpdate = true;
960
+ }
961
+ if (this.mesh.material.opacity <= 0) {
962
+ this.mesh.visible = false;
963
+ }
964
+ }
965
+ }
966
+ };
967
+
727
968
  // src/character/LocalController.ts
728
969
  import { Box3, Line3, Matrix4, Quaternion, Raycaster as Raycaster2, Vector3 as Vector33 } from "three";
729
970
  var LocalController = class {
@@ -997,13 +1238,17 @@ var Character = class {
997
1238
  __publicField(this, "controller", null);
998
1239
  __publicField(this, "name", null);
999
1240
  __publicField(this, "model", null);
1000
- __publicField(this, "color", new Color2());
1241
+ __publicField(this, "color", new Color3());
1001
1242
  __publicField(this, "position", new Vector34());
1243
+ __publicField(this, "tooltip", null);
1002
1244
  this.load();
1003
1245
  }
1004
1246
  async load() {
1005
1247
  this.model = new CharacterModel(this.characterDescription);
1006
1248
  await this.model.init();
1249
+ if (this.tooltip === null) {
1250
+ this.tooltip = new CharacterTooltip(this.model.mesh);
1251
+ }
1007
1252
  this.color = this.model.material.colorsCube216[this.id];
1008
1253
  if (this.isLocal) {
1009
1254
  this.controller = new LocalController(
@@ -1020,6 +1265,9 @@ var Character = class {
1020
1265
  update(time) {
1021
1266
  if (!this.model)
1022
1267
  return;
1268
+ if (this.tooltip) {
1269
+ this.tooltip.update(this.cameraManager.camera);
1270
+ }
1023
1271
  this.model.mesh.getWorldPosition(this.position);
1024
1272
  if (typeof this.model.material.uniforms.time !== "undefined") {
1025
1273
  this.model.material.uniforms.time.value = time;
@@ -1035,7 +1283,7 @@ import { Group, Vector3 as Vector36 } from "three";
1035
1283
  // src/character/RemoteController.ts
1036
1284
  import {
1037
1285
  AnimationMixer as AnimationMixer2,
1038
- Object3D as Object3D3,
1286
+ Object3D as Object3D4,
1039
1287
  Quaternion as Quaternion2,
1040
1288
  Vector3 as Vector35
1041
1289
  } from "three";
@@ -1045,7 +1293,7 @@ var RemoteController = class {
1045
1293
  this.id = id;
1046
1294
  __publicField(this, "modelLoader", ModelLoader_default);
1047
1295
  __publicField(this, "characterModel", null);
1048
- __publicField(this, "animationMixer", new AnimationMixer2(new Object3D3()));
1296
+ __publicField(this, "animationMixer", new AnimationMixer2(new Object3D4()));
1049
1297
  __publicField(this, "animations", /* @__PURE__ */ new Map());
1050
1298
  __publicField(this, "currentAnimation", 0 /* idle */);
1051
1299
  __publicField(this, "networkState", {
@@ -1187,6 +1435,7 @@ var CharacterManager = class {
1187
1435
  this.group.add(character.model.mesh);
1188
1436
  if (isLocal) {
1189
1437
  this.character = character;
1438
+ this.character.tooltip?.setText(`${id}`);
1190
1439
  } else {
1191
1440
  this.remoteCharacters.set(id, character);
1192
1441
  const remoteController = new RemoteController(character, id);
@@ -1212,6 +1461,7 @@ var CharacterManager = class {
1212
1461
  spawnPosition.z
1213
1462
  );
1214
1463
  this.remoteCharacterControllers.set(id, remoteController);
1464
+ character.tooltip?.setText(`${id}`);
1215
1465
  }
1216
1466
  resolve(character);
1217
1467
  },
@@ -1441,7 +1691,7 @@ import {
1441
1691
  NormalPass
1442
1692
  } from "postprocessing";
1443
1693
  import {
1444
- Color as Color4,
1694
+ Color as Color5,
1445
1695
  HalfFloatType,
1446
1696
  LinearSRGBColorSpace,
1447
1697
  LoadingManager as LoadingManager2,
@@ -1456,9 +1706,9 @@ import { BlendFunction } from "postprocessing";
1456
1706
  var composerValues = {
1457
1707
  renderer: {
1458
1708
  shadowMap: 2,
1459
- toneMapping: 4,
1709
+ toneMapping: 5,
1460
1710
  exposure: 1,
1461
- bgIntensity: 0.6,
1711
+ bgIntensity: 0.5,
1462
1712
  bgBlurriness: 0
1463
1713
  },
1464
1714
  ssao: {
@@ -1490,9 +1740,9 @@ var composerValues = {
1490
1740
  },
1491
1741
  brightness: -0.03,
1492
1742
  contrast: 1.3,
1493
- saturation: 0.95,
1494
- grain: 0.055,
1495
- bloom: 0.4
1743
+ saturation: 0.91,
1744
+ grain: 0.061,
1745
+ bloom: 0.45
1496
1746
  };
1497
1747
  var composerOptions = {
1498
1748
  renderer: {
@@ -1538,7 +1788,7 @@ var composerOptions = {
1538
1788
  amount: { min: 0, max: 0.2, step: 2e-3 }
1539
1789
  },
1540
1790
  bloom: {
1541
- amount: { min: 0, max: 4, step: 0.1 }
1791
+ amount: { min: 0, max: 2, step: 0.05 }
1542
1792
  }
1543
1793
  };
1544
1794
  var shadowMapTypes = {
@@ -1602,7 +1852,7 @@ var statsData = {
1602
1852
  import {
1603
1853
  BlendFunction as BlendFunction2
1604
1854
  } from "postprocessing";
1605
- import { Color as Color3 } from "three";
1855
+ import { Color as Color4 } from "three";
1606
1856
  import { Pane } from "tweakpane";
1607
1857
  var TweakPane = class {
1608
1858
  constructor(renderer, scene, composer) {
@@ -1793,12 +2043,8 @@ var TweakPane = class {
1793
2043
  break;
1794
2044
  case "toneMapping":
1795
2045
  this.renderer.toneMapping = e.value;
1796
- if (e.value !== 5 && e.value !== 0) {
1797
- this.toneMapping.hidden = true;
1798
- } else {
1799
- this.toneMapping.hidden = false;
1800
- }
1801
- toneMappingPass.enabled = e.value === 5 || e.value === 0 ? true : false;
2046
+ this.toneMapping.hidden = e.value !== 5;
2047
+ toneMappingPass.enabled = e.value === 5 ? true : false;
1802
2048
  setToneMappingType(e.value);
1803
2049
  break;
1804
2050
  case "exposure":
@@ -1872,7 +2118,7 @@ var TweakPane = class {
1872
2118
  return;
1873
2119
  }
1874
2120
  if (e.presetKey === "color") {
1875
- ssaoEffect.color = new Color3().setRGB(e.value.r, e.value.g, e.value.b);
2121
+ ssaoEffect.color = new Color4().setRGB(e.value.r, e.value.g, e.value.b);
1876
2122
  return;
1877
2123
  }
1878
2124
  ssaoEffect[preset] = e.value;
@@ -2236,7 +2482,7 @@ var Composer = class {
2236
2482
  bias: composerValues.ssao.bias,
2237
2483
  fade: composerValues.ssao.fade,
2238
2484
  resolutionScale: composerValues.ssao.resolutionScale,
2239
- color: new Color4().setRGB(composerValues.ssao.color.r, composerValues.ssao.color.g, composerValues.ssao.color.b),
2485
+ color: new Color5().setRGB(composerValues.ssao.color.r, composerValues.ssao.color.g, composerValues.ssao.color.b),
2240
2486
  worldDistanceThreshold: composerValues.ssao.worldDistanceThreshold,
2241
2487
  worldDistanceFalloff: composerValues.ssao.worldDistanceFalloff,
2242
2488
  worldProximityThreshold: composerValues.ssao.worldProximityThreshold,
@@ -2396,11 +2642,11 @@ import {
2396
2642
  getRelativePositionAndRotationRelativeToObject
2397
2643
  } from "mml-web";
2398
2644
  import {
2399
- Color as Color5,
2645
+ Color as Color6,
2400
2646
  DoubleSide,
2401
2647
  Euler,
2402
- FrontSide,
2403
- Mesh as Mesh2,
2648
+ FrontSide as FrontSide2,
2649
+ Mesh as Mesh3,
2404
2650
  MeshStandardMaterial as MeshStandardMaterial2,
2405
2651
  Vector3 as Vector37
2406
2652
  } from "three";
@@ -2455,13 +2701,13 @@ var CollisionsManager = class {
2455
2701
  if (!this.debug) {
2456
2702
  return { source: group, visualizer: null, meshBVH };
2457
2703
  }
2458
- const mergedMesh = new Mesh2(
2704
+ const mergedMesh = new Mesh3(
2459
2705
  newBufferGeometry,
2460
- new MeshStandardMaterial2({ color: 16711680, side: FrontSide, wireframe: true })
2706
+ new MeshStandardMaterial2({ color: 16711680, side: FrontSide2, wireframe: true })
2461
2707
  );
2462
2708
  mergedMesh.geometry.boundsTree = meshBVH;
2463
2709
  const visualizer = new MeshBVHVisualizer(mergedMesh, 3);
2464
- visualizer.edgeMaterial.color = new Color5(255);
2710
+ visualizer.edgeMaterial.color = new Color6(255);
2465
2711
  visualizer.update();
2466
2712
  return { source: group, visualizer, meshBVH };
2467
2713
  }