@needle-tools/engine 4.3.0-alpha → 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 (101) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/needle-engine.bundle.js +1467 -222
  3. package/dist/needle-engine.bundle.light.js +1467 -222
  4. package/dist/needle-engine.bundle.light.min.js +32 -32
  5. package/dist/needle-engine.bundle.light.umd.cjs +3 -3
  6. package/dist/needle-engine.bundle.min.js +3 -3
  7. package/dist/needle-engine.bundle.umd.cjs +3 -3
  8. package/dist/needle-engine.light.d.ts +9 -9
  9. package/lib/engine/engine_types.d.ts +162 -17
  10. package/lib/engine-components/Animator.d.ts +129 -21
  11. package/lib/engine-components/Animator.js +115 -21
  12. package/lib/engine-components/Animator.js.map +1 -1
  13. package/lib/engine-components/AnimatorController.d.ts +161 -32
  14. package/lib/engine-components/AnimatorController.js +176 -29
  15. package/lib/engine-components/AnimatorController.js.map +1 -1
  16. package/lib/engine-components/AudioListener.d.ts +16 -5
  17. package/lib/engine-components/AudioListener.js +16 -5
  18. package/lib/engine-components/AudioListener.js.map +1 -1
  19. package/lib/engine-components/AudioSource.d.ts +120 -28
  20. package/lib/engine-components/AudioSource.js +120 -37
  21. package/lib/engine-components/AudioSource.js.map +1 -1
  22. package/lib/engine-components/AvatarLoader.d.ts +61 -0
  23. package/lib/engine-components/AvatarLoader.js +61 -1
  24. package/lib/engine-components/AvatarLoader.js.map +1 -1
  25. package/lib/engine-components/AxesHelper.d.ts +19 -1
  26. package/lib/engine-components/AxesHelper.js +19 -1
  27. package/lib/engine-components/AxesHelper.js.map +1 -1
  28. package/lib/engine-components/BoxHelperComponent.d.ts +26 -0
  29. package/lib/engine-components/BoxHelperComponent.js +26 -0
  30. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  31. package/lib/engine-components/Camera.d.ts +126 -37
  32. package/lib/engine-components/Camera.js +139 -37
  33. package/lib/engine-components/Camera.js.map +1 -1
  34. package/lib/engine-components/CameraUtils.js +20 -0
  35. package/lib/engine-components/CameraUtils.js.map +1 -1
  36. package/lib/engine-components/Collider.d.ts +95 -21
  37. package/lib/engine-components/Collider.js +100 -23
  38. package/lib/engine-components/Collider.js.map +1 -1
  39. package/lib/engine-components/Component.d.ts +554 -106
  40. package/lib/engine-components/Component.js +352 -81
  41. package/lib/engine-components/Component.js.map +1 -1
  42. package/lib/engine-components/DragControls.d.ts +95 -21
  43. package/lib/engine-components/DragControls.js +126 -32
  44. package/lib/engine-components/DragControls.js.map +1 -1
  45. package/lib/engine-components/DropListener.d.ts +99 -16
  46. package/lib/engine-components/DropListener.js +119 -14
  47. package/lib/engine-components/DropListener.js.map +1 -1
  48. package/lib/engine-components/Light.d.ts +102 -5
  49. package/lib/engine-components/Light.js +102 -44
  50. package/lib/engine-components/Light.js.map +1 -1
  51. package/lib/engine-components/NeedleMenu.d.ts +28 -11
  52. package/lib/engine-components/NeedleMenu.js +28 -11
  53. package/lib/engine-components/NeedleMenu.js.map +1 -1
  54. package/lib/engine-components/Networking.d.ts +37 -5
  55. package/lib/engine-components/Networking.js +37 -5
  56. package/lib/engine-components/Networking.js.map +1 -1
  57. package/lib/engine-components/SceneSwitcher.js +44 -0
  58. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  59. package/lib/engine-components/SpatialTrigger.d.ts +66 -1
  60. package/lib/engine-components/SpatialTrigger.js +74 -2
  61. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  62. package/lib/engine-components/SpectatorCamera.d.ts +66 -4
  63. package/lib/engine-components/SpectatorCamera.js +132 -6
  64. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  65. package/lib/engine-components/SyncedTransform.d.ts +45 -6
  66. package/lib/engine-components/SyncedTransform.js +45 -6
  67. package/lib/engine-components/SyncedTransform.js.map +1 -1
  68. package/lib/engine-components/TransformGizmo.d.ts +49 -3
  69. package/lib/engine-components/TransformGizmo.js +49 -3
  70. package/lib/engine-components/TransformGizmo.js.map +1 -1
  71. package/lib/engine-components/webxr/WebXR.d.ts +131 -22
  72. package/lib/engine-components/webxr/WebXR.js +132 -23
  73. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  74. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +82 -9
  75. package/lib/engine-components-experimental/networking/PlayerSync.js +76 -11
  76. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  77. package/package.json +1 -1
  78. package/src/engine/engine_types.ts +179 -18
  79. package/src/engine-components/Animator.ts +142 -22
  80. package/src/engine-components/AnimatorController.ts +184 -34
  81. package/src/engine-components/AudioListener.ts +16 -5
  82. package/src/engine-components/AudioSource.ts +126 -37
  83. package/src/engine-components/AvatarLoader.ts +61 -2
  84. package/src/engine-components/AxesHelper.ts +21 -1
  85. package/src/engine-components/BoxHelperComponent.ts +26 -0
  86. package/src/engine-components/Camera.ts +147 -41
  87. package/src/engine-components/CameraUtils.ts +20 -0
  88. package/src/engine-components/Collider.ts +102 -27
  89. package/src/engine-components/Component.ts +605 -129
  90. package/src/engine-components/DragControls.ts +134 -38
  91. package/src/engine-components/DropListener.ts +143 -23
  92. package/src/engine-components/Light.ts +105 -44
  93. package/src/engine-components/NeedleMenu.ts +29 -11
  94. package/src/engine-components/Networking.ts +37 -6
  95. package/src/engine-components/SceneSwitcher.ts +48 -1
  96. package/src/engine-components/SpatialTrigger.ts +80 -3
  97. package/src/engine-components/SpectatorCamera.ts +136 -18
  98. package/src/engine-components/SyncedTransform.ts +50 -7
  99. package/src/engine-components/TransformGizmo.ts +49 -4
  100. package/src/engine-components/webxr/WebXR.ts +144 -27
  101. package/src/engine-components-experimental/networking/PlayerSync.ts +85 -13
@@ -19,63 +19,104 @@ import { Animation } from "./Animation.js";
19
19
  import { Behaviour } from "./Component.js";
20
20
  import { EventList } from "./EventList.js";
21
21
 
22
+ /**
23
+ * Debug mode can be enabled with the URL parameter `?debugdroplistener`, which
24
+ * logs additional information during drag and drop events and visualizes hit points.
25
+ */
22
26
  const debug = getParam("debugdroplistener");
23
27
 
28
+ /**
29
+ * Events dispatched by the DropListener component
30
+ * @enum {string}
31
+ */
24
32
  export enum DropListenerEvents {
25
33
  /**
26
- * Dispatched when a file is dropped into the scene. The detail of the event is the file that was dropped.
34
+ * Dispatched when a file is dropped into the scene. The detail of the event is the {@link File} that was dropped.
35
+ * The event is called once for each dropped file.
27
36
  */
28
37
  FileDropped = "file-dropped",
29
38
  /**
30
- * Dispatched when a new object is added to the scene. The detail of the event is the glTF that was added.
39
+ * Dispatched when a new object is added to the scene. The detail of the event contains {@link DropListenerOnDropArguments} for the content that was added.
31
40
  */
32
41
  ObjectAdded = "object-added",
33
42
  }
34
43
 
44
+ /**
45
+ * Context information for a drop operation
46
+ */
35
47
  declare type DropContext = {
48
+ /** Position where the file was dropped in screen coordinates */
36
49
  screenposition: Vector2;
50
+ /** URL of the dropped content, if applicable */
37
51
  url?: string,
52
+ /** File object of the dropped content, if applicable */
38
53
  file?: File;
54
+ /** 3D position where the content should be placed */
39
55
  point?: Vec3;
56
+ /** Size dimensions for the content */
40
57
  size?: Vec3;
41
58
  }
42
59
 
43
60
 
44
- /** Networking event arguments for the DropListener component */
61
+ /**
62
+ * Network event arguments passed between clients when using the DropListener with networking
63
+ */
45
64
  export declare type DropListenerNetworkEventArguments = {
65
+ /** Unique identifier of the sender */
46
66
  guid: string,
67
+ /** Name of the dropped object */
47
68
  name: string,
69
+ /** URL or array of URLs to the dropped content */
48
70
  url: string | string[],
49
71
  /** Worldspace point where the object was placed in the scene */
50
72
  point: Vec3;
51
73
  /** Bounding box size */
52
74
  size: Vec3;
75
+ /** MD5 hash of the content for verification */
53
76
  contentMD5: string;
54
77
  }
55
78
 
79
+ /**
80
+ * Arguments provided to handlers when an object is dropped or added to the scene
81
+ */
56
82
  export declare type DropListenerOnDropArguments = {
83
+ /** The DropListener component that processed the drop event */
57
84
  sender: DropListener,
58
- /** the root object added to the scene */
85
+ /** The root object added to the scene */
59
86
  object: Object3D,
60
- /** The whole dropped model */
87
+ /** The complete model with all associated data */
61
88
  model: Model,
89
+ /** MD5 hash of the content for verification */
62
90
  contentMD5: string;
91
+ /** The original dropped URL or File object */
63
92
  dropped: URL | File | undefined;
64
93
  }
65
94
 
66
- /** Dispatched when an object is dropped/changed */
95
+ /**
96
+ * CustomEvent dispatched when an object is added to the scene via the DropListener
97
+ */
67
98
  class DropListenerAddedEvent<T extends DropListenerOnDropArguments> extends CustomEvent<T> {
99
+ /**
100
+ * Creates a new added event with the provided details
101
+ * @param detail Information about the added object
102
+ */
68
103
  constructor(detail: T) {
69
104
  super(DropListenerEvents.ObjectAdded, { detail });
70
105
  }
71
106
  }
72
107
 
108
+ /**
109
+ * Key name used for blob storage parameters
110
+ */
73
111
  const blobKeyName = "blob";
74
112
 
75
113
  /** The DropListener component is used to listen for drag and drop events in the browser and add the dropped files to the scene
76
114
  * It can be used to allow users to drag and drop glTF files into the scene to add new objects.
77
115
  *
78
- * ## Events
116
+ * If {@link useNetworking} is enabled, the DropListener will automatically synchronize dropped files to other connected clients.
117
+ * Enable {@link fitIntoVolume} to automatically scale dropped objects to fit within the volume defined by {@link fitVolumeSize}.
118
+ *
119
+ * The following events are dispatched by the DropListener:
79
120
  * - **object-added** - dispatched when a new object is added to the scene
80
121
  * - **file-dropped** - dispatched when a file is dropped into the scene
81
122
  *
@@ -103,42 +144,46 @@ const blobKeyName = "blob";
103
144
  export class DropListener extends Behaviour {
104
145
 
105
146
  /**
106
- * When enabled the DropListener will automatically network dropped files to other clients.
147
+ * When enabled, the DropListener will automatically synchronize dropped files to other connected clients.
148
+ * When a file is dropped locally, it will be uploaded to blob storage and the URL will be shared with other clients.
107
149
  */
108
150
  @serializable()
109
151
  useNetworking: boolean = true;
110
152
 
111
153
  /**
112
- * When assigned the Droplistener will only accept files that are dropped on this object.
154
+ * When assigned, the DropListener will only accept files that are dropped on this specific object.
155
+ * This allows creating designated drop zones in your scene.
113
156
  */
114
157
  @serializable(Object3D)
115
158
  dropArea?: Object3D;
116
159
 
117
160
  /**
118
- * When enabled the object will be fitted into a volume. Use {@link fitVolumeSize} to specify the volume size.
161
+ * When enabled, dropped objects will be automatically scaled to fit within the volume defined by fitVolumeSize.
162
+ * Useful for ensuring dropped models appear at an appropriate scale.
119
163
  * @default false
120
164
  */
121
165
  @serializable()
122
166
  fitIntoVolume: boolean = false;
123
167
 
124
168
  /**
125
- * The volume size will be used to fit the object into the volume. Use {@link fitIntoVolume} to enable this feature.
169
+ * Defines the dimensions of the volume that dropped objects will be scaled to fit within.
170
+ * Only used when fitIntoVolume is enabled.
126
171
  */
127
172
  @serializable(Vector3)
128
173
  fitVolumeSize = new Vector3(1, 1, 1);
129
174
 
130
- /** When enabled the object will be placed at the drop position (under the cursor)
175
+ /**
176
+ * When enabled, dropped objects will be positioned at the point where the cursor hit the scene.
177
+ * When disabled, objects will be placed at the origin of the DropListener.
131
178
  * @default true
132
179
  */
133
180
  @serializable()
134
181
  placeAtHitPosition: boolean = true;
135
182
 
136
-
137
183
  /**
138
- * Invoked after a file has been **added** to the scene.
139
- * Arguments are {@link DropListenerOnDropArguments}
184
+ * Event list that gets invoked after a file has been successfully added to the scene.
185
+ * Receives {@link DropListenerOnDropArguments} containing the added object and related information.
140
186
  * @event object-added
141
- * @param {DropListenerOnDropArguments} evt
142
187
  * @example
143
188
  * ```typescript
144
189
  * dropListener.onDropped.addEventListener((evt) => {
@@ -178,6 +223,10 @@ export class DropListener extends Behaviour {
178
223
  this.removePreviouslyAddedObjects(false);
179
224
  }
180
225
 
226
+ /**
227
+ * Handles network events received from other clients containing information about dropped objects
228
+ * @param evt Network event data containing object information, position, and content URL
229
+ */
181
230
  private onNetworkEvent = (evt: DropListenerNetworkEventArguments) => {
182
231
  if (!this.useNetworking) {
183
232
  if (debug) console.debug("[DropListener] Ignoring networked event because networking is disabled", evt);
@@ -199,6 +248,11 @@ export class DropListener extends Behaviour {
199
248
  }
200
249
  }
201
250
 
251
+ /**
252
+ * Handles clipboard paste events and processes them as potential URL drops
253
+ * Only URLs are processed by this handler, and only when editing is allowed
254
+ * @param evt The paste event
255
+ */
202
256
  private handlePaste = (evt: Event) => {
203
257
  if (this.context.connection.allowEditing === false) return;
204
258
  if (evt.defaultPrevented) return;
@@ -217,12 +271,22 @@ export class DropListener extends Behaviour {
217
271
  .catch(console.warn);
218
272
  }
219
273
 
274
+ /**
275
+ * Handles drag events over the renderer's canvas
276
+ * Prevents default behavior to enable drop events
277
+ * @param evt The drag event
278
+ */
220
279
  private onDrag = (evt: DragEvent) => {
221
280
  if (this.context.connection.allowEditing === false) return;
222
281
  // necessary to get drop event
223
282
  evt.preventDefault();
224
283
  }
225
284
 
285
+ /**
286
+ * Processes drop events to add files to the scene
287
+ * Handles both file drops and text/URL drops
288
+ * @param evt The drop event
289
+ */
226
290
  private onDrop = async (evt: DragEvent) => {
227
291
  if (this.context.connection.allowEditing === false) return;
228
292
 
@@ -266,6 +330,14 @@ export class DropListener extends Behaviour {
266
330
  }
267
331
  }
268
332
 
333
+ /**
334
+ * Processes a dropped or pasted URL and tries to load it as a 3D model
335
+ * Handles special cases like GitHub URLs and Polyhaven asset URLs
336
+ * @param url The URL to process
337
+ * @param ctx Context information about where the drop occurred
338
+ * @param isRemote Whether this URL was shared from a remote client
339
+ * @returns The added object or null if loading failed
340
+ */
269
341
  private async addFromUrl(url: string, ctx: DropContext, isRemote: boolean) {
270
342
  if (debug) console.log("dropped url", url);
271
343
 
@@ -315,6 +387,12 @@ export class DropListener extends Behaviour {
315
387
 
316
388
  private _abort: AbortController | null = null;
317
389
 
390
+ /**
391
+ * Processes dropped files, loads them as 3D models, and handles networking if enabled
392
+ * Creates an abort controller to cancel previous uploads if new files are dropped
393
+ * @param fileList Array of dropped files
394
+ * @param ctx Context information about where the drop occurred
395
+ */
318
396
  private async addDroppedFiles(fileList: Array<File>, ctx: DropContext) {
319
397
  if (debug) console.log("Add files", fileList)
320
398
  if (!Array.isArray(fileList)) return;
@@ -361,7 +439,10 @@ export class DropListener extends Behaviour {
361
439
  private readonly _addedObjects = new Array<Object3D>();
362
440
  private readonly _addedModels = new Array<Model>();
363
441
 
364
- /** Removes all previously added objects from the scene and removes those object references */
442
+ /**
443
+ * Removes all previously added objects from the scene
444
+ * @param doDestroy When true, destroys the objects; when false, just clears the references
445
+ */
365
446
  private removePreviouslyAddedObjects(doDestroy: boolean = true) {
366
447
  if (doDestroy) {
367
448
  for (const prev of this._addedObjects) {
@@ -375,7 +456,13 @@ export class DropListener extends Behaviour {
375
456
  }
376
457
 
377
458
  /**
378
- * Adds the object to the scene and fits it into the volume if {@link fitIntoVolume} is enabled.
459
+ * Adds a loaded model to the scene with proper positioning and scaling.
460
+ * Handles placement based on component settings and raycasting.
461
+ * If {@link fitIntoVolume} is enabled, the object will be scaled to fit within the volume defined by {@link fitVolumeSize}.
462
+ * @param data The loaded model data and content hash
463
+ * @param ctx Context information about where the drop occurred
464
+ * @param isRemote Whether this object was shared from a remote client
465
+ * @returns The added object or null if adding failed
379
466
  */
380
467
  private addObject(data: { model: Model, contentMD5: string }, ctx: DropContext, isRemote: boolean): Object3D | null {
381
468
 
@@ -444,6 +531,13 @@ export class DropListener extends Behaviour {
444
531
  return obj;
445
532
  }
446
533
 
534
+ /**
535
+ * Sends a network event to other clients about a dropped object
536
+ * Only triggered when networking is enabled and the connection is established
537
+ * @param url The URL to the content that was dropped
538
+ * @param obj The object that was added to the scene
539
+ * @param contentmd5 The content hash for verification
540
+ */
447
541
  private async sendDropEvent(url: string, obj: Object3D, contentmd5: string) {
448
542
  if (!this.useNetworking) {
449
543
  if (debug) console.debug("[DropListener] Ignoring networked event because networking is disabled", url);
@@ -463,12 +557,20 @@ export class DropListener extends Behaviour {
463
557
  this.context.connection.send("droplistener", evt);
464
558
  }
465
559
  }
560
+
561
+ /**
562
+ * Deletes remote state for this DropListener's objects
563
+ * Called when new files are dropped to clean up previous state
564
+ */
466
565
  private deleteDropEvent() {
467
566
  this.context.connection.sendDeleteRemoteState(this.guid);
468
567
  }
469
568
 
470
-
471
-
569
+ /**
570
+ * Tests if a drop event occurred within the designated drop area if one is specified
571
+ * @param ctx The drop context containing screen position information
572
+ * @returns True if the drop is valid (either no drop area is set or the drop occurred inside it)
573
+ */
472
574
  private testIfIsInDropArea(ctx: DropContext): boolean {
473
575
  if (this.dropArea) {
474
576
  const screenPoint = this.context.input.convertScreenspaceToRaycastSpace(ctx.screenposition.clone());
@@ -492,7 +594,11 @@ export class DropListener extends Behaviour {
492
594
 
493
595
  }
494
596
 
495
-
597
+ /**
598
+ * Attempts to convert a Polyhaven website URL to a direct glTF model download URL
599
+ * @param urlStr The original Polyhaven URL
600
+ * @returns The direct download URL for the glTF model if it's a valid Polyhaven asset URL, otherwise returns the original URL
601
+ */
496
602
  function tryResolvePolyhavenAssetUrl(urlStr: string) {
497
603
  if (!urlStr.startsWith("https://polyhaven.com/")) return urlStr;
498
604
  // Handle dropping polyhaven image url
@@ -506,10 +612,18 @@ function tryResolvePolyhavenAssetUrl(urlStr: string) {
506
612
  return assetUrl;
507
613
  }
508
614
 
509
-
510
-
615
+ /**
616
+ * Helper namespace for loading files and models from various sources
617
+ */
511
618
  namespace FileHelper {
512
619
 
620
+ /**
621
+ * Loads and processes a File object into a 3D model
622
+ * @param file The file to load (supported formats: gltf, glb, fbx, obj, usdz, vrm)
623
+ * @param context The application context
624
+ * @param args Additional arguments including a unique guid for instantiation
625
+ * @returns Promise containing the loaded model and its content hash, or null if loading failed
626
+ */
513
627
  export async function loadFile(file: File, context: Context, args: { guid: string }): Promise<{ model: Model, contentMD5: string } | null> {
514
628
  const name = file.name.toLowerCase();
515
629
  if (name.endsWith(".gltf") ||
@@ -544,6 +658,12 @@ namespace FileHelper {
544
658
  return null;
545
659
  }
546
660
 
661
+ /**
662
+ * Loads a 3D model from a URL with progress visualization
663
+ * @param url The URL to load the model from
664
+ * @param args Arguments including context, parent object, and optional placement information
665
+ * @returns Promise containing the loaded model and its content hash, or null if loading failed
666
+ */
547
667
  export async function loadFileFromURL(url: URL, args: { guid: string, context: Context, parent: Object3D, point?: Vec3, size?: Vec3 }): Promise<{ model: Model, contentMD5: string } | null> {
548
668
  return new Promise(async (resolve, _reject) => {
549
669
 
@@ -24,82 +24,86 @@ const shadowMaxDistance = 300;
24
24
  const debug = getParam("debuglights");
25
25
 
26
26
 
27
- /// <summary>
28
- /// <para>The type of a Light.</para>
29
- /// </summary>
27
+ /**
28
+ * Defines the type of light in a scene.
29
+ */
30
30
  export enum LightType {
31
- /// <summary>
32
- /// <para>The light is a spot light.</para>
33
- /// </summary>
31
+ /** Spot light that emits light in a cone shape */
34
32
  Spot = 0,
35
- /// <summary>
36
- /// <para>The light is a directional light.</para>
37
- /// </summary>
33
+ /** Directional light that emits parallel light rays in a specific direction */
38
34
  Directional = 1,
39
- /// <summary>
40
- /// <para>The light is a point light.</para>
41
- /// </summary>
35
+ /** Point light that emits light in all directions from a single point */
42
36
  Point = 2,
37
+ /** Area light */
43
38
  Area = 3,
44
- /// <summary>
45
- /// <para>The light is a rectangle shaped area light. It affects only baked lightmaps and lightprobes.</para>
46
- /// </summary>
39
+ /** Rectangle shaped area light that only affects baked lightmaps and light probes */
47
40
  Rectangle = 3,
48
- /// <summary>
49
- /// <para>The light is a disc shaped area light. It affects only baked lightmaps and lightprobes.</para>
50
- /// </summary>
41
+ /** Disc shaped area light that only affects baked lightmaps and light probes */
51
42
  Disc = 4,
52
43
  }
44
+
45
+ /**
46
+ * Defines how a light contributes to the scene lighting.
47
+ */
53
48
  export enum LightmapBakeType {
54
- /// <summary>
55
- /// <para>Realtime lights cast run time light and shadows. They can change position, orientation, color, brightness, and many other properties at run time. No lighting gets baked into lightmaps or light probes..</para>
56
- /// </summary>
49
+ /** Light affects the scene in real-time with no baking */
57
50
  Realtime = 4,
58
- /// <summary>
59
- /// <para>Baked lights cannot move or change in any way during run time. All lighting for static objects gets baked into lightmaps. Lighting and shadows for dynamic objects gets baked into Light Probes.</para>
60
- /// </summary>
51
+ /** Light is completely baked into lightmaps and light probes */
61
52
  Baked = 2,
62
- /// <summary>
63
- /// <para>Mixed lights allow a mix of realtime and baked lighting, based on the Mixed Lighting Mode used. These lights cannot move, but can change color and intensity at run time. Changes to color and intensity only affect direct lighting as indirect lighting gets baked. If using Subtractive mode, changes to color or intensity are not calculated at run time on static objects.</para>
64
- /// </summary>
53
+ /** Combines aspects of realtime and baked lighting */
65
54
  Mixed = 1,
66
55
  }
67
56
 
68
- /// <summary>
69
- /// <para>Shadow casting options for a Light.</para>
70
- /// </summary>
57
+ /**
58
+ * Defines the shadow casting options for a Light.
59
+ * @enum {number}
60
+ */
71
61
  enum LightShadows {
72
- /// <summary>
73
- /// <para>Do not cast shadows (default).</para>
74
- /// </summary>
62
+ /** No shadows are cast */
75
63
  None = 0,
76
- /// <summary>
77
- /// <para>Cast "hard" shadows (with no shadow filtering).</para>
78
- /// </summary>
64
+ /** Hard-edged shadows without filtering */
79
65
  Hard = 1,
80
- /// <summary>
81
- /// <para>Cast "soft" shadows (with 4x PCF filtering).</para>
82
- /// </summary>
66
+ /** Soft shadows with PCF filtering */
83
67
  Soft = 2,
84
68
  }
85
69
 
86
- /** The Light component can be used to create a light source in the scene.
87
- * It can be used to create a directional light, a spot light or a point light.
88
- * The light can be set to cast shadows and the shadow type can be set to hard or soft shadows.
89
- * The light can be set to be baked or realtime.
90
- * The light can be set to be a main light which will be used for the main directional light in the scene.
70
+ /**
71
+ * The Light component creates a light source in the scene.
72
+ * Supports directional, spot, and point light types with various customization options.
73
+ * Lights can cast shadows with configurable settings and can be set to baked or realtime rendering.
74
+ *
75
+ * Debug mode can be enabled with the URL parameter `?debuglights`, which shows
76
+ * additional console output and visual helpers for lights.
77
+ *
91
78
  * @category Rendering
92
79
  * @group Components
93
80
  */
94
81
  export class Light extends Behaviour implements ILight {
95
82
 
83
+ /**
84
+ * The type of light (spot, directional, point, etc.)
85
+ */
96
86
  @serializable()
97
87
  private type: LightType = 0;
98
88
 
89
+ /**
90
+ * The maximum distance the light affects
91
+ */
99
92
  public range: number = 1;
93
+
94
+ /**
95
+ * The full outer angle of the spotlight cone in degrees
96
+ */
100
97
  public spotAngle: number = 1;
98
+
99
+ /**
100
+ * The angle of the inner cone in degrees for soft-edge spotlights
101
+ */
101
102
  public innerSpotAngle: number = 1;
102
103
 
104
+ /**
105
+ * The color of the light
106
+ */
103
107
  @serializable(Color)
104
108
  set color(val: Color) {
105
109
  this._color = val;
@@ -113,6 +117,9 @@ export class Light extends Behaviour implements ILight {
113
117
  }
114
118
  public _color: Color = new Color(0xffffff);
115
119
 
120
+ /**
121
+ * The near plane distance for shadow projection
122
+ */
116
123
  @serializable()
117
124
  set shadowNearPlane(val: number) {
118
125
  if (val === this._shadowNearPlane) return;
@@ -125,6 +132,9 @@ export class Light extends Behaviour implements ILight {
125
132
  get shadowNearPlane(): number { return this._shadowNearPlane; }
126
133
  private _shadowNearPlane: number = .1;
127
134
 
135
+ /**
136
+ * Shadow bias value to reduce shadow acne and peter-panning
137
+ */
128
138
  @serializable()
129
139
  set shadowBias(val: number) {
130
140
  if (val === this._shadowBias) return;
@@ -137,6 +147,9 @@ export class Light extends Behaviour implements ILight {
137
147
  get shadowBias(): number { return this._shadowBias; }
138
148
  private _shadowBias: number = 0;
139
149
 
150
+ /**
151
+ * Shadow normal bias to reduce shadow acne on sloped surfaces
152
+ */
140
153
  @serializable()
141
154
  set shadowNormalBias(val: number) {
142
155
  if (val === this._shadowNormalBias) return;
@@ -152,6 +165,9 @@ export class Light extends Behaviour implements ILight {
152
165
  /** when enabled this will remove the multiplication when setting the shadow bias settings initially */
153
166
  private _overrideShadowBiasSettings: boolean = false;
154
167
 
168
+ /**
169
+ * Shadow casting mode (None, Hard, or Soft)
170
+ */
155
171
  @serializable()
156
172
  set shadows(val: LightShadows) {
157
173
  this._shadows = val;
@@ -163,9 +179,16 @@ export class Light extends Behaviour implements ILight {
163
179
  get shadows(): LightShadows { return this._shadows; }
164
180
  private _shadows: LightShadows = 1;
165
181
 
182
+ /**
183
+ * Determines if the light contributes to realtime lighting, baked lighting, or a mix
184
+ */
166
185
  @serializable()
167
186
  private lightmapBakeType: LightmapBakeType = LightmapBakeType.Realtime;
168
187
 
188
+ /**
189
+ * Brightness of the light. In WebXR experiences, the intensity is automatically
190
+ * adjusted based on the AR session scale to maintain consistent lighting.
191
+ */
169
192
  @serializable()
170
193
  set intensity(val: number) {
171
194
  this._intensity = val;
@@ -184,6 +207,9 @@ export class Light extends Behaviour implements ILight {
184
207
  get intensity(): number { return this._intensity; }
185
208
  private _intensity: number = -1;
186
209
 
210
+ /**
211
+ * Maximum distance the shadow is projected
212
+ */
187
213
  @serializable()
188
214
  get shadowDistance(): number {
189
215
  const light = this.light;
@@ -207,6 +233,9 @@ export class Light extends Behaviour implements ILight {
207
233
  private shadowWidth?: number;
208
234
  private shadowHeight?: number;
209
235
 
236
+ /**
237
+ * Resolution of the shadow map in pixels (width and height)
238
+ */
210
239
  @serializable()
211
240
  get shadowResolution(): number {
212
241
  const light = this.light;
@@ -226,10 +255,16 @@ export class Light extends Behaviour implements ILight {
226
255
  }
227
256
  private _shadowResolution?: number = undefined;
228
257
 
258
+ /**
259
+ * Whether this light's illumination is entirely baked into lightmaps
260
+ */
229
261
  get isBaked() {
230
262
  return this.lightmapBakeType === LightmapBakeType.Baked;
231
263
  }
232
264
 
265
+ /**
266
+ * Checks if the GameObject itself is a {@link ThreeLight} object
267
+ */
233
268
  private get selfIsLight(): boolean {
234
269
  if (this.gameObject["isLight"] === true) return true;
235
270
  switch (this.gameObject.type) {
@@ -241,8 +276,16 @@ export class Light extends Behaviour implements ILight {
241
276
  return false;
242
277
  }
243
278
 
279
+ /**
280
+ * The underlying three.js {@link ThreeLight} instance
281
+ */
244
282
  private light: ThreeLight | undefined = undefined;
245
283
 
284
+ /**
285
+ * Gets the world position of the light
286
+ * @param vec Vector3 to store the result
287
+ * @returns The world position as a Vector3
288
+ */
246
289
  public getWorldPosition(vec: Vector3): Vector3 {
247
290
  if (this.light) {
248
291
  if (this.type === LightType.Directional) {
@@ -311,6 +354,10 @@ export class Light extends Behaviour implements ILight {
311
354
  // this.updateIntensity();
312
355
  }
313
356
 
357
+ /**
358
+ * Creates the appropriate three.js light based on the configured light type
359
+ * and applies all settings like shadows, intensity, and color.
360
+ */
314
361
  createLight() {
315
362
  const lightAlreadyCreated = this.selfIsLight;
316
363
 
@@ -447,6 +494,10 @@ export class Light extends Behaviour implements ILight {
447
494
 
448
495
  }
449
496
 
497
+ /**
498
+ * Coroutine that updates the main light reference in the context
499
+ * if this directional light should be the main light
500
+ */
450
501
  *updateMainLightRoutine() {
451
502
  while (true) {
452
503
  if (this.type === LightType.Directional) {
@@ -459,8 +510,14 @@ export class Light extends Behaviour implements ILight {
459
510
  }
460
511
  }
461
512
 
513
+ /**
514
+ * Controls whether the renderer's shadow map type can be changed when soft shadows are used
515
+ */
462
516
  static allowChangingRendererShadowMapType: boolean = true;
463
517
 
518
+ /**
519
+ * Updates shadow settings based on whether the shadows are set to hard or soft
520
+ */
464
521
  private updateShadowSoftHard() {
465
522
  if (!this.light) return;
466
523
  if (!this.light.shadow) return;
@@ -486,6 +543,10 @@ export class Light extends Behaviour implements ILight {
486
543
  }
487
544
  }
488
545
 
546
+ /**
547
+ * Configures a directional light by adding and positioning its target
548
+ * @param dirLight The directional light to set up
549
+ */
489
550
  private setDirectionalLight(dirLight: DirectionalLight) {
490
551
  dirLight.add(dirLight.target);
491
552
  dirLight.target.position.set(0, 0, -1);