@needle-tools/engine 4.2.5 → 4.3.0-alpha.1

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.
Files changed (121) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/components.needle.json +1 -1
  3. package/dist/needle-engine.bundle.js +4245 -2977
  4. package/dist/needle-engine.bundle.light.js +4236 -2968
  5. package/dist/needle-engine.bundle.light.min.js +73 -73
  6. package/dist/needle-engine.bundle.light.umd.cjs +61 -61
  7. package/dist/needle-engine.bundle.min.js +62 -62
  8. package/dist/needle-engine.bundle.umd.cjs +61 -61
  9. package/dist/needle-engine.light.d.ts +9 -9
  10. package/dist/three-examples.js +825 -794
  11. package/dist/three-examples.light.js +825 -794
  12. package/dist/three-examples.light.min.js +12 -12
  13. package/dist/three-examples.light.umd.cjs +10 -10
  14. package/dist/three-examples.min.js +12 -12
  15. package/dist/three-examples.umd.cjs +10 -10
  16. package/lib/engine/engine_addressables.d.ts +3 -0
  17. package/lib/engine/engine_addressables.js +18 -0
  18. package/lib/engine/engine_addressables.js.map +1 -1
  19. package/lib/engine/engine_input.d.ts +20 -1
  20. package/lib/engine/engine_input.js.map +1 -1
  21. package/lib/engine/engine_types.d.ts +162 -17
  22. package/lib/engine-components/Animator.d.ts +129 -21
  23. package/lib/engine-components/Animator.js +115 -21
  24. package/lib/engine-components/Animator.js.map +1 -1
  25. package/lib/engine-components/AnimatorController.d.ts +161 -32
  26. package/lib/engine-components/AnimatorController.js +176 -29
  27. package/lib/engine-components/AnimatorController.js.map +1 -1
  28. package/lib/engine-components/AudioListener.d.ts +16 -5
  29. package/lib/engine-components/AudioListener.js +16 -5
  30. package/lib/engine-components/AudioListener.js.map +1 -1
  31. package/lib/engine-components/AudioSource.d.ts +120 -28
  32. package/lib/engine-components/AudioSource.js +120 -37
  33. package/lib/engine-components/AudioSource.js.map +1 -1
  34. package/lib/engine-components/AvatarLoader.d.ts +61 -0
  35. package/lib/engine-components/AvatarLoader.js +61 -1
  36. package/lib/engine-components/AvatarLoader.js.map +1 -1
  37. package/lib/engine-components/AxesHelper.d.ts +19 -1
  38. package/lib/engine-components/AxesHelper.js +19 -1
  39. package/lib/engine-components/AxesHelper.js.map +1 -1
  40. package/lib/engine-components/BoxHelperComponent.d.ts +26 -0
  41. package/lib/engine-components/BoxHelperComponent.js +26 -0
  42. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  43. package/lib/engine-components/Camera.d.ts +126 -37
  44. package/lib/engine-components/Camera.js +139 -37
  45. package/lib/engine-components/Camera.js.map +1 -1
  46. package/lib/engine-components/CameraUtils.js +20 -0
  47. package/lib/engine-components/CameraUtils.js.map +1 -1
  48. package/lib/engine-components/Collider.d.ts +95 -21
  49. package/lib/engine-components/Collider.js +100 -23
  50. package/lib/engine-components/Collider.js.map +1 -1
  51. package/lib/engine-components/Component.d.ts +554 -106
  52. package/lib/engine-components/Component.js +352 -81
  53. package/lib/engine-components/Component.js.map +1 -1
  54. package/lib/engine-components/DragControls.d.ts +95 -21
  55. package/lib/engine-components/DragControls.js +126 -32
  56. package/lib/engine-components/DragControls.js.map +1 -1
  57. package/lib/engine-components/DropListener.d.ts +99 -16
  58. package/lib/engine-components/DropListener.js +119 -14
  59. package/lib/engine-components/DropListener.js.map +1 -1
  60. package/lib/engine-components/Light.d.ts +102 -5
  61. package/lib/engine-components/Light.js +102 -44
  62. package/lib/engine-components/Light.js.map +1 -1
  63. package/lib/engine-components/NeedleMenu.d.ts +28 -11
  64. package/lib/engine-components/NeedleMenu.js +28 -11
  65. package/lib/engine-components/NeedleMenu.js.map +1 -1
  66. package/lib/engine-components/Networking.d.ts +37 -5
  67. package/lib/engine-components/Networking.js +37 -5
  68. package/lib/engine-components/Networking.js.map +1 -1
  69. package/lib/engine-components/SceneSwitcher.d.ts +8 -0
  70. package/lib/engine-components/SceneSwitcher.js +72 -8
  71. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  72. package/lib/engine-components/SpatialTrigger.d.ts +66 -1
  73. package/lib/engine-components/SpatialTrigger.js +74 -2
  74. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  75. package/lib/engine-components/SpectatorCamera.d.ts +66 -4
  76. package/lib/engine-components/SpectatorCamera.js +132 -6
  77. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  78. package/lib/engine-components/SyncedTransform.d.ts +45 -6
  79. package/lib/engine-components/SyncedTransform.js +45 -6
  80. package/lib/engine-components/SyncedTransform.js.map +1 -1
  81. package/lib/engine-components/TransformGizmo.d.ts +49 -3
  82. package/lib/engine-components/TransformGizmo.js +49 -3
  83. package/lib/engine-components/TransformGizmo.js.map +1 -1
  84. package/lib/engine-components/ui/EventSystem.d.ts +1 -0
  85. package/lib/engine-components/ui/EventSystem.js +8 -5
  86. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  87. package/lib/engine-components/webxr/WebXR.d.ts +131 -22
  88. package/lib/engine-components/webxr/WebXR.js +132 -23
  89. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  90. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +82 -9
  91. package/lib/engine-components-experimental/networking/PlayerSync.js +76 -11
  92. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  93. package/package.json +1 -1
  94. package/plugins/vite/alias.js +6 -3
  95. package/src/engine/engine_addressables.ts +21 -0
  96. package/src/engine/engine_input.ts +20 -1
  97. package/src/engine/engine_types.ts +179 -18
  98. package/src/engine-components/Animator.ts +142 -22
  99. package/src/engine-components/AnimatorController.ts +184 -34
  100. package/src/engine-components/AudioListener.ts +16 -5
  101. package/src/engine-components/AudioSource.ts +126 -37
  102. package/src/engine-components/AvatarLoader.ts +61 -2
  103. package/src/engine-components/AxesHelper.ts +21 -1
  104. package/src/engine-components/BoxHelperComponent.ts +26 -0
  105. package/src/engine-components/Camera.ts +147 -41
  106. package/src/engine-components/CameraUtils.ts +20 -0
  107. package/src/engine-components/Collider.ts +102 -27
  108. package/src/engine-components/Component.ts +605 -129
  109. package/src/engine-components/DragControls.ts +134 -38
  110. package/src/engine-components/DropListener.ts +143 -23
  111. package/src/engine-components/Light.ts +105 -44
  112. package/src/engine-components/NeedleMenu.ts +29 -11
  113. package/src/engine-components/Networking.ts +37 -6
  114. package/src/engine-components/SceneSwitcher.ts +78 -9
  115. package/src/engine-components/SpatialTrigger.ts +80 -3
  116. package/src/engine-components/SpectatorCamera.ts +136 -18
  117. package/src/engine-components/SyncedTransform.ts +50 -7
  118. package/src/engine-components/TransformGizmo.ts +49 -4
  119. package/src/engine-components/ui/EventSystem.ts +9 -7
  120. package/src/engine-components/webxr/WebXR.ts +144 -27
  121. package/src/engine-components-experimental/networking/PlayerSync.ts +85 -13
@@ -17,50 +17,77 @@ import { AvatarMarker } from "./webxr/WebXRAvatar.js";
17
17
  import { XRStateFlag } from "./webxr/XRFlag.js";
18
18
 
19
19
 
20
+ /**
21
+ * Defines the viewing perspective in spectator mode
22
+ */
20
23
  export enum SpectatorMode {
24
+ /** View from the perspective of the followed player */
21
25
  FirstPerson = 0,
26
+ /** Freely view from a third-person perspective */
22
27
  ThirdPerson = 1,
23
28
  }
24
29
 
25
30
  const debug = getParam("debugspectator");
26
31
 
27
32
  /**
33
+ * Provides functionality to follow and spectate other users in a networked environment.
34
+ * Handles camera switching, following behavior, and network synchronization for spectator mode.
35
+ *
36
+ * Debug mode can be enabled with the URL parameter `?debugspectator`, which provides additional console output.
37
+ *
28
38
  * @category Networking
29
39
  * @group Components
30
40
  */
31
41
  export class SpectatorCamera extends Behaviour {
32
42
 
43
+ /** Reference to the Camera component on this GameObject */
33
44
  cam: Camera | null = null;
34
45
 
35
- /** when enabled pressing F will send a request to all connected users to follow me, ESC to stop */
46
+ /**
47
+ * When enabled, pressing F will send a request to all connected users to follow the local player.
48
+ * Pressing ESC will stop spectating.
49
+ */
36
50
  @serializable()
37
51
  useKeys: boolean = true;
38
52
 
39
53
  private _mode: SpectatorMode = SpectatorMode.FirstPerson;
40
54
 
55
+ /** Gets the current spectator perspective mode */
41
56
  get mode() { return this._mode; }
57
+ /** Sets the current spectator perspective mode */
42
58
  set mode(val: SpectatorMode) {
43
59
  this._mode = val;
44
60
  }
45
61
 
46
- /** if this user is currently spectating someone else */
62
+ /** Returns whether this user is currently spectating another user */
47
63
  get isSpectating(): boolean {
48
64
  return this._handler?.currentTarget !== undefined;
49
65
  }
50
66
 
67
+ /**
68
+ * Checks if this instance is spectating the user with the given ID
69
+ * @param userId The user ID to check
70
+ * @returns True if spectating the specified user, false otherwise
71
+ */
51
72
  isSpectatingUser(userId: string): boolean {
52
73
  return this.target?.userId === userId;
53
74
  }
54
75
 
76
+ /**
77
+ * Checks if the user with the specified ID is following this user
78
+ * @param userId The user ID to check
79
+ * @returns True if the specified user is following this user, false otherwise
80
+ */
55
81
  isFollowedBy(userId: string): boolean {
56
82
  return this.followers?.includes(userId);
57
83
  }
58
84
 
59
- /** list of other users that are following me */
85
+ /** List of user IDs that are currently following the user */
60
86
  get followers(): string[] {
61
87
  return this._networking.followers;
62
88
  }
63
89
 
90
+ /** Stops the current spectating session */
64
91
  stopSpectating() {
65
92
  if (this.context.isInXR) {
66
93
  this.followSelf();
@@ -69,11 +96,15 @@ export class SpectatorCamera extends Behaviour {
69
96
  this.target = undefined;
70
97
  }
71
98
 
99
+ /** Gets the local player's connection ID */
72
100
  private get localId() : string {
73
101
  return this.context.connection.connectionId ?? "local";
74
102
  }
75
103
 
76
- /** player view to follow */
104
+ /**
105
+ * Sets the player view to follow
106
+ * @param target The PlayerView to follow, or undefined to stop spectating
107
+ */
77
108
  set target(target: PlayerView | undefined) {
78
109
  if (this._handler) {
79
110
 
@@ -106,14 +137,17 @@ export class SpectatorCamera extends Behaviour {
106
137
  }
107
138
  }
108
139
 
140
+ /** Gets the currently followed player view */
109
141
  get target(): PlayerView | undefined {
110
142
  return this._handler?.currentTarget;
111
143
  }
112
144
 
145
+ /** Sends a network request for all users to follow this player */
113
146
  requestAllFollowMe() {
114
147
  this._networking.onRequestFollowMe();
115
148
  }
116
149
 
150
+ /** Determines if the camera is spectating the local player */
117
151
  private get isSpectatingSelf() {
118
152
  return this.isSpectating && this.target?.currentObject === this.context.players.getPlayerView(this.localId)?.currentObject;
119
153
  }
@@ -131,7 +165,6 @@ export class SpectatorCamera extends Behaviour {
131
165
  private _networking!: SpectatorCamNetworking;
132
166
 
133
167
  awake(): void {
134
-
135
168
  this._debug = new SpectatorSelectionController(this.context, this);
136
169
  this._networking = new SpectatorCamNetworking(this.context, this);
137
170
  this._networking.awake();
@@ -144,7 +177,6 @@ export class SpectatorCamera extends Behaviour {
144
177
  return;
145
178
  }
146
179
 
147
-
148
180
  if (!this._handler && this.cam)
149
181
  this._handler = new SpectatorHandler(this.context, this.cam, this);
150
182
 
@@ -157,6 +189,10 @@ export class SpectatorCamera extends Behaviour {
157
189
  this._networking?.destroy();
158
190
  }
159
191
 
192
+ /**
193
+ * Checks if the current platform supports spectator mode
194
+ * @returns True if the platform is supported, false otherwise
195
+ */
160
196
  private isSupportedPlatform() {
161
197
  const ua = window.navigator.userAgent;
162
198
  const standalone = /Windows|MacOS/.test(ua);
@@ -164,12 +200,19 @@ export class SpectatorCamera extends Behaviour {
164
200
  return standalone && !isHololens;
165
201
  }
166
202
 
203
+ /**
204
+ * Called before entering WebXR mode
205
+ * @param _evt The WebXR event
206
+ */
167
207
  onBeforeXR(_evt) {
168
208
  if (!this.isSupportedPlatform()) return;
169
209
  GameObject.setActive(this.gameObject, true);
170
210
  }
171
211
 
172
-
212
+ /**
213
+ * Called when entering WebXR mode
214
+ * @param _evt The WebXR event
215
+ */
173
216
  onEnterXR(_evt) {
174
217
  if (!this.isSupportedPlatform()) return;
175
218
  if (debug) console.log(this.context.mainCamera);
@@ -178,6 +221,10 @@ export class SpectatorCamera extends Behaviour {
178
221
  }
179
222
  }
180
223
 
224
+ /**
225
+ * Called when exiting WebXR mode
226
+ * @param _evt The WebXR event
227
+ */
181
228
  onLeaveXR(_evt) {
182
229
  this.context.removeCamera(this.cam as ICamera);
183
230
  GameObject.setActive(this.gameObject, false);
@@ -188,7 +235,9 @@ export class SpectatorCamera extends Behaviour {
188
235
  this.stopSpectating();
189
236
  }
190
237
 
191
-
238
+ /**
239
+ * Sets the target to follow the local player
240
+ */
192
241
  private followSelf() {
193
242
  this.target = this.context.players.getPlayerView(this.context.connection.connectionId);
194
243
  if (!this.target) {
@@ -201,6 +250,9 @@ export class SpectatorCamera extends Behaviour {
201
250
  // TODO: only show Spectator cam for DesktopVR;
202
251
  // don't show for AR, don't show on Quest
203
252
  // TODO: properly align cameras on enter/exit VR, seems currently spectator cam breaks alignment
253
+ /**
254
+ * Called after the main rendering pass to render the spectator view
255
+ */
204
256
  onAfterRender(): void {
205
257
  if (!this.cam) return;
206
258
 
@@ -278,6 +330,9 @@ export class SpectatorCamera extends Behaviour {
278
330
  this.resetAvatarFlags();
279
331
  }
280
332
 
333
+ /**
334
+ * Updates avatar visibility flags for rendering in spectator mode
335
+ */
281
336
  private setAvatarFlagsBeforeRender() {
282
337
  const isFirstPersonMode = this._mode === SpectatorMode.FirstPerson;
283
338
 
@@ -295,6 +350,9 @@ export class SpectatorCamera extends Behaviour {
295
350
  }
296
351
  }
297
352
 
353
+ /**
354
+ * Restores avatar visibility flags after spectator rendering
355
+ */
298
356
  private resetAvatarFlags() {
299
357
  for (const av of AvatarMarker.instances) {
300
358
  if (av.avatar && "flags" in av.avatar) {
@@ -313,6 +371,9 @@ export class SpectatorCamera extends Behaviour {
313
371
  }
314
372
  }
315
373
 
374
+ /**
375
+ * Interface for handling spectator camera behavior
376
+ */
316
377
  interface ISpectatorHandler {
317
378
  context: Context;
318
379
  get currentTarget(): PlayerView | undefined;
@@ -322,6 +383,9 @@ interface ISpectatorHandler {
322
383
  destroy();
323
384
  }
324
385
 
386
+ /**
387
+ * Handles the smooth following behavior for the spectator camera
388
+ */
325
389
  class SpectatorHandler implements ISpectatorHandler {
326
390
 
327
391
  readonly context: Context;
@@ -333,6 +397,7 @@ class SpectatorHandler implements ISpectatorHandler {
333
397
  private view?: PlayerView;
334
398
  private currentObject: Object3D | undefined;
335
399
 
400
+ /** Gets the currently targeted player view */
336
401
  get currentTarget(): PlayerView | undefined {
337
402
  return this.view;
338
403
  }
@@ -343,6 +408,10 @@ class SpectatorHandler implements ISpectatorHandler {
343
408
  this.spectator = spectator;
344
409
  }
345
410
 
411
+ /**
412
+ * Sets the target player view to follow
413
+ * @param view The PlayerView to follow
414
+ */
346
415
  set(view?: PlayerView): void {
347
416
  const followObject = view?.currentObject;
348
417
  if (!followObject) {
@@ -368,6 +437,7 @@ class SpectatorHandler implements ISpectatorHandler {
368
437
  else this.context.removeCamera(this.cam as ICamera);
369
438
  }
370
439
 
440
+ /** Disables the spectator following behavior */
371
441
  disable() {
372
442
  if (debug) console.log("STOP FOLLOW", this.currentObject);
373
443
  this.view = undefined;
@@ -377,12 +447,17 @@ class SpectatorHandler implements ISpectatorHandler {
377
447
  this.follow.enabled = false;
378
448
  }
379
449
 
450
+ /** Cleans up resources used by the handler */
380
451
  destroy() {
381
452
  this.target?.removeFromParent();
382
453
  if (this.follow)
383
454
  GameObject.destroy(this.follow);
384
455
  }
385
456
 
457
+ /**
458
+ * Updates the camera position and orientation based on the spectator mode
459
+ * @param mode The current spectator mode (first or third person)
460
+ */
386
461
  update(mode: SpectatorMode) {
387
462
  if (this.currentTarget?.isConnected === false || this.currentTarget?.removed === true) {
388
463
  if (debug) console.log("Target disconnected or timeout", this.currentTarget);
@@ -431,13 +506,13 @@ class SpectatorHandler implements ISpectatorHandler {
431
506
  target.quaternion.copy(_inverseYQuat);
432
507
  else target.quaternion.identity();
433
508
  }
434
-
435
-
436
509
  }
437
510
 
438
511
  const _inverseYQuat = new Quaternion().setFromAxisAngle(new Vector3(0, 1, 0), Math.PI);
439
512
 
440
-
513
+ /**
514
+ * Handles user input for selecting targets to spectate
515
+ */
441
516
  class SpectatorSelectionController {
442
517
 
443
518
  private readonly context: Context;
@@ -468,6 +543,9 @@ class SpectatorSelectionController {
468
543
  });
469
544
  }
470
545
 
546
+ /**
547
+ * Attempts to select an avatar to spectate through raycasting
548
+ */
471
549
  private trySelectObject() {
472
550
  const opts = new RaycastOptions();
473
551
  opts.setMask(0xffffff);
@@ -491,17 +569,17 @@ class SpectatorSelectionController {
491
569
  }
492
570
  }
493
571
 
494
-
495
-
496
-
497
-
572
+ /**
573
+ * Network model for communicating follower changes
574
+ */
498
575
  class SpectatorFollowerChangedEventModel implements IModel {
499
- /** the user that is following */
576
+ /** The user ID that is following */
500
577
  guid: string;
501
578
  readonly dontSave: boolean = true;
502
579
 
503
- /** the user being followed */
580
+ /** The user ID being followed */
504
581
  targetUserId: string | undefined;
582
+ /** Indicates if the user stopped following */
505
583
  stoppedFollowing: boolean;
506
584
 
507
585
  constructor(connectionId: string, userId: string | undefined, stoppedFollowing: boolean) {
@@ -511,6 +589,9 @@ class SpectatorFollowerChangedEventModel implements IModel {
511
589
  }
512
590
  }
513
591
 
592
+ /**
593
+ * Network model for requesting users to follow a specific player
594
+ */
514
595
  class SpectatorFollowEventModel implements IModel {
515
596
  guid: string;
516
597
  userId: string | undefined;
@@ -521,11 +602,14 @@ class SpectatorFollowEventModel implements IModel {
521
602
  }
522
603
  }
523
604
 
605
+ /**
606
+ * Handles network communication for spectator functionality
607
+ */
524
608
  class SpectatorCamNetworking {
525
609
 
610
+ /** List of user IDs currently following this player */
526
611
  readonly followers: string[] = [];
527
612
 
528
-
529
613
  private readonly context: Context;
530
614
  private readonly spectator: SpectatorCamera;
531
615
  private _followerEventMethod: Function;
@@ -540,6 +624,9 @@ class SpectatorCamNetworking {
540
624
  this._joinedRoomMethod = this.onUserJoinedRoom.bind(this);
541
625
  }
542
626
 
627
+ /**
628
+ * Initializes network event listeners
629
+ */
543
630
  awake() {
544
631
  this.context.connection.beginListen("spectator-follower-changed", this._followerEventMethod);
545
632
  this.context.connection.beginListen("spectator-request-follow", this._requestFollowMethod);
@@ -555,12 +642,20 @@ class SpectatorCamNetworking {
555
642
  });
556
643
  }
557
644
 
645
+ /**
646
+ * Removes network event listeners
647
+ */
558
648
  destroy() {
559
649
  this.context.connection.stopListen("spectator-follower-changed", this._followerEventMethod);
560
650
  this.context.connection.stopListen("spectator-request-follow", this._requestFollowMethod);
561
651
  this.context.connection.stopListen(RoomEvents.JoinedRoom, this._joinedRoomMethod);
562
652
  }
563
653
 
654
+ /**
655
+ * Notifies other users about spectating target changes
656
+ * @param target The new target being spectated
657
+ * @param _prevId The previous target's user ID
658
+ */
564
659
  onSpectatedObjectChanged(target: PlayerView | undefined, _prevId?: string) {
565
660
  if (debug)
566
661
  console.log(this.context.connection.connectionId, "onSpectatedObjectChanged", target, _prevId);
@@ -572,6 +667,10 @@ class SpectatorCamNetworking {
572
667
  }
573
668
  }
574
669
 
670
+ /**
671
+ * Requests other users to follow this player or stop following
672
+ * @param stop Whether to request users to stop following
673
+ */
575
674
  onRequestFollowMe(stop: boolean = false) {
576
675
  if (debug)
577
676
  console.log("Request follow", this.context.connection.connectionId);
@@ -583,12 +682,19 @@ class SpectatorCamNetworking {
583
682
  }
584
683
  }
585
684
 
685
+ /**
686
+ * Handles room join events
687
+ */
586
688
  private onUserJoinedRoom() {
587
689
  if (getParam("followme")) {
588
690
  this.onRequestFollowMe();
589
691
  }
590
692
  }
591
693
 
694
+ /**
695
+ * Processes follower status change events from the network
696
+ * @param evt The follower change event data
697
+ */
592
698
  private onFollowerEvent(evt: SpectatorFollowerChangedEventModel) {
593
699
  const userBeingFollowed = evt.targetUserId;
594
700
  const userThatIsFollowing = evt.guid;
@@ -615,6 +721,9 @@ class SpectatorCamNetworking {
615
721
  }
616
722
  }
617
723
 
724
+ /**
725
+ * Removes followers that are no longer connected to the room
726
+ */
618
727
  private removeDisconnectedFollowers() {
619
728
  for (let i = this.followers.length - 1; i >= 0; i--) {
620
729
  const id = this.followers[i];
@@ -626,6 +735,11 @@ class SpectatorCamNetworking {
626
735
 
627
736
  private _lastRequestFollowUser: SpectatorFollowEventModel | undefined;
628
737
 
738
+ /**
739
+ * Handles follow requests from other users
740
+ * @param evt The follow request event
741
+ * @returns True if the request was handled successfully
742
+ */
629
743
  private onRequestFollowEvent(evt: SpectatorFollowEventModel) {
630
744
  this._lastRequestFollowUser = evt;
631
745
 
@@ -652,6 +766,10 @@ class SpectatorCamNetworking {
652
766
  }
653
767
 
654
768
  private _enforceFollowInterval: any;
769
+
770
+ /**
771
+ * Periodically retries following a user if the initial attempt failed
772
+ */
655
773
  private enforceFollow() {
656
774
  if (this._enforceFollowInterval) return;
657
775
  this._enforceFollowInterval = setInterval(() => {
@@ -19,7 +19,12 @@ registerBinaryType(SyncedTransformIdentifier, SyncedTransformModel.getRootAsSync
19
19
 
20
20
  const builder = new flatbuffers.Builder();
21
21
 
22
- /** Creates a flatbuffer model containing the transform data of a game object. Used by {@link SyncedTransform}
22
+ /**
23
+ * Creates a flatbuffer model containing the transform data of a game object. Used by {@link SyncedTransform}
24
+ * @param guid The unique identifier of the object to sync
25
+ * @param b The behavior component containing transform data
26
+ * @param fast Whether to use fast mode synchronization (syncs more frequently)
27
+ * @returns A Uint8Array containing the serialized transform data
23
28
  */
24
29
  export function createTransformModel(guid: string, b: Behaviour, fast: boolean = true): Uint8Array {
25
30
  builder.clear();
@@ -50,18 +55,28 @@ onUpdate((ctx) => {
50
55
  })
51
56
 
52
57
  /**
53
- * SyncedTransform is a behaviour that syncs the transform of a game object over the network.
58
+ * SyncedTransform synchronizes the position and rotation of a game object over the network.
59
+ * It handles ownership transfer, interpolation, and network state updates automatically.
54
60
  * @category Networking
55
61
  * @group Components
56
62
  */
57
63
  export class SyncedTransform extends Behaviour {
58
64
 
59
-
65
+
60
66
  // public autoOwnership: boolean = true;
67
+ /** When true, overrides physics behavior when this object is owned by the local user */
61
68
  public overridePhysics: boolean = true
69
+
70
+ /** Whether to smoothly interpolate position changes when receiving updates */
62
71
  public interpolatePosition: boolean = true;
72
+
73
+ /** Whether to smoothly interpolate rotation changes when receiving updates */
63
74
  public interpolateRotation: boolean = true;
75
+
76
+ /** When true, sends updates at a higher frequency, useful for fast-moving objects */
64
77
  public fastMode: boolean = false;
78
+
79
+ /** When true, notifies other clients when this object is destroyed */
65
80
  public syncDestroy: boolean = false;
66
81
 
67
82
  // private _state!: SyncedTransformModel;
@@ -77,7 +92,10 @@ export class SyncedTransform extends Behaviour {
77
92
  private _receivedFastUpdate: boolean = false;
78
93
  private _shouldRequestOwnership: boolean = false;
79
94
 
80
- /** Request ownership of an object - you need to be connected to a room */
95
+ /**
96
+ * Requests ownership of this object on the network.
97
+ * You need to be connected to a room for this to work.
98
+ */
81
99
  public requestOwnership() {
82
100
  if (debug)
83
101
  console.log("Request ownership");
@@ -89,10 +107,18 @@ export class SyncedTransform extends Behaviour {
89
107
  this._model.requestOwnership();
90
108
  }
91
109
 
110
+ /**
111
+ * Checks if this client has ownership of the object
112
+ * @returns true if this client has ownership, false if not, undefined if ownership state is unknown
113
+ */
92
114
  public hasOwnership(): boolean | undefined {
93
115
  return this._model?.hasOwnership ?? undefined;
94
116
  }
95
117
 
118
+ /**
119
+ * Checks if the object is owned by any client
120
+ * @returns true if the object is owned, false if not, undefined if ownership state is unknown
121
+ */
96
122
  public isOwned(): boolean | undefined {
97
123
  return this._model?.isOwned;
98
124
  }
@@ -140,6 +166,9 @@ export class SyncedTransform extends Behaviour {
140
166
  this.context.connection.stopListenBinary(SyncedTransformIdentifier, this.receivedDataCallback);
141
167
  }
142
168
 
169
+ /**
170
+ * Attempts to retrieve and apply the last known network state for this transform
171
+ */
143
172
  private tryGetLastState() {
144
173
  const model = this.context.connection.tryGetState(this.guid) as unknown as SyncedTransformModel;
145
174
  if (model) this.onReceivedData(model);
@@ -147,6 +176,10 @@ export class SyncedTransform extends Behaviour {
147
176
 
148
177
  private tempEuler: Euler = new Euler();
149
178
 
179
+ /**
180
+ * Handles incoming network data for this transform
181
+ * @param data The model containing transform information
182
+ */
150
183
  private onReceivedData(data: SyncedTransformModel) {
151
184
  if (this.destroyed) return;
152
185
  if (typeof data.guid === "function" && data.guid() === this.guid) {
@@ -183,7 +216,10 @@ export class SyncedTransform extends Behaviour {
183
216
  }
184
217
  }
185
218
 
186
- /** @internal */
219
+ /**
220
+ * @internal
221
+ * Initializes tracking of position and rotation when component is enabled
222
+ */
187
223
  onEnable(): void {
188
224
  this.lastWorldPos.copy(this.worldPosition);
189
225
  this.lastWorldRotation.copy(this.worldQuaternion);
@@ -194,7 +230,10 @@ export class SyncedTransform extends Behaviour {
194
230
  }
195
231
  }
196
232
 
197
- /** @internal */
233
+ /**
234
+ * @internal
235
+ * Releases ownership when component is disabled
236
+ */
198
237
  onDisable(): void {
199
238
  if (this._model)
200
239
  this._model.freeOwnership();
@@ -205,7 +244,11 @@ export class SyncedTransform extends Behaviour {
205
244
  private lastWorldPos!: Vector3;
206
245
  private lastWorldRotation!: Quaternion;
207
246
 
208
- /** @internal */
247
+ /**
248
+ * @internal
249
+ * Handles transform synchronization before each render frame
250
+ * Sends updates when owner, receives and applies updates when not owner
251
+ */
209
252
  onBeforeRender() {
210
253
  if (!this.activeAndEnabled || !this.context.connection.isConnected) return;
211
254
  // console.log("BEFORE RENDER", this.destroyed, this.guid, this._model?.isOwned, this.name, this.gameObject);
@@ -8,27 +8,43 @@ import { OrbitControls } from "./OrbitControls.js";
8
8
  import { SyncedTransform } from "./SyncedTransform.js";
9
9
 
10
10
  /**
11
- * TransformGizmo is a component that displays a gizmo for transforming the object in the scene.
11
+ * TransformGizmo displays manipulation controls for translating, rotating, and scaling objects in the scene.
12
+ * It wraps three.js {@link TransformControls} and provides keyboard shortcuts for changing modes and settings.
12
13
  * @category Helpers
13
14
  * @group Components
14
15
  */
15
16
  export class TransformGizmo extends Behaviour {
16
17
 
18
+ /**
19
+ * When true, this is considered a helper gizmo and will only be shown if showGizmos is enabled in engine parameters.
20
+ */
17
21
  @serializable()
18
22
  public isGizmo: boolean = false;
19
23
 
24
+ /**
25
+ * Specifies the translation grid snap value in world units.
26
+ * Applied when holding Shift while translating an object.
27
+ */
20
28
  @serializable()
21
29
  public translationSnap: number = 1;
22
30
 
31
+ /**
32
+ * Specifies the rotation snap angle in degrees.
33
+ * Applied when holding Shift while rotating an object.
34
+ */
23
35
  @serializable()
24
36
  public rotationSnapAngle: number = 15;
25
37
 
38
+ /**
39
+ * Specifies the scale snapping value.
40
+ * Applied when holding Shift while scaling an object.
41
+ */
26
42
  @serializable()
27
43
  public scaleSnap: number = .25;
28
44
 
29
45
  /**
30
- * Get the underlying three.js TransformControls instance.
31
- * @returns The TransformControls instance.
46
+ * Gets the underlying three.js {@link TransformControls} instance.
47
+ * @returns The TransformControls instance or undefined if not initialized.
32
48
  */
33
49
  get control() {
34
50
  return this._control;
@@ -81,6 +97,10 @@ export class TransformGizmo extends Behaviour {
81
97
  window.removeEventListener('keyup', this.windowKeyUpListener);
82
98
  }
83
99
 
100
+ /**
101
+ * Enables grid snapping for transform operations according to set snap values.
102
+ * This applies the translationSnap, rotationSnapAngle, and scaleSnap properties to the controls.
103
+ */
84
104
  enableSnapping() {
85
105
  if (this._control) {
86
106
  this._control.setTranslationSnap(this.translationSnap);
@@ -89,6 +109,10 @@ export class TransformGizmo extends Behaviour {
89
109
  }
90
110
  }
91
111
 
112
+ /**
113
+ * Disables grid snapping for transform operations.
114
+ * Removes all snapping constraints from the transform controls.
115
+ */
92
116
  disableSnapping() {
93
117
  if (this._control) {
94
118
  this._control.setTranslationSnap(null);
@@ -97,6 +121,11 @@ export class TransformGizmo extends Behaviour {
97
121
  }
98
122
  }
99
123
 
124
+ /**
125
+ * Event handler for when dragging state changes.
126
+ * Disables orbit controls during dragging and requests ownership of the transform if it's synchronized.
127
+ * @param event The drag change event
128
+ */
100
129
  private onControlChangedEvent = (event) => {
101
130
  const orbit = this.orbit;
102
131
  if (orbit) orbit.enabled = !event.value;
@@ -109,7 +138,18 @@ export class TransformGizmo extends Behaviour {
109
138
  }
110
139
  }
111
140
 
112
-
141
+ /**
142
+ * Handles keyboard shortcuts for transform operations:
143
+ * - Q: Toggle local/world space
144
+ * - W: Translation mode
145
+ * - E: Rotation mode
146
+ * - R: Scale mode
147
+ * - Shift: Enable snapping (while held)
148
+ * - +/-: Adjust gizmo size
149
+ * - X/Y/Z: Toggle visibility of respective axis
150
+ * - Spacebar: Toggle controls enabled state
151
+ * @param event The keyboard event
152
+ */
113
153
  private windowKeyDownListener = (event) => {
114
154
  if (!this.enabled) return;
115
155
  if (!this._control) return;
@@ -162,6 +202,11 @@ export class TransformGizmo extends Behaviour {
162
202
  }
163
203
  }
164
204
 
205
+ /**
206
+ * Handles keyboard key release events.
207
+ * Currently only handles releasing Shift key to disable snapping.
208
+ * @param event The keyboard event
209
+ */
165
210
  private windowKeyUpListener = (event) => {
166
211
  if (!this.enabled) return;
167
212
  switch (event.keyCode) {