@needle-tools/engine 5.1.0-alpha.4 → 5.1.0-alpha.6

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 (133) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/components.needle.json +1 -1
  3. package/dist/{needle-engine.bundle-DQCuBTVp.umd.cjs → needle-engine.bundle-5avtTUMM.umd.cjs} +149 -148
  4. package/dist/{needle-engine.bundle-AjVIot3d.min.js → needle-engine.bundle-BHcw4C8f.min.js} +187 -186
  5. package/dist/{needle-engine.bundle-B7cqsI4c.js → needle-engine.bundle-C0gPOq4m.js} +7522 -7092
  6. package/dist/needle-engine.d.ts +715 -176
  7. package/dist/needle-engine.js +595 -593
  8. package/dist/needle-engine.min.js +1 -1
  9. package/dist/needle-engine.umd.cjs +1 -1
  10. package/dist/three.js +1 -0
  11. package/dist/three.min.js +21 -21
  12. package/dist/three.umd.cjs +16 -16
  13. package/lib/engine/api.d.ts +3 -1
  14. package/lib/engine/api.js +3 -1
  15. package/lib/engine/api.js.map +1 -1
  16. package/lib/engine/codegen/register_types.js +10 -10
  17. package/lib/engine/codegen/register_types.js.map +1 -1
  18. package/lib/engine/engine_camera.fit.js +16 -4
  19. package/lib/engine/engine_camera.fit.js.map +1 -1
  20. package/lib/engine/engine_context.d.ts +20 -7
  21. package/lib/engine/engine_context.js +36 -14
  22. package/lib/engine/engine_context.js.map +1 -1
  23. package/lib/engine/engine_context_eventbus.d.ts +47 -0
  24. package/lib/engine/engine_context_eventbus.js +47 -0
  25. package/lib/engine/engine_context_eventbus.js.map +1 -0
  26. package/lib/engine/engine_init.js +2 -2
  27. package/lib/engine/engine_init.js.map +1 -1
  28. package/lib/engine/engine_input.d.ts +23 -4
  29. package/lib/engine/engine_input.js +2 -1
  30. package/lib/engine/engine_input.js.map +1 -1
  31. package/lib/engine/engine_license.d.ts +7 -7
  32. package/lib/engine/engine_license.js +185 -57
  33. package/lib/engine/engine_license.js.map +1 -1
  34. package/lib/engine/engine_networking_blob.js +3 -3
  35. package/lib/engine/engine_networking_blob.js.map +1 -1
  36. package/lib/engine/engine_physics_rapier.d.ts +10 -0
  37. package/lib/engine/engine_physics_rapier.js +6 -0
  38. package/lib/engine/engine_physics_rapier.js.map +1 -1
  39. package/lib/engine/engine_types.d.ts +10 -0
  40. package/lib/engine/engine_utils_qrcode.js +2 -2
  41. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  42. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  43. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  44. package/lib/engine/webcomponents/needle menu/needle-menu.js +5 -5
  45. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  46. package/lib/engine/webcomponents/needle-engine.js +2 -2
  47. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  48. package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
  49. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  50. package/lib/engine/xr/TempXRContext.js +2 -2
  51. package/lib/engine/xr/TempXRContext.js.map +1 -1
  52. package/lib/engine-components/AnimationBuilder.d.ts +158 -0
  53. package/lib/engine-components/AnimationBuilder.js +305 -0
  54. package/lib/engine-components/AnimationBuilder.js.map +1 -0
  55. package/lib/engine-components/Animator.js +6 -1
  56. package/lib/engine-components/Animator.js.map +1 -1
  57. package/lib/engine-components/AnimatorController.builder.d.ts +101 -23
  58. package/lib/engine-components/AnimatorController.builder.js +88 -20
  59. package/lib/engine-components/AnimatorController.builder.js.map +1 -1
  60. package/lib/engine-components/AnimatorController.js +2 -0
  61. package/lib/engine-components/AnimatorController.js.map +1 -1
  62. package/lib/engine-components/ContactShadows.d.ts +1 -0
  63. package/lib/engine-components/ContactShadows.js +14 -1
  64. package/lib/engine-components/ContactShadows.js.map +1 -1
  65. package/lib/engine-components/DropListener.js +3 -0
  66. package/lib/engine-components/DropListener.js.map +1 -1
  67. package/lib/engine-components/OrbitControls.d.ts +0 -2
  68. package/lib/engine-components/OrbitControls.js +14 -1
  69. package/lib/engine-components/OrbitControls.js.map +1 -1
  70. package/lib/engine-components/SceneSwitcher.js +3 -0
  71. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  72. package/lib/engine-components/api.d.ts +1 -0
  73. package/lib/engine-components/api.js +1 -0
  74. package/lib/engine-components/api.js.map +1 -1
  75. package/lib/engine-components/codegen/components.d.ts +6 -6
  76. package/lib/engine-components/codegen/components.js +6 -6
  77. package/lib/engine-components/codegen/components.js.map +1 -1
  78. package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
  79. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  80. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  81. package/lib/engine-components/timeline/PlayableDirector.d.ts +7 -7
  82. package/lib/engine-components/timeline/PlayableDirector.js +6 -6
  83. package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
  84. package/lib/engine-components/timeline/TimelineBuilder.d.ts +175 -9
  85. package/lib/engine-components/timeline/TimelineBuilder.js +108 -2
  86. package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -1
  87. package/lib/engine-components/timeline/TimelineTracks.d.ts +15 -7
  88. package/lib/engine-components/timeline/TimelineTracks.js +22 -14
  89. package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
  90. package/lib/engine-components/web/CursorFollow.d.ts +0 -1
  91. package/lib/engine-components/web/CursorFollow.js +0 -1
  92. package/lib/engine-components/web/CursorFollow.js.map +1 -1
  93. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +62 -1
  94. package/lib/engine-components/webxr/WebXRImageTracking.js +55 -2
  95. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  96. package/package.json +1 -1
  97. package/plugins/common/cloud.js +6 -1
  98. package/plugins/common/license.js +26 -8
  99. package/plugins/vite/license.js +42 -7
  100. package/src/engine/api.ts +4 -1
  101. package/src/engine/codegen/register_types.ts +10 -10
  102. package/src/engine/engine_camera.fit.ts +15 -4
  103. package/src/engine/engine_context.ts +41 -16
  104. package/src/engine/engine_context_eventbus.ts +73 -0
  105. package/src/engine/engine_init.ts +2 -2
  106. package/src/engine/engine_input.ts +27 -6
  107. package/src/engine/engine_license.ts +201 -55
  108. package/src/engine/engine_networking_blob.ts +3 -3
  109. package/src/engine/engine_physics_rapier.ts +20 -6
  110. package/src/engine/engine_types.ts +22 -12
  111. package/src/engine/engine_utils_qrcode.ts +2 -2
  112. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
  113. package/src/engine/webcomponents/needle menu/needle-menu.ts +5 -5
  114. package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
  115. package/src/engine/webcomponents/needle-engine.ts +2 -2
  116. package/src/engine/xr/TempXRContext.ts +2 -2
  117. package/src/engine-components/AnimationBuilder.ts +472 -0
  118. package/src/engine-components/Animator.ts +6 -1
  119. package/src/engine-components/AnimatorController.builder.ts +163 -37
  120. package/src/engine-components/AnimatorController.ts +1 -0
  121. package/src/engine-components/ContactShadows.ts +15 -1
  122. package/src/engine-components/DropListener.ts +3 -0
  123. package/src/engine-components/OrbitControls.ts +16 -5
  124. package/src/engine-components/SceneSwitcher.ts +3 -0
  125. package/src/engine-components/api.ts +1 -0
  126. package/src/engine-components/codegen/components.ts +6 -6
  127. package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
  128. package/src/engine-components/timeline/PlayableDirector.ts +20 -20
  129. package/src/engine-components/timeline/TimelineBuilder.ts +277 -17
  130. package/src/engine-components/timeline/TimelineTracks.ts +24 -16
  131. package/src/engine-components/web/CursorFollow.ts +0 -1
  132. package/src/engine-components/webxr/WebXRImageTracking.ts +77 -7
  133. package/src/vite-env.d.ts +0 -16
@@ -7,19 +7,33 @@ import { SSR } from "./engine_ssr.js";
7
7
  import type { IContext } from "./engine_types.js";
8
8
  import { getParam } from "./engine_utils.js";
9
9
 
10
- const debug = getParam("debuglicense");
10
+ const debug = getParam("__debuglic__");
11
11
 
12
- const _licenseCheckResultChangedCallbacks: ((result: boolean) => void)[] = [];
12
+ const qKUrR: ((result: boolean) => void)[] = [];
13
13
 
14
- // This is modified by a bundler (e.g. vite)
15
- // Do not edit manually
16
- let NEEDLE_ENGINE_LICENSE_TYPE: string = "basic";
17
- if (debug)
18
- console.log("License Type: " + NEEDLE_ENGINE_LICENSE_TYPE)
14
+ // DO NOT EDIT MANUALLY
15
+ let EzdGPQg: string = "";
16
+ // eslint-disable-next-line prefer-const
17
+ let _$InwX: string = "";
18
+
19
+ if (debug) {
20
+ console.log("License Type: " + EzdGPQg);
21
+ if (_$InwX) {
22
+ console.log("License JWT: " + _$InwX);
23
+ try {
24
+ const payload = JSON.parse(atob(_$InwX.split(".")[1].replace(/-/g, '+').replace(/_/g, '/')));
25
+ console.log("License JWT payload:", payload);
26
+ }
27
+ catch { console.log("License JWT payload: (failed to decode)"); }
28
+ }
29
+ else {
30
+ console.log("License JWT: (none)");
31
+ }
32
+ }
19
33
 
20
34
  /** @internal */
21
- export function hasProLicense() {
22
- switch (NEEDLE_ENGINE_LICENSE_TYPE) {
35
+ export function _cxKhKwDL() {
36
+ switch (EzdGPQg) {
23
37
  case "pro":
24
38
  case "enterprise":
25
39
  return true;
@@ -28,8 +42,8 @@ export function hasProLicense() {
28
42
  }
29
43
 
30
44
  /** @internal */
31
- export function hasIndieLicense() {
32
- switch (NEEDLE_ENGINE_LICENSE_TYPE) {
45
+ export function __otwqOR() {
46
+ switch (EzdGPQg) {
33
47
  case "indie":
34
48
  return true;
35
49
  }
@@ -37,8 +51,8 @@ export function hasIndieLicense() {
37
51
  }
38
52
 
39
53
  /** @internal */
40
- export function hasEduLicense() {
41
- switch (NEEDLE_ENGINE_LICENSE_TYPE) {
54
+ export function __mPmwPS() {
55
+ switch (EzdGPQg) {
42
56
  case "edu":
43
57
  return true;
44
58
  }
@@ -46,20 +60,20 @@ export function hasEduLicense() {
46
60
  }
47
61
 
48
62
  /** @internal */
49
- export function hasCommercialLicense() {
50
- return hasProLicense() || hasIndieLicense() || hasEduLicense();
63
+ export function LynjGsV() {
64
+ return _cxKhKwDL() || __otwqOR() || __mPmwPS();
51
65
  }
52
66
 
53
67
 
54
68
  /** @internal */
55
- export function onLicenseCheckResultChanged(cb: (result: boolean) => void) {
56
- if (hasProLicense() || hasIndieLicense() || hasEduLicense())
69
+ export function $yRlAEF(cb: (result: boolean) => void) {
70
+ if (_cxKhKwDL() || __otwqOR() || __mPmwPS())
57
71
  return cb(true);
58
- _licenseCheckResultChangedCallbacks.push(cb);
72
+ qKUrR.push(cb);
59
73
  }
60
74
 
61
- function invokeLicenseCheckResultChanged(result: boolean) {
62
- for (const cb of _licenseCheckResultChangedCallbacks) {
75
+ function cLH(result: boolean) {
76
+ for (const cb of qKUrR) {
63
77
  try {
64
78
  cb(result);
65
79
  }
@@ -70,6 +84,128 @@ function invokeLicenseCheckResultChanged(result: boolean) {
70
84
  }
71
85
 
72
86
 
87
+ // #region JWT
88
+
89
+ // ECDSA P-256 public key for verifying license JWTs (verification-only, safe to ship)
90
+ /* eslint-disable no-secrets/no-secrets -- public key, not a secret */
91
+ const ACBIZP = {
92
+ kty: "EC",
93
+ crv: "P-256",
94
+ x: "A34nyKMjhQYVgzeE4tyLUYdx34TAKogDa7v7PRaO9Lg",
95
+ y: "JZI9IQavGCpGjEG_-pa0J-MHQYWJYINUM-MnvSu0TmE",
96
+ } as const;
97
+ /* eslint-enable no-secrets/no-secrets */
98
+
99
+ /** Base64url decode (RFC 7515) */
100
+ function base64urlDecode(str: string): Uint8Array {
101
+ const base64 = str.replace(/-/g, '+').replace(/_/g, '/');
102
+ const padded = base64 + '='.repeat((4 - base64.length % 4) % 4);
103
+ const binary = atob(padded);
104
+ const bytes = new Uint8Array(binary.length);
105
+ for (let i = 0; i < binary.length; i++) {
106
+ bytes[i] = binary.charCodeAt(i);
107
+ }
108
+ return bytes;
109
+ }
110
+
111
+ /**
112
+ * Verify a JWT license token and return the `type` claim if valid.
113
+ * Returns null if the JWT is missing, malformed, or has an invalid signature.
114
+ */
115
+ async function IKPk(jwt: string): Promise<string | null> {
116
+ if (!jwt) return null;
117
+ try {
118
+ const parts = jwt.split(".");
119
+ if (parts.length !== 3) return null;
120
+
121
+ const [headerB64, payloadB64, signatureB64] = parts;
122
+
123
+ const key = await crypto.subtle.importKey(
124
+ "jwk",
125
+ ACBIZP,
126
+ { name: "ECDSA", namedCurve: "P-256" },
127
+ false,
128
+ ["verify"]
129
+ );
130
+
131
+ const signingInput = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
132
+ const signature = base64urlDecode(signatureB64);
133
+
134
+ const valid = await crypto.subtle.verify(
135
+ { name: "ECDSA", hash: "SHA-256" },
136
+ key,
137
+ signature.buffer as ArrayBuffer,
138
+ signingInput
139
+ );
140
+
141
+ if (!valid) {
142
+ if (debug) console.warn("JWT: signature verification failed");
143
+ return null;
144
+ }
145
+
146
+ const payloadStr = new TextDecoder().decode(base64urlDecode(payloadB64));
147
+ const payload = JSON.parse(payloadStr);
148
+
149
+ if (typeof payload.type !== "string" || payload.type.length === 0) {
150
+ if (debug) console.warn("JWT: missing or invalid 'type' claim");
151
+ return null;
152
+ }
153
+
154
+ // Optional: check expiration if present (future-proof — server doesn't set this yet)
155
+ if (typeof payload.exp === "number") {
156
+ const nowSeconds = Math.floor(Date.now() / 1000);
157
+ if (nowSeconds > payload.exp) {
158
+ if (debug) console.warn("JWT: token has expired (exp=" + payload.exp + ", now=" + nowSeconds + ")");
159
+ return null;
160
+ }
161
+ }
162
+
163
+ // Optional: check audience/domain if present (future-proof — server doesn't set this yet)
164
+ if (payload.aud) {
165
+ const currentHost = typeof window !== "undefined" ? window.location.hostname : undefined;
166
+ if (currentHost) {
167
+ const allowed = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
168
+ if (!allowed.some((a: string) => currentHost === a || currentHost.endsWith("." + a))) {
169
+ if (debug) console.warn("JWT: domain '" + currentHost + "' not in allowed audience: " + allowed.join(", "));
170
+ return null;
171
+ }
172
+ }
173
+ }
174
+
175
+ if (debug) console.log("JWT: verified license type: " + payload.type);
176
+ return payload.type;
177
+ }
178
+ catch (err) {
179
+ if (debug) console.error("JWT: verification error", err);
180
+ return null;
181
+ }
182
+ }
183
+
184
+ /** Verify the injected JWT and update the license type if valid.
185
+ * The engine ONLY trusts the JWT — the plain EzdGPQg string is ignored. */
186
+ let _jwtVerificationPromise: Promise<void> | undefined = undefined;
187
+ async function _EyK(): Promise<void> {
188
+ // NOTE: do NOT add an `if (!_$InwX) return` guard here.
189
+ // esbuild (Vite dependency pre-bundling) would see the variable as constant ""
190
+ // and tree-shake the entire JWT verification code path.
191
+ const jwt = _$InwX;
192
+ // Clear after reading — this reassignment also prevents esbuild from
193
+ // constant-folding the variable (it now has multiple assignment sites).
194
+ _$InwX = "";
195
+ const verifiedType = await IKPk(jwt);
196
+ if (verifiedType) {
197
+ EzdGPQg = verifiedType;
198
+ if (debug) console.log("License type set from verified JWT: " + verifiedType);
199
+ cLH(LynjGsV());
200
+ }
201
+ else {
202
+ EzdGPQg = "basic";
203
+ if (debug && jwt) console.warn("JWT verification failed — license reset to basic");
204
+ }
205
+ }
206
+
207
+ // #endregion JWT License Verification
208
+
73
209
 
74
210
  // #region Telemetry
75
211
  export namespace Telemetry {
@@ -135,7 +271,7 @@ export namespace Telemetry {
135
271
 
136
272
  const attribute = domElement?.getAttribute("no-telemetry");
137
273
  if (attribute === "" || attribute === "true" || attribute === "1") {
138
- if (NEEDLE_ENGINE_LICENSE_TYPE === "pro" || NEEDLE_ENGINE_LICENSE_TYPE === "enterprise") {
274
+ if (EzdGPQg === "pro" || EzdGPQg === "enterprise") {
139
275
  if (debug) console.debug("Telemetry is disabled via no-telemetry attribute");
140
276
  return false;
141
277
  }
@@ -242,22 +378,32 @@ export namespace Telemetry {
242
378
  }
243
379
 
244
380
 
245
- export function initLicense() {
381
+ export function _$AnFl() {
382
+
383
+ if(EzdGPQg === "") EzdGPQg = "basic";
384
+
385
+ // Start JWT verification — must be here (not top-level) to avoid tree-shaking
386
+ _jwtVerificationPromise = _EyK();
387
+
246
388
  Telemetry.init();
247
389
  ContextRegistry.registerCallback(ContextEvent.ContextRegistered, evt => {
248
- showLicenseInfo(evt.context);
249
- handleForbidden(evt.context);
250
- setTimeout(() => sendUsageMessageToAnalyticsBackend(evt.context), 2000);
390
+ $vyRL(evt.context);
391
+ uZY(evt.context);
392
+ setTimeout(() => cEROvL(evt.context), 2000);
251
393
  });
252
394
  }
253
395
 
254
- export let runtimeLicenseCheckPromise: Promise<void> | undefined = undefined;
396
+ export let _$oYJ: Promise<void> | undefined = undefined;
255
397
  let applicationIsForbidden = false;
256
398
  let applicationForbiddenText = "";
257
- async function checkLicense() {
399
+ async function __lVbhf() {
258
400
  // Only perform the runtime license check once
259
- if (runtimeLicenseCheckPromise) return runtimeLicenseCheckPromise;
260
- if (NEEDLE_ENGINE_LICENSE_TYPE === "basic") {
401
+ if (_$oYJ) return _$oYJ;
402
+ // Wait for JWT verification to complete first (if running)
403
+ if (_jwtVerificationPromise) {
404
+ await _jwtVerificationPromise;
405
+ }
406
+ if (EzdGPQg === "basic") {
261
407
  try {
262
408
  const licenseUrl = "https://needle.tools/api/v1/needle-engine/check?location=" + encodeURIComponent(window.location.href) + "&version=" + VERSION + "&generator=" + encodeURIComponent(GENERATOR);
263
409
  const res = await fetch(licenseUrl, {
@@ -269,29 +415,29 @@ async function checkLicense() {
269
415
  if (res?.status === 200) {
270
416
  applicationIsForbidden = false;
271
417
  if (debug) console.log("License check succeeded");
272
- NEEDLE_ENGINE_LICENSE_TYPE = "pro";
273
- invokeLicenseCheckResultChanged(true);
418
+ EzdGPQg = "pro";
419
+ cLH(true);
274
420
  }
275
421
  else if (res?.status === 403) {
276
- invokeLicenseCheckResultChanged(false);
422
+ cLH(false);
277
423
  applicationIsForbidden = true;
278
424
  applicationForbiddenText = await res.text();
279
425
  }
280
426
  else {
281
- invokeLicenseCheckResultChanged(false);
427
+ cLH(false);
282
428
  if (debug) console.log("License check failed with status " + res?.status);
283
429
  }
284
430
  }
285
431
  catch (err) {
286
- invokeLicenseCheckResultChanged(false);
432
+ cLH(false);
287
433
  if (debug) console.error("License check failed", err);
288
434
  }
289
435
  }
290
- else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + NEEDLE_ENGINE_LICENSE_TYPE + "\"");
436
+ else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + EzdGPQg + "\"");
291
437
  }
292
- runtimeLicenseCheckPromise = checkLicense();
438
+ _$oYJ = __lVbhf();
293
439
 
294
- async function handleForbidden(ctx: IContext) {
440
+ async function uZY(ctx: IContext) {
295
441
  function createForbiddenElement() {
296
442
  const div = document.createElement("div");
297
443
  div.className = "needle-forbidden";
@@ -356,40 +502,40 @@ async function handleForbidden(ctx: IContext) {
356
502
  }, 500)
357
503
  }
358
504
 
359
- async function showLicenseInfo(ctx: IContext) {
505
+ async function $vyRL(ctx: IContext) {
360
506
  try {
361
- if (!hasProLicense() && !hasIndieLicense()) {
362
- return onNonCommercialVersionDetected(ctx);
507
+ if (!_cxKhKwDL() && !__otwqOR()) {
508
+ return LGWV(ctx);
363
509
  }
364
510
  }
365
511
  catch (err) {
366
512
  if (debug) console.log("License check failed", err)
367
- return onNonCommercialVersionDetected(ctx)
513
+ return LGWV(ctx)
368
514
  }
369
- if (debug) onNonCommercialVersionDetected(ctx)
515
+ if (debug) LGWV(ctx)
370
516
  }
371
517
 
372
518
 
373
519
 
374
- async function onNonCommercialVersionDetected(ctx: IContext) {
520
+ async function LGWV(ctx: IContext) {
375
521
 
376
522
  // if the engine loads faster than the license check, we need to capture the ready event here
377
523
  let isReady = false;
378
524
  ctx.domElement.addEventListener("ready", () => isReady = true);
379
525
 
380
- await runtimeLicenseCheckPromise?.catch(() => { });
526
+ await _$oYJ?.catch(() => { });
381
527
 
382
528
 
383
- if (hasProLicense() || hasIndieLicense()) return;
384
- if (hasCommercialLicense() === false) logNonCommercialUse();
529
+ if (_cxKhKwDL() || __otwqOR()) return;
530
+ if (LynjGsV() === false) _kYgJQd();
385
531
 
386
532
  // check if the engine is already ready (meaning has finished loading)
387
533
  if (isReady) {
388
- insertNonCommercialUseHint(ctx);
534
+ _$XDPaPw(ctx);
389
535
  }
390
536
  else {
391
537
  ctx.domElement.addEventListener("ready", () => {
392
- insertNonCommercialUseHint(ctx);
538
+ _$XDPaPw(ctx);
393
539
  });
394
540
  }
395
541
  }
@@ -397,7 +543,7 @@ async function onNonCommercialVersionDetected(ctx: IContext) {
397
543
  // const licenseElementIdentifier = "needle-license-element";
398
544
  // const licenseDuration = 10000;
399
545
  // const licenseDelay = 1200;
400
- function insertNonCommercialUseHint(ctx: IContext) {
546
+ function _$XDPaPw(ctx: IContext) {
401
547
 
402
548
  const style = `
403
549
  position: relative;
@@ -410,7 +556,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
410
556
  padding: 10px;
411
557
  padding-left: 30px;
412
558
  `;
413
- if (NEEDLE_ENGINE_LICENSE_TYPE === "edu") {
559
+ if (EzdGPQg === "edu") {
414
560
  if (navigator.webdriver) {
415
561
  console.log("This project is supported by Needle for Education – https://needle.tools");
416
562
  }
@@ -467,7 +613,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
467
613
  }
468
614
  }, 1000);
469
615
 
470
- if (hasEduLicense()) {
616
+ if (__mPmwPS()) {
471
617
  const removeDelay = 20_000;
472
618
  setTimeout(() => {
473
619
  clearInterval(interval);
@@ -476,7 +622,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
476
622
  const intervalInMinutes = 5;
477
623
  setTimeout(() => {
478
624
  if (ctx.domElement.parentNode)
479
- insertNonCommercialUseHint(ctx);
625
+ _$XDPaPw(ctx);
480
626
  }, 1000 * 60 * intervalInMinutes)
481
627
  }, removeDelay);
482
628
  }
@@ -487,7 +633,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
487
633
  const base64Logo = "data:image/webp;base64,UklGRrABAABXRUJQVlA4WAoAAAAQAAAAHwAAHwAAQUxQSKEAAAARN6CmbSM4WR7vdARON11EBDq3fLiNbVtVzpMCPlKAEzsx0Y/x+Ovuv4dn0EFE/ydAvz6YggXzgh5sVgXM/zOC/4sii7qgGvB5N7hmuQYwkvazWAu1JPW41FXSHq6pnaQWvqYH18Fc0j1hO/BFTtIeSBlJi5w6qIIO7IOrwhFsB2Yxukif0FTRLpXswHR8MxbslKe9VZsn/Ub5C7YFOpqSTABWUDgg6AAAAFAGAJ0BKiAAIAA+7VyoTqmkpCI3+qgBMB2JbACdMt69DwMIQBLhkTO6XwY00UEDK6cNIDnuNibPf0EgAP7Y1myuiQHLDsF/0h5unrGh6WAbv7aegg2ZMd3uRKfT/3SJztcaujYfTvMXspfCTmYcoO6a+vhC3ss4M8uM58t4siiu59I4aOl59e9Sr6xoxYlHf2v+NnBNpJYeJf8jABQAId/PXuBkLEFkiCucgSGEcfhvajql/j3reCGl0M5/9gQWy7ayNPs+wlvIxFnNfSlfuND4CZOCyxOHhRqOmHN4ULHo3tCSrUNvgAA=";
488
634
 
489
635
  let lastLogTime = 0;
490
- async function logNonCommercialUse(_logo?: string) {
636
+ async function _kYgJQd(_logo?: string) {
491
637
  const now = Date.now();
492
638
  if (now - lastLogTime < 2000) return;
493
639
  lastLogTime = now;
@@ -520,7 +666,7 @@ async function logNonCommercialUse(_logo?: string) {
520
666
  }
521
667
 
522
668
 
523
- async function sendUsageMessageToAnalyticsBackend(context: IContext) {
669
+ async function cEROvL(context: IContext) {
524
670
  // We can't send beacons from cross-origin isolated pages
525
671
  if (window.crossOriginIsolated) return;
526
672
 
@@ -535,7 +681,7 @@ async function sendUsageMessageToAnalyticsBackend(context: IContext) {
535
681
 
536
682
  // current url without query parameters
537
683
  const currentUrl = window.location.href.split("?")[0];
538
- const license = NEEDLE_ENGINE_LICENSE_TYPE;
684
+ const license = EzdGPQg;
539
685
 
540
686
  const beaconData = {
541
687
  license,
@@ -1,7 +1,7 @@
1
1
  import { FileLoader } from "three";
2
2
 
3
3
  import { showBalloonWarning } from "./debug/index.js";
4
- import { hasCommercialLicense } from "./engine_license.js";
4
+ import { LynjGsV } from "./engine_license.js";
5
5
  import { delay } from "./engine_utils.js";
6
6
  import { md5AsBytes, md5Hex, sha256Base64 } from "./engine_utils_hash.js";
7
7
 
@@ -45,7 +45,7 @@ export namespace BlobStorage {
45
45
  */
46
46
  export function canUpload(info: { filesize: number }) {
47
47
  const sizeInMB = info.filesize / 1024 / 1024;
48
- if (hasCommercialLicense()) {
48
+ if (LynjGsV()) {
49
49
  return sizeInMB < maxSizeInMB;
50
50
  }
51
51
  return sizeInMB < maxFreeSizeInMB;
@@ -100,7 +100,7 @@ export namespace BlobStorage {
100
100
  console.warn(`Your file is too large for uploading (${filesizeInMB.toFixed(1)}MB). Max allowed size is ${maxSizeInMB}MB`);
101
101
  return null;
102
102
  }
103
- else if (!hasCommercialLicense() && filesizeInMB > maxFreeSizeInMB) {
103
+ else if (!LynjGsV() && filesizeInMB > maxFreeSizeInMB) {
104
104
  if (opts?.silent !== true) showBalloonWarning(`File is too large for uploading. Please get a <a href=\"https://needle.tools/pricing\" target=\"_blank\">commercial license</a> to upload files larger than 5MB`);
105
105
  console.warn(`Your file is too large for uploading (${filesizeInMB.toFixed(1)}MB). Max size is 5MB for non-commercial users. Please get a commercial license at https://needle.tools/pricing for larger files (up to 50MB)`);
106
106
  return null;
@@ -402,11 +402,16 @@ export class RapierPhysics implements IPhysicsEngine {
402
402
  filterGroups?: number,
403
403
  /** Return false to ignore this collider */
404
404
  filterPredicate?: (c: ICollider) => boolean,
405
- /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
405
+ /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
406
406
  * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
407
- * @default undefined
407
+ * @default undefined
408
408
  */
409
- useIgnoreRaycastLayer?: boolean
409
+ useIgnoreRaycastLayer?: boolean,
410
+ /** When true, trigger/sensor colliders will be included in the raycast results.
411
+ * By default trigger colliders are skipped.
412
+ * @default false
413
+ */
414
+ includeTriggers?: boolean,
410
415
  })
411
416
  : null | { point: Vector3, collider: ICollider } {
412
417
 
@@ -428,6 +433,8 @@ export class RapierPhysics implements IPhysicsEngine {
428
433
 
429
434
  const hit = this.world?.castRay(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
430
435
  const component = c[$componentKey];
436
+ // Skip trigger/sensor colliders unless explicitly included
437
+ if (options?.includeTriggers !== true && component?.isTrigger) return false;
431
438
  if (options?.filterPredicate) return options.filterPredicate(component);
432
439
  if (options?.useIgnoreRaycastLayer !== false) {
433
440
  // ignore objects in the IgnoreRaycast=2 layer
@@ -453,11 +460,16 @@ export class RapierPhysics implements IPhysicsEngine {
453
460
  filterGroups?: number,
454
461
  /** Return false to ignore this collider */
455
462
  filterPredicate?: (c: ICollider) => boolean,
456
- /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
463
+ /** When enabled the hit object's layer will be tested. If layer 2 is enabled the object will be ignored (Layer 2 == IgnoreRaycast)
457
464
  * If not set the raycast will ignore objects in the IgnoreRaycast layer (default: true)
458
- * @default undefined
465
+ * @default undefined
459
466
  */
460
- useIgnoreRaycastLayer?: boolean
467
+ useIgnoreRaycastLayer?: boolean,
468
+ /** When true, trigger/sensor colliders will be included in the raycast results.
469
+ * By default trigger colliders are skipped.
470
+ * @default false
471
+ */
472
+ includeTriggers?: boolean,
461
473
  })
462
474
  : null | { point: Vector3, normal: Vector3, collider: ICollider } {
463
475
 
@@ -478,6 +490,8 @@ export class RapierPhysics implements IPhysicsEngine {
478
490
 
479
491
  const hit = this.world?.castRayAndGetNormal(ray, maxDistance, solid, options?.queryFilterFlags, options?.filterGroups, undefined, undefined, (c) => {
480
492
  const component = c[$componentKey];
493
+ // Skip trigger/sensor colliders unless explicitly included
494
+ if (options?.includeTriggers !== true && component?.isTrigger) return false;
481
495
  if (options?.filterPredicate) return options.filterPredicate(component);
482
496
  if (options?.useIgnoreRaycastLayer !== false) {
483
497
  // ignore objects in the IgnoreRaycast=2 layer
@@ -521,20 +521,25 @@ export interface IPhysicsEngine {
521
521
  /** True if you want to also hit objects when the raycast starts from inside a collider */
522
522
  solid?: boolean,
523
523
  queryFilterFlags?: QueryFilterFlags,
524
- /**
525
- * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
526
- * The scene query will only consider hits with colliders with collision groups compatible with
524
+ /**
525
+ * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
526
+ * The scene query will only consider hits with colliders with collision groups compatible with
527
527
  * this collision group (using the bitwise test described in the collision groups section).
528
- * For example membership 0x0001 and filter 0x0002 should be 0x00010002
528
+ * For example membership 0x0001 and filter 0x0002 should be 0x00010002
529
529
  * @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
530
530
  */
531
531
  filterGroups?: number,
532
- /**
532
+ /**
533
533
  * Predicate to filter colliders in raycast results
534
534
  * @param collider The collider being tested
535
535
  * @returns False to ignore this collider, true to include it
536
536
  */
537
- filterPredicate?: (collider: ICollider) => boolean
537
+ filterPredicate?: (collider: ICollider) => boolean,
538
+ /** When true, trigger/sensor colliders will be included in the raycast results.
539
+ * By default trigger colliders are skipped.
540
+ * @default false
541
+ */
542
+ includeTriggers?: boolean,
538
543
  }): RaycastResult;
539
544
 
540
545
  /**
@@ -549,20 +554,25 @@ export interface IPhysicsEngine {
549
554
  /** True if you want to also hit objects when the raycast starts from inside a collider */
550
555
  solid?: boolean,
551
556
  queryFilterFlags?: QueryFilterFlags,
552
- /**
553
- * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
554
- * The scene query will only consider hits with colliders with collision groups compatible with
557
+ /**
558
+ * Raycast filter groups. Groups are used to apply the collision group rules for the scene query.
559
+ * The scene query will only consider hits with colliders with collision groups compatible with
555
560
  * this collision group (using the bitwise test described in the collision groups section).
556
- * For example membership 0x0001 and filter 0x0002 should be 0x00010002
561
+ * For example membership 0x0001 and filter 0x0002 should be 0x00010002
557
562
  * @see https://rapier.rs/docs/user_guides/javascript/colliders#collision-groups-and-solver-groups
558
563
  */
559
564
  filterGroups?: number,
560
- /**
565
+ /**
561
566
  * Predicate to filter colliders in raycast results
562
567
  * @param collider The collider being tested
563
568
  * @returns False to ignore this collider, true to include it
564
569
  */
565
- filterPredicate?: (collider: ICollider) => boolean
570
+ filterPredicate?: (collider: ICollider) => boolean,
571
+ /** When true, trigger/sensor colliders will be included in the raycast results.
572
+ * By default trigger colliders are skipped.
573
+ * @default false
574
+ */
575
+ includeTriggers?: boolean,
566
576
  }): RaycastResult;
567
577
 
568
578
  /**
@@ -4,7 +4,7 @@ import { Quaternion, Vector2, Vector3, Vector4 } from "three";
4
4
 
5
5
  import { needleLogoOnlySVG } from "./assets/index.js";
6
6
  import { isDevEnvironment } from "./debug/debug.js";
7
- import { hasCommercialLicense } from "./engine_license.js";
7
+ import { LynjGsV } from "./engine_license.js";
8
8
  import { InternalAttributeUtils } from "./engine_utils_attributes.js";
9
9
  import type { NeedleEngineWebComponent } from "./webcomponents/needle-engine.js";
10
10
 
@@ -135,7 +135,7 @@ async function internalRenderQRCodeOverlays(canvas: HTMLCanvasElement, args: { s
135
135
  console.debug("[QR Code] No web component found")
136
136
  }
137
137
 
138
- const canUseCustomLogo = hasCommercialLicense();
138
+ const canUseCustomLogo = LynjGsV();
139
139
 
140
140
  // Query logo src from needle-engine attribute.
141
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)
@@ -2,7 +2,7 @@ import { Mesh, Object3D, TextureLoader, Vector4 } from "three";
2
2
  import ThreeMeshUI from "three-mesh-ui";
3
3
 
4
4
  import { addNewComponent } from "../../engine_components.js";
5
- import { hasProLicense } from "../../engine_license.js";
5
+ import { _cxKhKwDL } from "../../engine_license.js";
6
6
  import { OneEuroFilterXYZ } from "../../engine_math.js";
7
7
  import type { Context } from "../../engine_setup.js";
8
8
  import { lookAtObject } from "../../engine_three_utils.js";
@@ -321,7 +321,7 @@ export class NeedleSpatialMenu {
321
321
  }
322
322
  if (this.menu) {
323
323
  const index = this.menu.children.indexOf(this._poweredByNeedleElement as any);
324
- if (!this._showNeedleLogo && hasProLicense()) {
324
+ if (!this._showNeedleLogo && _cxKhKwDL()) {
325
325
  if (index >= 0) {
326
326
  this._poweredByNeedleElement.removeFromParent();
327
327
  this.markDirty();
@@ -1,6 +1,6 @@
1
1
  import { showBalloonMessage } from "../../debug/debug.js";
2
2
  import type { Context } from "../../engine_context.js";
3
- import { hasCommercialLicense, onLicenseCheckResultChanged, Telemetry } from "../../engine_license.js";
3
+ import { LynjGsV, $yRlAEF, Telemetry } from "../../engine_license.js";
4
4
  import { isLocalNetwork } from "../../engine_networking_utils.js";
5
5
  import { HTMLElementBase } from "../../engine_ssr.js";
6
6
  import { DeviceUtilities, getParam } from "../../engine_utils.js";
@@ -778,8 +778,8 @@ export class NeedleMenuElement extends HTMLElementBase {
778
778
  try {
779
779
  // if the user has a license then we CAN hide the needle logo
780
780
  // calling this method immediately will cause an issue with vite bundling tho
781
- window.requestAnimationFrame(() => onLicenseCheckResultChanged(res => {
782
- if (res == true && hasCommercialLicense() && !debugNonCommercial) {
781
+ window.requestAnimationFrame(() => $yRlAEF(res => {
782
+ if (res == true && LynjGsV() && !debugNonCommercial) {
783
783
  let visible = this._userRequestedLogoVisible;
784
784
  if (visible === undefined) visible = false;
785
785
  this.___onSetLogoVisible(visible);
@@ -830,7 +830,7 @@ export class NeedleMenuElement extends HTMLElementBase {
830
830
  // ensure the menu is not hidden or removed
831
831
  const requiredParent = this?.parentNode;
832
832
  if (this.style.display != "flex" || this.style.visibility != "visible" || this.style.opacity != "1" || requiredParent != this._domElement?.shadowRoot) {
833
- if (!hasCommercialLicense()) {
833
+ if (!LynjGsV()) {
834
834
  const change = changeEventCounter++;
835
835
  // if a user doesn't have a local pro license *but* for development the menu is hidden then we show a warning
836
836
  if (isLocalNetwork() && this._userRequestedMenuVisible === false) {
@@ -918,7 +918,7 @@ export class NeedleMenuElement extends HTMLElementBase {
918
918
  showNeedleLogo(visible: boolean) {
919
919
  this._userRequestedLogoVisible = visible;
920
920
  if (!visible) {
921
- if (!hasCommercialLicense() || debugNonCommercial) {
921
+ if (!LynjGsV() || debugNonCommercial) {
922
922
  console.warn("[Needle Engine] You need a PRO license to hide the Needle Engine logo in production.");
923
923
  const localNetwork = isLocalNetwork()
924
924
  if (!localNetwork) return;