@needle-tools/engine 4.11.2 → 4.11.3-next.2e95398

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 (96) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/{needle-engine.bundle-DxIfYnRl.js → needle-engine.bundle-Bk9fxkI9.js} +4668 -4642
  3. package/dist/{needle-engine.bundle-BaUshOzH.min.js → needle-engine.bundle-DFuROAWi.min.js} +130 -130
  4. package/dist/{needle-engine.bundle-Ci2JE5sk.umd.cjs → needle-engine.bundle-DHN7tA4V.umd.cjs} +127 -127
  5. package/dist/needle-engine.js +2 -2
  6. package/dist/needle-engine.min.js +1 -1
  7. package/dist/needle-engine.umd.cjs +1 -1
  8. package/lib/engine/api.d.ts +1 -0
  9. package/lib/engine/api.js +1 -0
  10. package/lib/engine/api.js.map +1 -1
  11. package/lib/engine/engine_utils.d.ts +0 -23
  12. package/lib/engine/engine_utils.js +0 -202
  13. package/lib/engine/engine_utils.js.map +1 -1
  14. package/lib/engine/engine_utils_attributes.d.ts +48 -0
  15. package/lib/engine/engine_utils_attributes.js +70 -0
  16. package/lib/engine/engine_utils_attributes.js.map +1 -0
  17. package/lib/engine/engine_utils_qrcode.d.ts +23 -0
  18. package/lib/engine/engine_utils_qrcode.js +234 -0
  19. package/lib/engine/engine_utils_qrcode.js.map +1 -0
  20. package/lib/engine/webcomponents/buttons.js +1 -1
  21. package/lib/engine/webcomponents/buttons.js.map +1 -1
  22. package/lib/engine-components/Animation.d.ts +1 -1
  23. package/lib/engine-components/Animation.js +1 -1
  24. package/lib/engine-components/AnimationCurve.d.ts +3 -0
  25. package/lib/engine-components/AnimationCurve.js +3 -0
  26. package/lib/engine-components/AnimationCurve.js.map +1 -1
  27. package/lib/engine-components/Animator.d.ts +2 -1
  28. package/lib/engine-components/Animator.js +2 -1
  29. package/lib/engine-components/Animator.js.map +1 -1
  30. package/lib/engine-components/AnimatorController.d.ts +3 -0
  31. package/lib/engine-components/AnimatorController.js +3 -0
  32. package/lib/engine-components/AnimatorController.js.map +1 -1
  33. package/lib/engine-components/LookAtConstraint.d.ts +4 -0
  34. package/lib/engine-components/LookAtConstraint.js +4 -0
  35. package/lib/engine-components/LookAtConstraint.js.map +1 -1
  36. package/lib/engine-components/NeedleMenu.d.ts +1 -0
  37. package/lib/engine-components/NeedleMenu.js +1 -0
  38. package/lib/engine-components/NeedleMenu.js.map +1 -1
  39. package/lib/engine-components/NestedGltf.d.ts +3 -0
  40. package/lib/engine-components/NestedGltf.js +3 -0
  41. package/lib/engine-components/NestedGltf.js.map +1 -1
  42. package/lib/engine-components/ReflectionProbe.d.ts +4 -0
  43. package/lib/engine-components/ReflectionProbe.js +4 -0
  44. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  45. package/lib/engine-components/RendererLightmap.d.ts +6 -0
  46. package/lib/engine-components/RendererLightmap.js +6 -3
  47. package/lib/engine-components/RendererLightmap.js.map +1 -1
  48. package/lib/engine-components/SeeThrough.d.ts +3 -0
  49. package/lib/engine-components/SeeThrough.js +8 -1
  50. package/lib/engine-components/SeeThrough.js.map +1 -1
  51. package/lib/engine-components/Skybox.d.ts +3 -0
  52. package/lib/engine-components/Skybox.js +3 -0
  53. package/lib/engine-components/Skybox.js.map +1 -1
  54. package/lib/engine-components/SpriteRenderer.d.ts +14 -1
  55. package/lib/engine-components/SpriteRenderer.js +17 -1
  56. package/lib/engine-components/SpriteRenderer.js.map +1 -1
  57. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  58. package/lib/engine-components/splines/Spline.d.ts +3 -0
  59. package/lib/engine-components/splines/Spline.js +3 -0
  60. package/lib/engine-components/splines/Spline.js.map +1 -1
  61. package/lib/engine-components/splines/SplineUtils.d.ts +3 -0
  62. package/lib/engine-components/splines/SplineUtils.js +3 -0
  63. package/lib/engine-components/splines/SplineUtils.js.map +1 -1
  64. package/lib/engine-components/splines/SplineWalker.d.ts +3 -0
  65. package/lib/engine-components/splines/SplineWalker.js +3 -0
  66. package/lib/engine-components/splines/SplineWalker.js.map +1 -1
  67. package/lib/engine-components/timeline/SignalAsset.d.ts +11 -1
  68. package/lib/engine-components/timeline/SignalAsset.js +11 -1
  69. package/lib/engine-components/timeline/SignalAsset.js.map +1 -1
  70. package/lib/engine-components/ui/Raycaster.d.ts +18 -0
  71. package/lib/engine-components/ui/Raycaster.js +18 -0
  72. package/lib/engine-components/ui/Raycaster.js.map +1 -1
  73. package/package.json +2 -2
  74. package/src/engine/api.ts +1 -0
  75. package/src/engine/engine_utils.ts +0 -229
  76. package/src/engine/engine_utils_attributes.ts +72 -0
  77. package/src/engine/engine_utils_qrcode.ts +266 -0
  78. package/src/engine/webcomponents/buttons.ts +1 -1
  79. package/src/engine-components/Animation.ts +1 -1
  80. package/src/engine-components/AnimationCurve.ts +4 -1
  81. package/src/engine-components/Animator.ts +3 -2
  82. package/src/engine-components/AnimatorController.ts +3 -0
  83. package/src/engine-components/LookAtConstraint.ts +6 -1
  84. package/src/engine-components/NeedleMenu.ts +1 -0
  85. package/src/engine-components/NestedGltf.ts +3 -0
  86. package/src/engine-components/ReflectionProbe.ts +4 -0
  87. package/src/engine-components/RendererLightmap.ts +7 -3
  88. package/src/engine-components/SeeThrough.ts +8 -1
  89. package/src/engine-components/Skybox.ts +3 -0
  90. package/src/engine-components/SpriteRenderer.ts +18 -2
  91. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +1 -1
  92. package/src/engine-components/splines/Spline.ts +3 -0
  93. package/src/engine-components/splines/SplineUtils.ts +3 -1
  94. package/src/engine-components/splines/SplineWalker.ts +3 -0
  95. package/src/engine-components/timeline/SignalAsset.ts +13 -2
  96. package/src/engine-components/ui/Raycaster.ts +19 -0
@@ -0,0 +1,266 @@
1
+
2
+ // use for typesafe interface method calls
3
+ import { Quaternion, Vector2, Vector3, Vector4 } from "three";
4
+
5
+ import { needleLogoOnlySVG } from "./assets/index.js";
6
+ import { isDevEnvironment } from "./debug/debug.js";
7
+ import { hasCommercialLicense } from "./engine_license.js";
8
+ import { InternalAttributeUtils } from "./engine_utils_attributes.js";
9
+ import type { NeedleEngineWebComponent } from "./webcomponents/needle-engine.js";
10
+
11
+
12
+
13
+ /** Generates a QR code HTML image using https://github.com/davidshimjs/qrcodejs
14
+ * @param args.text The text to encode
15
+ * @param args.width The width of the QR code
16
+ * @param args.height The height of the QR code
17
+ * @param args.colorDark The color of the dark squares
18
+ * @param args.colorLight The color of the light squares
19
+ * @param args.correctLevel The error correction level to use
20
+ * @param args.showLogo If true, the logo will be shown in the center of the QR code. By default the Needle Logo will be used. You can override which logo is being used by setting the `needle-engine` web component's `qr-logo-src` attribute. The logo can also be disabled by setting that attribute to a falsey value (e.g. "0" or "false")
21
+ * @param args.showUrl If true, the URL will be shown below the QR code
22
+ * @param args.domElement The dom element to append the QR code to. If not provided a new div will be created and returned
23
+ * @returns The dom element containing the QR code
24
+ */
25
+ export async function generateQRCode(args: { domElement?: HTMLElement, text: string, width?: number, height?: number, colorDark?: string, colorLight?: string, correctLevel?: any, showLogo?: boolean, showUrl?: boolean }): Promise<HTMLElement> {
26
+
27
+ // Ensure that the QRCode library is loaded
28
+ if (!globalThis["QRCode"]) {
29
+ const url = "https://cdn.jsdelivr.net/gh/davidshimjs/qrcodejs@gh-pages/qrcode.min.js";
30
+ let script = document.head.querySelector(`script[src="${url}"]`) as HTMLScriptElement;
31
+ if (!script) {
32
+ script = document.createElement("script");
33
+ script.src = url;
34
+ document.head.appendChild(script);
35
+ }
36
+
37
+ await new Promise((resolve, _reject) => {
38
+ script.addEventListener("load", () => {
39
+ resolve(true);
40
+ });
41
+ });
42
+ }
43
+
44
+ const QRCODE = globalThis["QRCode"];
45
+ const target = args.domElement ?? document.createElement("div");
46
+ const qrCode = new QRCODE(target, {
47
+ width: args.width ?? 256,
48
+ height: args.height ?? 256,
49
+ colorDark: "#000000",
50
+ colorLight: "#ffffff",
51
+ correctLevel: args.showLogo ? QRCODE.CorrectionLevel.H : QRCODE.CorrectLevel.M,
52
+ ...args,
53
+ });
54
+
55
+ // Number of rows/columns of the generated QR code
56
+ const moduleCount = qrCode?._oQRCode.moduleCount || 0;
57
+ const canvas = qrCode?._oDrawing?._elCanvas as HTMLCanvasElement;
58
+
59
+ let sizePercentage = 0.25;
60
+ if (moduleCount < 40)
61
+ sizePercentage = Math.floor(moduleCount / 4) / moduleCount;
62
+ else
63
+ sizePercentage = Math.floor(moduleCount / 6) / moduleCount;
64
+
65
+ const paddingPercentage = Math.floor(moduleCount / 20) / moduleCount;
66
+ try {
67
+ const img = await internalRenderQRCodeOverlays(canvas, { showLogo: args.showLogo, logoSize: sizePercentage, logoPadding: paddingPercentage }).catch(_e => { /** ignore */ });
68
+ if (img) {
69
+ target.innerHTML = "";
70
+ target.append(img);
71
+ }
72
+ }
73
+ catch { } // Ignore
74
+
75
+ if (args.showUrl !== false && args.text) {
76
+ // Add link label below the QR code
77
+ // Clean up the text. If it's a URL: remove the protocol, www. part, trailing slashes or trailing question marks
78
+ const existingLabel = target.querySelector(".qr-code-link-label");
79
+ let displayText = args.text.replace(/^(https?:\/\/)?(www\.)?/, "").replace(/\/+$/, "").replace(/\?+$/, "");
80
+ displayText = "Scan to visit " + displayText;
81
+ if (existingLabel) {
82
+ existingLabel.textContent = displayText;
83
+ } else {
84
+ // Create a new label
85
+ const linkLabel = document.createElement("div");
86
+ linkLabel.classList.add("qr-code-link-label");
87
+ args.text = displayText;
88
+ linkLabel.textContent = args.text;
89
+ linkLabel.addEventListener("click", (ev) => {
90
+ // Prevent the QR panel from closing
91
+ ev.stopImmediatePropagation();
92
+ });
93
+
94
+ linkLabel.style.textAlign = "center";
95
+ linkLabel.style.fontSize = "0.8em";
96
+ linkLabel.style.marginTop = "0.1em";
97
+ linkLabel.style.color = "#000000";
98
+ linkLabel.style.fontFamily = "'Roboto Flex', sans-serif";
99
+ linkLabel.style.opacity = "0.5";
100
+ linkLabel.style.wordBreak = "break-all";
101
+ linkLabel.style.wordWrap = "break-word";
102
+ linkLabel.style.marginBottom = "0.3em";
103
+
104
+ // Ensure max. width
105
+ target.style.width = "calc(210px + 20px)";
106
+
107
+ target.appendChild(linkLabel);
108
+ }
109
+ }
110
+
111
+ return target;
112
+ }
113
+
114
+
115
+ async function internalRenderQRCodeOverlays(canvas: HTMLCanvasElement, args: { showLogo?: boolean, logoSize?: number, logoPadding?: number }): Promise<HTMLImageElement | void> {
116
+ if (!canvas) return;
117
+
118
+ // Internal settings
119
+ const canvasPadding = 8;
120
+ const shadowBlur = 20;
121
+ const rectanglePadding = args.logoPadding || 1. / 32;
122
+ // With dropshadow under the logo
123
+ /*
124
+ const shadowColor = "#00000099";
125
+ const rectangleRadius = 0.4 * 16;
126
+ */
127
+ // Without dropshadow under the logo
128
+ const shadowColor = "transparent";
129
+ const rectangleRadius = 0;
130
+
131
+ // Draw the website's icon in the center of the QR code
132
+ const image = new Image();
133
+ const element = document.querySelector("needle-engine") as NeedleEngineWebComponent;
134
+ if (!element) {
135
+ console.debug("[QR Code] No web component found")
136
+ }
137
+
138
+ const canUseCustomLogo = hasCommercialLicense();
139
+
140
+ // Query logo src from needle-engine attribute.
141
+ // For any supported attribute it's possible to use "falsey" values (e.g. "0" or "false" to disable the logo in the QR code)
142
+ let logoSrc: false | string | null = null;
143
+ logoSrc = InternalAttributeUtils.getAttributeAndCheckFalsey(element, "qrcode-logo-src");
144
+ if (canUseCustomLogo && args.showLogo !== true && logoSrc === false) return; // Explictly disabled
145
+ logoSrc ||= InternalAttributeUtils.getAttributeAndCheckFalsey(element, "logo-src");
146
+ if (canUseCustomLogo && args.showLogo !== true && logoSrc === false) return; // Explicitly disabled
147
+ logoSrc ||= InternalAttributeUtils.getAttributeAndCheckFalsey(element, "loading-logo-src", {
148
+ onAttribute: () => {
149
+ if (isDevEnvironment()) console.warn("[QR Code] 'loading-logo-src' is deprecated, please use 'logo-src' or 'qrcode-logo-src' instead.");
150
+ else console.debug("[QR Code] 'loading-logo-src' is deprecated.");
151
+ }
152
+ });
153
+ if (canUseCustomLogo && args.showLogo !== true && logoSrc === false) return; // Explicitly disabled
154
+
155
+ if (logoSrc && !canUseCustomLogo) {
156
+ console.warn("[QR Code] Custom logo is only available with a commercial license. Using default Needle logo. Please get a commercial license at https://needle.tools/pricing.");
157
+ logoSrc = null;
158
+ }
159
+
160
+ logoSrc ||= needleLogoOnlySVG;
161
+ if (!logoSrc) return;
162
+
163
+ let haveLogo = false;
164
+ if (args.showLogo !== false) {
165
+ image.src = logoSrc;
166
+ haveLogo = await new Promise((resolve, _reject) => {
167
+ image.onload = () => resolve(true);
168
+ image.onerror = (err) => {
169
+ let errorUrl = logoSrc !== needleLogoOnlySVG ? "'" + logoSrc + "'" : null;
170
+ console.error("[QR Code] Error loading logo image for QR code", errorUrl, isDevEnvironment() ? err : "");
171
+ resolve(false);
172
+ };
173
+ });
174
+ }
175
+
176
+ // Add some padding around the canvas – we need to copy the QR code image to a larger canvas
177
+ const paddedCanvas = document.createElement("canvas");
178
+ paddedCanvas.width = canvas.width + canvasPadding;
179
+ paddedCanvas.height = canvas.height + canvasPadding;
180
+ const paddedContext = paddedCanvas.getContext("2d");
181
+ if (!paddedContext) {
182
+ return;
183
+ }
184
+
185
+ // Clear with white
186
+ paddedContext.fillStyle = "#ffffff";
187
+ paddedContext.fillRect(0, 0, paddedCanvas.width, paddedCanvas.height);
188
+ paddedContext.drawImage(canvas, canvasPadding / 2, canvasPadding / 2);
189
+
190
+ // Enable anti-aliasing
191
+ paddedContext.imageSmoothingEnabled = true;
192
+ paddedContext.imageSmoothingQuality = "high";
193
+ // @ts-ignore
194
+ paddedContext.mozImageSmoothingEnabled = true;
195
+ // @ts-ignore
196
+ paddedContext.webkitImageSmoothingEnabled = true;
197
+
198
+ // Draw a slight gradient background with 10% opacity and "lighten" composite operation
199
+ paddedContext.globalCompositeOperation = "lighten";
200
+ const gradient = paddedContext.createLinearGradient(0, 0, 0, paddedCanvas.height);
201
+ gradient.addColorStop(0, "rgb(45, 45, 45)");
202
+ gradient.addColorStop(1, "rgb(45, 45, 45)");
203
+ paddedContext.fillStyle = gradient;
204
+ paddedContext.fillRect(0, 0, paddedCanvas.width, paddedCanvas.height);
205
+ paddedContext.globalCompositeOperation = "source-over";
206
+
207
+
208
+ let sizeX = Math.min(canvas.width, canvas.height) * (args.logoSize || 0.25);
209
+ let sizeY = sizeX;
210
+
211
+ if (haveLogo) {
212
+ // Get aspect of image
213
+ const aspect = image.width / image.height;
214
+ if (aspect > 1) sizeY = sizeX / aspect;
215
+ else sizeX = sizeY * aspect;
216
+
217
+ const rectanglePaddingPx = rectanglePadding * canvas.width;
218
+
219
+ // Apply padding
220
+ const sizeForBackground = Math.max(sizeX, sizeY);
221
+ const sizeXPadded = Math.round(sizeForBackground + rectanglePaddingPx);
222
+ const sizeYPadded = Math.round(sizeForBackground + rectanglePaddingPx);
223
+ const x = (paddedCanvas.width - sizeForBackground) / 2;
224
+ const y = (paddedCanvas.height - sizeForBackground) / 2;
225
+
226
+ // Draw shape with blurred shadow
227
+ paddedContext.shadowColor = shadowColor;
228
+ paddedContext.shadowBlur = shadowBlur;
229
+
230
+ // Draw rounded rectangle with radius
231
+ // Convert 0.4rem to pixels, taking DPI into account
232
+ const radius = rectangleRadius;
233
+ const xPadded = Math.round(x - rectanglePaddingPx / 2);
234
+ const yPadded = Math.round(y - rectanglePaddingPx / 2);
235
+ paddedContext.beginPath();
236
+ paddedContext.moveTo(xPadded + radius, yPadded);
237
+ paddedContext.lineTo(xPadded + sizeXPadded - radius, yPadded);
238
+ paddedContext.quadraticCurveTo(xPadded + sizeXPadded, yPadded, xPadded + sizeXPadded, yPadded + radius);
239
+ paddedContext.lineTo(xPadded + sizeXPadded, yPadded + sizeYPadded - radius);
240
+ paddedContext.quadraticCurveTo(xPadded + sizeXPadded, yPadded + sizeYPadded, xPadded + sizeXPadded - radius, yPadded + sizeYPadded);
241
+ paddedContext.lineTo(xPadded + radius, yPadded + sizeYPadded);
242
+ paddedContext.quadraticCurveTo(xPadded, yPadded + sizeYPadded, xPadded, yPadded + sizeYPadded - radius);
243
+ paddedContext.lineTo(xPadded, yPadded + radius);
244
+ paddedContext.quadraticCurveTo(xPadded, yPadded, xPadded + radius, yPadded);
245
+ paddedContext.fillStyle = "#ffffff";
246
+ paddedContext.closePath();
247
+ paddedContext.fill();
248
+ paddedContext.clip();
249
+
250
+ // Reset shadow and draw favicon
251
+ paddedContext.shadowColor = "transparent";
252
+ const logoX = (paddedCanvas.width - sizeX) / 2;
253
+ const logoY = (paddedCanvas.height - sizeY) / 2;
254
+ paddedContext.drawImage(image, logoX, logoY, sizeX, sizeY);
255
+ }
256
+
257
+ // Replace the canvas with the padded one
258
+ const paddedImage = paddedCanvas.toDataURL("image/png");
259
+ const img = document.createElement("img");
260
+ img.src = paddedImage;
261
+ img.style.width = "100%";
262
+ img.style.height = "auto";
263
+
264
+ return img;
265
+ }
266
+
@@ -1,6 +1,6 @@
1
1
  import { isDevEnvironment, showBalloonWarning } from "../debug/debug.js";
2
2
  import { IContext } from "../engine_types.js";
3
- import { generateQRCode, isMobileDevice } from "../engine_utils.js";
3
+ import { generateQRCode } from "../engine_utils_qrcode.js";
4
4
  import { onXRSessionEnd, onXRSessionStart } from "../xr/events.js";
5
5
  import { getIconElement } from "./icons.js";
6
6
 
@@ -58,7 +58,7 @@ declare type AnimationIdentifier = AnimationClip | number | string | undefined;
58
58
  class Vec2 { x!: number; y!: number }
59
59
 
60
60
  /**
61
- * Animation component to play animations on a GameObject
61
+ * Animation component to play animations on a GameObject.
62
62
  * @category Animation and Sequencing
63
63
  * @group Components
64
64
  */
@@ -27,7 +27,10 @@ export class Keyframe {
27
27
  }
28
28
 
29
29
  /**
30
- * AnimationCurve is a representation of a curve that can be used to animate values over time.
30
+ * AnimationCurve is a representation of a curve that can be used to animate values over time.
31
+ *
32
+ * @category Animation
33
+ * @group Utilities
31
34
  */
32
35
  export class AnimationCurve {
33
36
 
@@ -39,8 +39,9 @@ export declare class PlayOptions {
39
39
 
40
40
  /**
41
41
  * The Animator component plays and manages animations on a GameObject.
42
- * It works with an AnimatorController to handle state transitions and animation blending.
43
- * A new AnimatorController can be created from code via `AnimatorController.createFromClips`.
42
+ * It works with an {@link AnimatorController} to handle state transitions and animation blending.
43
+ * A new AnimatorController can be created from code via `AnimatorController.createFromClips`.
44
+ *
44
45
  * @category Animation and Sequencing
45
46
  * @group Components
46
47
  */
@@ -51,6 +51,9 @@ declare type CreateAnimatorControllerOptions = {
51
51
  *
52
52
  * Use the static method {@link AnimatorController.createFromClips} to create
53
53
  * an animator controller from a set of animation clips.
54
+ *
55
+ * @category Animation and Sequencing
56
+ * @group Utilities
54
57
  */
55
58
  export class AnimatorController {
56
59
 
@@ -2,9 +2,14 @@ import { Object3D, Vector3 } from "three";
2
2
 
3
3
  import { serializable } from "../engine/engine_serialization_decorator.js";
4
4
  import { Behaviour } from "./Component.js";
5
+ import type { OrbitControls } from "./OrbitControls.js";
5
6
 
6
7
  /**
7
- * A LookAtConstraint is used by OrbitControls to make the camera look at a target.
8
+ * A LookAtConstraint is used by OrbitControls to make the camera look at a target.
9
+ * This component is used by {@link OrbitControls} internally.
10
+ *
11
+ * @category Camera Controls
12
+ * @group Components
8
13
  */
9
14
  export class LookAtConstraint extends Behaviour {
10
15
 
@@ -9,6 +9,7 @@ import { Behaviour } from './Component.js';
9
9
  *
10
10
  * Controls display options, button visibility, and menu positioning.
11
11
  * From code, you can access the menu via {@link Context.menu}.
12
+ *
12
13
  * @category User Interface
13
14
  * @group Components
14
15
  **/
@@ -10,6 +10,9 @@ const debug = getParam("debugnestedgltf");
10
10
 
11
11
  /** The nested gltf is a component that is used to load a gltf file when the component becomes active (start)
12
12
  * It will load the gltf file and instantiate it as a child of the parent of the GameObject that has this component
13
+ *
14
+ * @category Asset Management
15
+ * @group Components
13
16
  */
14
17
  export class NestedGltf extends Behaviour {
15
18
 
@@ -15,6 +15,10 @@ const $reflectionProbeKey = Symbol("reflectionProbeKey");
15
15
  const $originalMaterial = Symbol("original material");
16
16
 
17
17
  /**
18
+ * A ReflectionProbe provides reflection data to materials within its defined area.
19
+ *
20
+ * - Sample: http://samples.needle.tools/reflection-probes
21
+ *
18
22
  * @category Rendering
19
23
  * @group Components
20
24
  */
@@ -9,9 +9,13 @@ const debug = getParam("debuglightmaps");
9
9
 
10
10
  declare type MaterialWithLightmap = Material & { lightMap?: Texture | null };
11
11
 
12
- // this component is automatically added by the Renderer if the object has lightmap uvs AND we have a lightmap
13
- // for multimaterial objects GLTF exports a "Group" with the renderer component
14
- // and every child mesh is a material from unity
12
+
13
+ /**
14
+ * This component is automatically added by the {@link Renderer} component if the object has lightmap uvs AND we have a lightmap.
15
+ *
16
+ * @category Rendering
17
+ * @group Components
18
+ */
15
19
  export class RendererLightmap {
16
20
 
17
21
  get lightmap(): Texture | null {
@@ -39,6 +39,9 @@ let i = 0;
39
39
  * Requires a Renderer component on the same object or a child object.
40
40
  *
41
41
  * - Example https://see-through-walls-z23hmxbz1kjfjn.needle.run/
42
+ *
43
+ * @category Rendering
44
+ * @group Components
42
45
  */
43
46
  export class SeeThrough extends Behaviour {
44
47
 
@@ -241,6 +244,7 @@ export class SeeThrough extends Behaviour {
241
244
 
242
245
  const wasTransparent = mat.transparent;
243
246
  const wasAlphaHash = mat.alphaHash;
247
+ const previousOpacity = mat.opacity;
244
248
 
245
249
  mat.alphaHash = this.useAlphaHash;
246
250
 
@@ -253,7 +257,10 @@ export class SeeThrough extends Behaviour {
253
257
  mat.transparent = mat.opacity >= 1 ? false : !this.useAlphaHash;
254
258
  }
255
259
 
256
- if (wasTransparent != mat.transparent || wasAlphaHash != mat.alphaHash) {
260
+ if (wasTransparent !== mat.transparent
261
+ || wasAlphaHash !== mat.alphaHash
262
+ || mat.opacity !== previousOpacity // MeshPhysicsMaterial needs that and maybe other materials too...
263
+ ) {
257
264
  mat.needsUpdate = true;
258
265
  }
259
266
  }
@@ -120,6 +120,9 @@ ContextRegistry.registerCallback(ContextEvent.ContextCreationStart, () => {
120
120
  * ```ts
121
121
  * skybox.setSkybox("https://example.com/skybox.hdr");
122
122
  * ```
123
+ *
124
+ * @category Rendering
125
+ * @group Components
123
126
  */
124
127
  export class RemoteSkybox extends Behaviour {
125
128
 
@@ -9,6 +9,9 @@ import { Behaviour } from "./Component.js";
9
9
  const debug = getParam("debugspriterenderer");
10
10
  const showWireframe = getParam("wireframe");
11
11
 
12
+ /**
13
+ * @internal
14
+ */
12
15
  class SpriteUtils {
13
16
 
14
17
  static cache: { [key: string]: BufferGeometry } = {};
@@ -82,7 +85,7 @@ function updateTextureIfNecessary(tex: Texture) {
82
85
  }
83
86
 
84
87
  /**
85
- * A sprite is a mesh that represents a 2D image
88
+ * A sprite is a mesh that represents a 2D image. Used by the {@link SpriteRenderer} to render 2D images in the scene.
86
89
  * @category Rendering
87
90
  * @group Components
88
91
  */
@@ -152,6 +155,9 @@ export class Sprite {
152
155
 
153
156
  const $spriteTexOwner = Symbol("spriteOwner");
154
157
 
158
+ /**
159
+ * @category Sprites
160
+ */
155
161
  export class SpriteSheet {
156
162
 
157
163
  @serializable(Sprite)
@@ -162,6 +168,11 @@ export class SpriteSheet {
162
168
  }
163
169
  }
164
170
 
171
+ /**
172
+ * Used by the {@link SpriteRenderer} to hold the sprite sheet and the currently active sprite index.
173
+ *
174
+ * @category Sprites
175
+ */
165
176
  export class SpriteData {
166
177
 
167
178
  static create() {
@@ -246,7 +257,12 @@ export class SpriteData {
246
257
  }
247
258
 
248
259
  /**
249
- * The sprite renderer renders a sprite on a GameObject using an assigned spritesheet ({@link SpriteData}).
260
+ * The sprite renderer renders a sprite on a GameObject using an assigned spritesheet ({@link SpriteData}).
261
+ *
262
+ * - Example: https://engine.needle.tools/samples/spritesheet-animation
263
+ *
264
+ * @category Sprites
265
+ * @group Components
250
266
  */
251
267
  export class SpriteRenderer extends Behaviour {
252
268
 
@@ -42,9 +42,9 @@ import { Progress } from '../../../engine/engine_time_utils.js';
42
42
  // import { BehaviorExtension } from '../../api.js';
43
43
  import type { IUSDExporterExtension } from './Extension.js';
44
44
  import type { AnimationExtension } from './extensions/Animation.js';
45
+ import { BehaviorExtension } from './extensions/behavior/Behaviour.js';
45
46
  import type { PhysicsExtension } from './extensions/behavior/PhysicsExtension.js';
46
47
  import {buildNodeMaterial} from './extensions/NodeMaterialConverter.js';
47
- import { BehaviorExtension } from './extensions/behavior/Behaviour.js';
48
48
 
49
49
  type MeshPhysicalNodeMaterial = import("three/src/materials/nodes/MeshPhysicalNodeMaterial.js").default;
50
50
 
@@ -36,6 +36,9 @@ export class SplineData {
36
36
  * The spline is defined by an array of knots (SplineData) which define position, rotation and tangents.
37
37
  *
38
38
  * You can create a SplineContainer from an array of points using the static method 'createFromPoints'.
39
+ *
40
+ * @category Splines
41
+ * @group Components
39
42
  */
40
43
  export class SplineContainer extends Behaviour {
41
44
 
@@ -3,7 +3,9 @@ import { Vector3 } from "three";
3
3
  import { Mathf } from "../../engine/engine_math.js";
4
4
  import { SplineContainer, SplineData } from "./Spline.js";
5
5
 
6
-
6
+ /**
7
+ * @category Splines
8
+ */
7
9
  export namespace SplineUtils {
8
10
 
9
11
  /**
@@ -11,6 +11,9 @@ import { SplineContainer } from "./Spline.js";
11
11
  * Use this with a SplineContainer component.
12
12
  *
13
13
  * - Example http://samples.needle.tools/splines
14
+ *
15
+ * @category Splines
16
+ * @group Components
14
17
  */
15
18
  export class SplineWalker extends Behaviour {
16
19
 
@@ -2,15 +2,23 @@ import { serializable } from "../../engine/engine_serialization_decorator.js";
2
2
  import { getParam } from "../../engine/engine_utils.js";
3
3
  import { Behaviour } from "../Component.js";
4
4
  import { EventList } from "../EventList.js";
5
+ import type { PlayableDirector } from "./PlayableDirector.js";
5
6
 
6
7
  const debug = getParam("debugsignals")
7
8
 
8
9
 
10
+ /**
11
+ * Used to reference a signal asset in a SignalReceiver. This is internally used by the {@link SignalReceiverEvent}.
12
+ */
9
13
  export class SignalAsset {
10
14
  @serializable()
11
15
  guid!: string;
12
16
  }
13
17
 
18
+ /**
19
+ * An event that links a signal to a reaction.
20
+ * Used internally by {@link SignalReceiver}.
21
+ */
14
22
  export class SignalReceiverEvent {
15
23
  @serializable(SignalAsset)
16
24
  signal!: SignalAsset;
@@ -19,7 +27,10 @@ export class SignalReceiverEvent {
19
27
  }
20
28
 
21
29
  /** SignalReceiver is a component that listens for signals and invokes a reaction when a signal is received.
22
- * Signals can be added to a signal track on a timeline
30
+ * Signals can be added to a signal track on a {@link PlayableDirector}
31
+ *
32
+ * @category Sequencing and Timelines
33
+ * @group Components
23
34
  */
24
35
  export class SignalReceiver extends Behaviour {
25
36
 
@@ -41,7 +52,7 @@ export class SignalReceiver extends Behaviour {
41
52
 
42
53
  /** @internal */
43
54
  awake(): void {
44
- if(debug) console.log("SignalReceiver awake", this);
55
+ if (debug) console.log("SignalReceiver awake", this);
45
56
  }
46
57
 
47
58
  /** @internal */
@@ -28,6 +28,12 @@ export abstract class Raycaster extends Behaviour {
28
28
  }
29
29
 
30
30
 
31
+ /**
32
+ * A Raycaster that performs raycasting against its own GameObject.
33
+ *
34
+ * @category Interaction
35
+ * @group Components
36
+ */
31
37
  export class ObjectRaycaster extends Raycaster {
32
38
  private targets: Object3D[] | null = null;
33
39
  private raycastHits: Intersection[] = [];
@@ -65,6 +71,13 @@ export class ObjectRaycaster extends Raycaster {
65
71
  }
66
72
  }
67
73
 
74
+
75
+ /**
76
+ * A Raycaster that performs raycasting against UI elements (objects with a CanvasRenderer component).
77
+ *
78
+ * @category UI
79
+ * @group Components
80
+ */
68
81
  export class GraphicRaycaster extends ObjectRaycaster {
69
82
  // eventCamera: Camera | null = null;
70
83
  // ignoreReversedGraphics: boolean = false;
@@ -76,6 +89,12 @@ export class GraphicRaycaster extends ObjectRaycaster {
76
89
  }
77
90
  }
78
91
 
92
+ /**
93
+ * A Raycaster that performs sphere overlap raycasting for spatial grab interactions in XR.
94
+ *
95
+ * @category XR
96
+ * @group Components
97
+ */
79
98
  export class SpatialGrabRaycaster extends Raycaster {
80
99
 
81
100
  /**