@needle-tools/engine 6.0.0-alpha.4 → 6.0.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 (65) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +11 -1
  3. package/dist/{gltf-progressive-CcSfG2Ja.js → gltf-progressive-B7lOWdLe.js} +117 -115
  4. package/dist/gltf-progressive-BpT9M5Mt.umd.cjs +10 -0
  5. package/dist/gltf-progressive-D0rzvhNG.min.js +10 -0
  6. package/dist/{materialx-B3qY8vPU.js → materialx-Bd9BE6LR.js} +1 -1
  7. package/dist/{materialx-BwYvA-4x.umd.cjs → materialx-CzRx9AGf.umd.cjs} +2 -2
  8. package/dist/{materialx-CTPhpPxI.min.js → materialx-x1m4IJd1.min.js} +1 -1
  9. package/dist/{needle-engine.bundle-Bmcb5t3w.min.js → needle-engine.bundle-D6mZl1dR.min.js} +29 -29
  10. package/dist/{needle-engine.bundle-BuUj9B4K.umd.cjs → needle-engine.bundle-DOHf03pR.umd.cjs} +14 -14
  11. package/dist/{needle-engine.bundle-0tD9EcNs.js → needle-engine.bundle-Hu7ZAxEI.js} +75 -69
  12. package/dist/needle-engine.d.ts +5 -5
  13. package/dist/needle-engine.js +192 -192
  14. package/dist/needle-engine.min.js +1 -1
  15. package/dist/needle-engine.umd.cjs +1 -1
  16. package/dist/{vendor-BQUQwut5.js → vendor-BatPc34p.js} +50 -41
  17. package/dist/{vendor-BJviq-Oq.umd.cjs → vendor-CDN1hirK.umd.cjs} +1 -1
  18. package/dist/{vendor-CdNldo8c.min.js → vendor-T07c_9f_.min.js} +1 -1
  19. package/lib/engine/api.d.ts +1 -1
  20. package/lib/engine/api.js +1 -1
  21. package/lib/engine/api.js.map +1 -1
  22. package/lib/engine/engine_init.js +2 -2
  23. package/lib/engine/engine_init.js.map +1 -1
  24. package/lib/engine/engine_license.d.ts +7 -7
  25. package/lib/engine/engine_license.js +98 -78
  26. package/lib/engine/engine_license.js.map +1 -1
  27. package/lib/engine/engine_networking_blob.js +3 -3
  28. package/lib/engine/engine_networking_blob.js.map +1 -1
  29. package/lib/engine/engine_utils_qrcode.js +2 -2
  30. package/lib/engine/engine_utils_qrcode.js.map +1 -1
  31. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  32. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  33. package/lib/engine/webcomponents/needle menu/needle-menu.js +5 -5
  34. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  35. package/lib/engine/webcomponents/needle-engine.js +2 -2
  36. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  37. package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
  38. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  39. package/lib/engine/xr/TempXRContext.js +2 -2
  40. package/lib/engine/xr/TempXRContext.js.map +1 -1
  41. package/lib/engine-components/Renderer.d.ts +1 -1
  42. package/lib/engine-components/Renderer.js +2 -11
  43. package/lib/engine-components/Renderer.js.map +1 -1
  44. package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
  45. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  46. package/package.json +6 -3
  47. package/plugins/common/license.js +4 -4
  48. package/plugins/license/README.md +38 -0
  49. package/plugins/license/cli.js +46 -0
  50. package/plugins/license/index.js +24 -0
  51. package/plugins/vite/license.js +4 -4
  52. package/src/engine/api.ts +1 -1
  53. package/src/engine/engine_init.ts +2 -2
  54. package/src/engine/engine_license.ts +93 -76
  55. package/src/engine/engine_networking_blob.ts +3 -3
  56. package/src/engine/engine_utils_qrcode.ts +2 -2
  57. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
  58. package/src/engine/webcomponents/needle menu/needle-menu.ts +5 -5
  59. package/src/engine/webcomponents/needle-engine.loading.ts +2 -2
  60. package/src/engine/webcomponents/needle-engine.ts +2 -2
  61. package/src/engine/xr/TempXRContext.ts +2 -2
  62. package/src/engine-components/Renderer.ts +4 -13
  63. package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
  64. package/dist/gltf-progressive-BYG9UH7O.min.js +0 -10
  65. package/dist/gltf-progressive-sK--FWg7.umd.cjs +0 -10
@@ -0,0 +1,24 @@
1
+ // @ts-check
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { getMeta } from "../common/config.cjs";
5
+ import { resolveLicense } from "../common/license.js";
6
+
7
+ /**
8
+ * Write a signed license file for a site that does not use a Needle build plugin.
9
+ * The file contains only the public, signed JWT. Never write the Cloud access token.
10
+ * @param {{ out?: string, team?: string, accessToken?: string }} [options]
11
+ * @returns {Promise<{ output: string, signed: boolean }>}
12
+ */
13
+ export async function generateLicenseFile(options = {}) {
14
+ const output = resolve(options.out ?? "public/needle-license.json");
15
+ mkdirSync(dirname(output), { recursive: true });
16
+ // Clear a previous license before resolving, including when resolution throws.
17
+ writeFileSync(output, '{"jwt":""}\n');
18
+ const team = options.team ?? getMeta()?.license?.team;
19
+ const license = /** @type {{ jwt: string | null } | null} */ (
20
+ /** @type {unknown} */ (await resolveLicense({ team, accessToken: options.accessToken }))
21
+ );
22
+ if (license?.jwt) writeFileSync(output, JSON.stringify({ jwt: license.jwt }) + "\n");
23
+ return { output, signed: Boolean(license?.jwt) };
24
+ }
@@ -49,12 +49,12 @@ export function needleLicense(command, config, userSettings) {
49
49
  let modified = false;
50
50
 
51
51
  // Replace license type
52
- const index = src.indexOf("btgRyBvJ");
52
+ const index = src.indexOf("__deG");
53
53
  if (index >= 0) {
54
54
  const end = src.indexOf(";", index);
55
55
  if (end >= 0) {
56
56
  const line = src.substring(index, end);
57
- const replaced = "btgRyBvJ = \"" + licenseResult.type + "\"";
57
+ const replaced = "__deG = \"" + licenseResult.type + "\"";
58
58
  src = src.replace(line, replaced);
59
59
  modified = true;
60
60
  }
@@ -62,12 +62,12 @@ export function needleLicense(command, config, userSettings) {
62
62
 
63
63
  // Replace license JWT (same pattern)
64
64
  if (licenseResult.jwt) {
65
- const jwtIndex = src.indexOf("__rmQg");
65
+ const jwtIndex = src.indexOf("yDKPfo");
66
66
  if (jwtIndex >= 0) {
67
67
  const jwtEnd = src.indexOf(";", jwtIndex);
68
68
  if (jwtEnd >= 0) {
69
69
  const jwtLine = src.substring(jwtIndex, jwtEnd);
70
- const jwtReplaced = "__rmQg = \"" + licenseResult.jwt + "\"";
70
+ const jwtReplaced = "yDKPfo = \"" + licenseResult.jwt + "\"";
71
71
  src = src.replace(jwtLine, jwtReplaced);
72
72
  modified = true;
73
73
  }
package/src/engine/api.ts CHANGED
@@ -237,7 +237,7 @@ export * from "./engine_input.js";
237
237
  export { InstancingUtil } from "./engine_instancing.js";
238
238
 
239
239
  /** License checking utilities */
240
- export { _$IqaqwY, $TNE, $vnStLM } from "./engine_license.js";
240
+ export { KLnyx, _$sHuA, $jVksoCHS } from "./engine_license.js";
241
241
 
242
242
 
243
243
  // ============================================================================
@@ -8,7 +8,7 @@ import { initBuiltinTypes } from "./codegen/register_types.js";
8
8
  import { initSpatialConsole } from "./debug/debug_spatial_console.js";
9
9
  import { initAddressableSerializers } from "./engine_addressables.js";
10
10
  import { ensureAudioContextIsResumed } from "./engine_audio.js";
11
- import { FiUWO } from "./engine_license.js";
11
+ import { $bqSkkSKJ } from "./engine_license.js";
12
12
  import { initNeedleLoader } from "./engine_loaders.js";
13
13
  import { initPhysics } from "./engine_physics_rapier.js";
14
14
  import { initBuiltinSerializers } from "./engine_serialization_builtin_serializer.js";
@@ -59,7 +59,7 @@ export function initEngine() {
59
59
  initPhysics();
60
60
  initXR();
61
61
  initSpatialConsole();
62
- FiUWO();
62
+ $bqSkkSKJ();
63
63
 
64
64
  // Must be last. customElements.define() upgrades existing <needle-engine>
65
65
  // elements synchronously, which can trigger context.create() and dispatch
@@ -42,19 +42,19 @@ function setLicenseTimeout(ctx: IContext, callback: () => void, delay: number) {
42
42
  return timer;
43
43
  }
44
44
 
45
- const _$zlWB: ((result: boolean) => void)[] = [];
45
+ const _$hziI: ((result: boolean) => void)[] = [];
46
46
 
47
47
  // DO NOT EDIT MANUALLY
48
- let btgRyBvJ: string = "";
48
+ let __deG: string = "";
49
49
  // eslint-disable-next-line prefer-const
50
- let __rmQg: string = "";
50
+ let yDKPfo: string = "";
51
51
 
52
52
  if (debug) {
53
- console.log("License Type: " + btgRyBvJ);
54
- if (__rmQg) {
55
- console.log("License JWT: " + __rmQg);
53
+ console.log("License Type: " + __deG);
54
+ if (yDKPfo) {
55
+ console.log("License JWT: " + yDKPfo);
56
56
  try {
57
- const payload = JSON.parse(atob(__rmQg.split(".")[1].replace(/-/g, '+').replace(/_/g, '/')));
57
+ const payload = JSON.parse(atob(yDKPfo.split(".")[1].replace(/-/g, '+').replace(/_/g, '/')));
58
58
  console.log("License JWT payload:", payload);
59
59
  }
60
60
  catch { console.log("License JWT payload: (failed to decode)"); }
@@ -65,8 +65,8 @@ if (debug) {
65
65
  }
66
66
 
67
67
  /** @internal */
68
- export function $vnStLM() {
69
- switch (btgRyBvJ) {
68
+ export function $jVksoCHS() {
69
+ switch (__deG) {
70
70
  case "pro":
71
71
  case "enterprise":
72
72
  return true;
@@ -75,8 +75,8 @@ export function $vnStLM() {
75
75
  }
76
76
 
77
77
  /** @internal */
78
- export function $TNE() {
79
- switch (btgRyBvJ) {
78
+ export function _$sHuA() {
79
+ switch (__deG) {
80
80
  case "indie":
81
81
  return true;
82
82
  }
@@ -84,8 +84,8 @@ export function $TNE() {
84
84
  }
85
85
 
86
86
  /** @internal */
87
- export function $wyQnLr() {
88
- switch (btgRyBvJ) {
87
+ export function $BZiUJx() {
88
+ switch (__deG) {
89
89
  case "edu":
90
90
  return true;
91
91
  }
@@ -93,26 +93,26 @@ export function $wyQnLr() {
93
93
  }
94
94
 
95
95
  /** @internal */
96
- export function _$IqaqwY() {
97
- return $vnStLM() || $TNE() || $wyQnLr();
96
+ export function KLnyx() {
97
+ return $jVksoCHS() || _$sHuA() || $BZiUJx();
98
98
  }
99
99
 
100
100
 
101
101
  /** @internal */
102
- export function __YPGv(cb: (result: boolean) => void) {
103
- if ($vnStLM() || $TNE() || $wyQnLr()) {
102
+ export function _$jODX(cb: (result: boolean) => void) {
103
+ if ($jVksoCHS() || _$sHuA() || $BZiUJx()) {
104
104
  cb(true);
105
105
  return () => {};
106
106
  }
107
- _$zlWB.push(cb);
107
+ _$hziI.push(cb);
108
108
  return () => {
109
- const index = _$zlWB.indexOf(cb);
110
- if (index >= 0) _$zlWB.splice(index, 1);
109
+ const index = _$hziI.indexOf(cb);
110
+ if (index >= 0) _$hziI.splice(index, 1);
111
111
  };
112
112
  }
113
113
 
114
- function SpVw(result: boolean) {
115
- for (const cb of _$zlWB) {
114
+ function __QVQhCm(result: boolean) {
115
+ for (const cb of _$hziI) {
116
116
  try {
117
117
  cb(result);
118
118
  }
@@ -127,7 +127,7 @@ function SpVw(result: boolean) {
127
127
 
128
128
  // ECDSA P-256 public key for verifying license JWTs (verification-only, safe to ship)
129
129
  /* eslint-disable no-secrets/no-secrets -- public key, not a secret */
130
- const __xEfpTWY = {
130
+ const _UHT = {
131
131
  kty: "EC",
132
132
  crv: "P-256",
133
133
  x: "A34nyKMjhQYVgzeE4tyLUYdx34TAKogDa7v7PRaO9Lg",
@@ -151,7 +151,7 @@ function base64urlDecode(str: string): Uint8Array {
151
151
  * Verify a JWT license token and return the `type` claim if valid.
152
152
  * Returns null if the JWT is missing, malformed, or has an invalid signature.
153
153
  */
154
- async function QyCIa(jwt: string): Promise<string | null> {
154
+ async function _$IUNmiHVF(jwt: string): Promise<string | null> {
155
155
  if (!jwt) return null;
156
156
  try {
157
157
  const parts = jwt.split(".");
@@ -161,7 +161,7 @@ async function QyCIa(jwt: string): Promise<string | null> {
161
161
 
162
162
  const key = await crypto.subtle.importKey(
163
163
  "jwk",
164
- __xEfpTWY,
164
+ _UHT,
165
165
  { name: "ECDSA", namedCurve: "P-256" },
166
166
  false,
167
167
  ["verify"]
@@ -221,24 +221,40 @@ async function QyCIa(jwt: string): Promise<string | null> {
221
221
  }
222
222
 
223
223
  /** Verify the injected JWT and update the license type if valid.
224
- * The engine ONLY trusts the JWT — the plain btgRyBvJ string is ignored. */
224
+ * The engine ONLY trusts the JWT — the plain __deG string is ignored. */
225
225
  let _jwtVerificationPromise: Promise<void> | undefined = undefined;
226
- async function __hSxthgWC(): Promise<void> {
227
- // NOTE: do NOT add an `if (!__rmQg) return` guard here.
228
- // esbuild (Vite dependency pre-bundling) would see the variable as constant ""
229
- // and tree-shake the entire JWT verification code path.
230
- const jwt = __rmQg;
231
- // Clear after reading — this reassignment also prevents esbuild from
232
- // constant-folding the variable (it now has multiple assignment sites).
233
- __rmQg = "";
234
- const verifiedType = await QyCIa(jwt);
226
+ async function wJwFeUbX(): Promise<void> {
227
+ // The bundled JWT may be empty when a build supplies a signed license file.
228
+ // Do not return early: the meta tag below may provide the JWT instead.
229
+ // Keep the bundled binding mutable so Vite's esbuild pre-bundling does not
230
+ // treat its initial empty value as constant and remove JWT verification.
231
+ let jwt = yDKPfo;
232
+ // Clear the bundled JWT after reading it; this assignment keeps the binding mutable.
233
+ yDKPfo = "";
234
+ if (!jwt && typeof document !== "undefined") {
235
+ const licenseFile = document.querySelector('meta[name="needle-license"]')?.getAttribute("content");
236
+ if (licenseFile) {
237
+ try {
238
+ const url = new URL(licenseFile, document.baseURI);
239
+ const response = await fetch(url, { cache: "no-store" });
240
+ if (response.ok) {
241
+ const data = await response.json();
242
+ if (typeof data?.jwt === "string") jwt = data.jwt;
243
+ }
244
+ }
245
+ catch (err) {
246
+ if (debug) console.warn("Could not load signed license file", err);
247
+ }
248
+ }
249
+ }
250
+ const verifiedType = await _$IUNmiHVF(jwt);
235
251
  if (verifiedType) {
236
- btgRyBvJ = verifiedType;
252
+ __deG = verifiedType;
237
253
  if (debug) console.log("License type set from verified JWT: " + verifiedType);
238
- SpVw(_$IqaqwY());
254
+ __QVQhCm(KLnyx());
239
255
  }
240
256
  else {
241
- btgRyBvJ = "basic";
257
+ __deG = "basic";
242
258
  if (debug && jwt) console.warn("JWT verification failed — license reset to basic");
243
259
  }
244
260
  }
@@ -361,7 +377,7 @@ export namespace Telemetry {
361
377
  // NOTE: this does NOT affect license enforcement — the /check call, the "forbidden"
362
378
  // overlay and the watermark/logo run on separate, ungated code paths.
363
379
  const attribute = domElement?.getAttribute("no-telemetry");
364
- if ($vnStLM() && (attribute === "" || attribute === "true" || attribute === "1")) {
380
+ if ($jVksoCHS() && (attribute === "" || attribute === "true" || attribute === "1")) {
365
381
  if (debug) console.debug("Telemetry is disabled via no-telemetry attribute");
366
382
  return false;
367
383
  }
@@ -689,18 +705,21 @@ export namespace Telemetry {
689
705
  }
690
706
 
691
707
 
692
- export function FiUWO() {
708
+ export function $bqSkkSKJ() {
693
709
 
694
- if(btgRyBvJ === "") btgRyBvJ = "basic";
710
+ if(__deG === "") __deG = "basic";
695
711
 
696
712
  // Start JWT verification — must be here (not top-level) to avoid tree-shaking
697
- _jwtVerificationPromise = __hSxthgWC();
713
+ _jwtVerificationPromise = wJwFeUbX();
714
+ // Start after setting the initial type. At module scope the type was still "",
715
+ // so Basic builds skipped the runtime check entirely.
716
+ _$cThps = __zwPG();
698
717
 
699
718
  Telemetry.init();
700
719
  ContextRegistry.registerCallback(ContextEvent.ContextRegistered, evt => {
701
- __zUywTXF(evt.context);
702
- $FUD(evt.context);
703
- setLicenseTimeout(evt.context, () => __jDHSHz(evt.context), 2000);
720
+ pTWobY(evt.context);
721
+ _$XfWxk(evt.context);
722
+ setLicenseTimeout(evt.context, () => _YuMDhu(evt.context), 2000);
704
723
  });
705
724
  // ContextCreated fires after the renderer exists, so the canvas is available for context-loss monitoring
706
725
  ContextRegistry.registerCallback(ContextEvent.ContextCreated, evt => {
@@ -709,17 +728,17 @@ export function FiUWO() {
709
728
  });
710
729
  }
711
730
 
712
- export let __BOmm: Promise<void> | undefined = undefined;
731
+ export let _$cThps: Promise<void> | undefined = undefined;
713
732
  let applicationIsForbidden = false;
714
733
  let applicationForbiddenText = "";
715
- async function _$CByS() {
734
+ async function __zwPG() {
716
735
  // Only perform the runtime license check once
717
- if (__BOmm) return __BOmm;
736
+ if (_$cThps) return _$cThps;
718
737
  // Wait for JWT verification to complete first (if running)
719
738
  if (_jwtVerificationPromise) {
720
739
  await _jwtVerificationPromise;
721
740
  }
722
- if (btgRyBvJ === "basic") {
741
+ if (__deG === "basic") {
723
742
  try {
724
743
  const licenseUrl = "https://needle.tools/api/v1/needle-engine/check?location=" + encodeURIComponent(window.location.href) + "&version=" + VERSION + "&generator=" + encodeURIComponent(GENERATOR);
725
744
  const res = await fetch(licenseUrl, {
@@ -731,29 +750,27 @@ async function _$CByS() {
731
750
  if (res?.status === 200) {
732
751
  applicationIsForbidden = false;
733
752
  if (debug) console.log("License check succeeded");
734
- btgRyBvJ = "pro";
735
- SpVw(true);
753
+ __deG = "pro";
754
+ __QVQhCm(true);
736
755
  }
737
756
  else if (res?.status === 403) {
738
- SpVw(false);
757
+ __QVQhCm(false);
739
758
  applicationIsForbidden = true;
740
759
  applicationForbiddenText = await res.text();
741
760
  }
742
761
  else {
743
- SpVw(false);
762
+ __QVQhCm(false);
744
763
  if (debug) console.log("License check failed with status " + res?.status);
745
764
  }
746
765
  }
747
766
  catch (err) {
748
- SpVw(false);
767
+ __QVQhCm(false);
749
768
  if (debug) console.error("License check failed", err);
750
769
  }
751
770
  }
752
- else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + btgRyBvJ + "\"");
771
+ else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + __deG + "\"");
753
772
  }
754
- __BOmm = _$CByS();
755
-
756
- async function $FUD(ctx: IContext) {
773
+ async function _$XfWxk(ctx: IContext) {
757
774
  function createForbiddenElement() {
758
775
  const div = document.createElement("div");
759
776
  div.className = "needle-forbidden";
@@ -818,40 +835,40 @@ async function $FUD(ctx: IContext) {
818
835
  }, 500)
819
836
  }
820
837
 
821
- async function __zUywTXF(ctx: IContext) {
838
+ async function pTWobY(ctx: IContext) {
822
839
  try {
823
- if (!$vnStLM() && !$TNE()) {
824
- return fFIu(ctx);
840
+ if (!$jVksoCHS() && !_$sHuA()) {
841
+ return $KXTmgnjE(ctx);
825
842
  }
826
843
  }
827
844
  catch (err) {
828
845
  if (debug) console.log("License check failed", err)
829
- return fFIu(ctx)
846
+ return $KXTmgnjE(ctx)
830
847
  }
831
- if (debug) fFIu(ctx)
848
+ if (debug) $KXTmgnjE(ctx)
832
849
  }
833
850
 
834
851
 
835
852
 
836
- async function fFIu(ctx: IContext) {
853
+ async function $KXTmgnjE(ctx: IContext) {
837
854
 
838
855
  // if the engine loads faster than the license check, we need to capture the ready event here
839
856
  let isReady = false;
840
857
  ctx.domElement.addEventListener("ready", () => isReady = true);
841
858
 
842
- await __BOmm?.catch(() => { });
859
+ await _$cThps?.catch(() => { });
843
860
 
844
861
 
845
- if ($vnStLM() || $TNE()) return;
846
- if (_$IqaqwY() === false) Yjj();
862
+ if ($jVksoCHS() || _$sHuA()) return;
863
+ if (KLnyx() === false) $vKd();
847
864
 
848
865
  // check if the engine is already ready (meaning has finished loading)
849
866
  if (isReady) {
850
- fWqZoV(ctx);
867
+ __OzoZ(ctx);
851
868
  }
852
869
  else {
853
870
  ctx.domElement.addEventListener("ready", () => {
854
- fWqZoV(ctx);
871
+ __OzoZ(ctx);
855
872
  });
856
873
  }
857
874
  }
@@ -859,7 +876,7 @@ async function fFIu(ctx: IContext) {
859
876
  // const licenseElementIdentifier = "needle-license-element";
860
877
  // const licenseDuration = 10000;
861
878
  // const licenseDelay = 1200;
862
- function fWqZoV(ctx: IContext) {
879
+ function __OzoZ(ctx: IContext) {
863
880
 
864
881
  const style = `
865
882
  position: relative;
@@ -872,7 +889,7 @@ function fWqZoV(ctx: IContext) {
872
889
  padding: 10px;
873
890
  padding-left: 30px;
874
891
  `;
875
- if (btgRyBvJ === "edu") {
892
+ if (__deG === "edu") {
876
893
  if (navigator.webdriver) {
877
894
  console.log("This project is supported by Needle for Education – https://needle.tools");
878
895
  }
@@ -929,7 +946,7 @@ function fWqZoV(ctx: IContext) {
929
946
  }
930
947
  }, 1000);
931
948
 
932
- if ($wyQnLr()) {
949
+ if ($BZiUJx()) {
933
950
  const removeDelay = 20_000;
934
951
  setLicenseTimeout(ctx, () => {
935
952
  clearInterval(interval);
@@ -938,7 +955,7 @@ function fWqZoV(ctx: IContext) {
938
955
  const intervalInMinutes = 5;
939
956
  setLicenseTimeout(ctx, () => {
940
957
  if (ctx.domElement.parentNode)
941
- fWqZoV(ctx);
958
+ __OzoZ(ctx);
942
959
  }, 1000 * 60 * intervalInMinutes)
943
960
  }, removeDelay);
944
961
  }
@@ -949,7 +966,7 @@ function fWqZoV(ctx: IContext) {
949
966
  const base64Logo = "data:image/webp;base64,UklGRrABAABXRUJQVlA4WAoAAAAQAAAAHwAAHwAAQUxQSKEAAAARN6CmbSM4WR7vdARON11EBDq3fLiNbVtVzpMCPlKAEzsx0Y/x+Ovuv4dn0EFE/ydAvz6YggXzgh5sVgXM/zOC/4sii7qgGvB5N7hmuQYwkvazWAu1JPW41FXSHq6pnaQWvqYH18Fc0j1hO/BFTtIeSBlJi5w6qIIO7IOrwhFsB2Yxukif0FTRLpXswHR8MxbslKe9VZsn/Ub5C7YFOpqSTABWUDgg6AAAAFAGAJ0BKiAAIAA+7VyoTqmkpCI3+qgBMB2JbACdMt69DwMIQBLhkTO6XwY00UEDK6cNIDnuNibPf0EgAP7Y1myuiQHLDsF/0h5unrGh6WAbv7aegg2ZMd3uRKfT/3SJztcaujYfTvMXspfCTmYcoO6a+vhC3ss4M8uM58t4siiu59I4aOl59e9Sr6xoxYlHf2v+NnBNpJYeJf8jABQAId/PXuBkLEFkiCucgSGEcfhvajql/j3reCGl0M5/9gQWy7ayNPs+wlvIxFnNfSlfuND4CZOCyxOHhRqOmHN4ULHo3tCSrUNvgAA=";
950
967
 
951
968
  let lastLogTime = 0;
952
- async function Yjj(_logo?: string) {
969
+ async function $vKd(_logo?: string) {
953
970
  const now = Date.now();
954
971
  if (now - lastLogTime < 2000) return;
955
972
  lastLogTime = now;
@@ -982,7 +999,7 @@ async function Yjj(_logo?: string) {
982
999
  }
983
1000
 
984
1001
 
985
- async function __jDHSHz(context: IContext) {
1002
+ async function _YuMDhu(context: IContext) {
986
1003
  // isAllowed() now also covers cross-origin-isolated pages (where beacons can't be sent)
987
1004
  // and Do Not Track / GPC.
988
1005
  if (!Telemetry.isAllowed(context)) {
@@ -996,7 +1013,7 @@ async function __jDHSHz(context: IContext) {
996
1013
 
997
1014
  // current url without query parameters
998
1015
  const currentUrl = window.location.href.split("?")[0];
999
- const license = btgRyBvJ;
1016
+ const license = __deG;
1000
1017
 
1001
1018
  const beaconData = {
1002
1019
  license,
@@ -1,7 +1,7 @@
1
1
  import { FileLoader } from "three";
2
2
 
3
3
  import { showBalloonWarning } from "./debug/index.js";
4
- import { _$IqaqwY } from "./engine_license.js";
4
+ import { KLnyx } 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 (_$IqaqwY()) {
48
+ if (KLnyx()) {
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 (!_$IqaqwY() && filesizeInMB > maxFreeSizeInMB) {
103
+ else if (!KLnyx() && 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;
@@ -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 { _$IqaqwY } from "./engine_license.js";
7
+ import { KLnyx } 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 = _$IqaqwY();
138
+ const canUseCustomLogo = KLnyx();
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 { _$IqaqwY } from "../../engine_license.js";
5
+ import { KLnyx } 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 && _$IqaqwY()) {
324
+ if (!this._showNeedleLogo && KLnyx()) {
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 { _$IqaqwY, __YPGv, Telemetry } from "../../engine_license.js";
3
+ import { KLnyx, _$jODX, 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";
@@ -801,8 +801,8 @@ export class NeedleMenuElement extends HTMLElementBase {
801
801
  // calling this method immediately will cause an issue with vite bundling tho
802
802
  this._licenseFrame = window.requestAnimationFrame(() => {
803
803
  this._licenseFrame = undefined;
804
- this._unsubscribeLicense = __YPGv(res => {
805
- if (res == true && _$IqaqwY() && !debugNonCommercial) {
804
+ this._unsubscribeLicense = _$jODX(res => {
805
+ if (res == true && KLnyx() && !debugNonCommercial) {
806
806
  let visible = this._userRequestedLogoVisible;
807
807
  if (visible === undefined) visible = false;
808
808
  this.___onSetLogoVisible(visible);
@@ -854,7 +854,7 @@ export class NeedleMenuElement extends HTMLElementBase {
854
854
  // ensure the menu is not hidden or removed
855
855
  const requiredParent = this?.parentNode;
856
856
  if (this.style.display != "flex" || this.style.visibility != "visible" || this.style.opacity != "1" || requiredParent != this._domElement?.shadowRoot) {
857
- if (!_$IqaqwY()) {
857
+ if (!KLnyx()) {
858
858
  const change = changeEventCounter++;
859
859
  // if a user doesn't have a local pro license *but* for development the menu is hidden then we show a warning
860
860
  if (isLocalNetwork() && this._userRequestedMenuVisible === false) {
@@ -950,7 +950,7 @@ export class NeedleMenuElement extends HTMLElementBase {
950
950
  showNeedleLogo(visible: boolean) {
951
951
  this._userRequestedLogoVisible = visible;
952
952
  if (!visible) {
953
- if (!_$IqaqwY() || debugNonCommercial) {
953
+ if (!KLnyx() || debugNonCommercial) {
954
954
  console.warn("[Needle Engine] You need a commercial license to hide the Needle Engine logo in production.");
955
955
  const localNetwork = isLocalNetwork()
956
956
  if (!localNetwork) return;
@@ -1,6 +1,6 @@
1
1
  import { needleLogoOnlySVG } from "../assets/index.js"
2
2
  import { showBalloonWarning } from "../debug/index.js";
3
- import { $vnStLM } from "../engine_license.js";
3
+ import { $jVksoCHS } from "../engine_license.js";
4
4
  import { Mathf } from "../engine_math.js";
5
5
  import { LoadingProgressArgs } from "../engine_setup.js";
6
6
  import { getParam } from "../engine_utils.js";
@@ -402,7 +402,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
402
402
  const logoToggle = InternalAttributeUtils.getAttributeAndCheckFalsey(this._element, "loading-logo");
403
403
  const showLogo = logoToggle !== null && logoToggle !== false;
404
404
 
405
- const hasLicense = $vnStLM();
405
+ const hasLicense = $jVksoCHS();
406
406
 
407
407
  const className = this._loadingElementOptions?.className ?? EngineLoadingView.LoadingContainerClassName;
408
408
  el.classList.add(className);
@@ -3,7 +3,7 @@ import type { Texture } from "three";
3
3
  import { isDevEnvironment, showBalloonWarning } from "../debug/index.js";
4
4
  import { PUBLIC_KEY, VERSION } from "../engine_constants.js";
5
5
  import { ContextEvent, ContextRegistry } from "../engine_context_registry.js";
6
- import { _$IqaqwY, Telemetry } from "../engine_license.js";
6
+ import { KLnyx, Telemetry } from "../engine_license.js";
7
7
  import { onStart } from "../engine_lifecycle_api.js";
8
8
  import { setDracoDecoderPath, setDracoDecoderType, setKtx2TranscoderPath } from "../engine_loaders.gltf.js";
9
9
  import { Context, ContextCreateArgs } from "../engine_setup.js";
@@ -617,7 +617,7 @@ export class NeedleEngineWebComponent extends HTMLElementBase implements INeedle
617
617
 
618
618
 
619
619
  // Loading start events
620
- const allowOverridingDefaultLoading = _$IqaqwY();
620
+ const allowOverridingDefaultLoading = KLnyx();
621
621
  // default loading can be overriden by calling preventDefault in the onload start event
622
622
  this.ensureLoadStartIsRegistered();
623
623
  let useDefaultLoading = this.dispatchEvent(new CustomEvent("loadstart", {
@@ -3,7 +3,7 @@ import { ArrayCamera, AxesHelper, Camera, Color, DirectionalLight, Fog, GridHelp
3
3
  import { needleLogoOnlySVG } from "../assets/index.js";
4
4
  import { isDevEnvironment } from "../debug/index.js";
5
5
  import { ObjectUtils, PrimitiveType } from "../engine_create_objects.js";
6
- import { _$IqaqwY } from "../engine_license.js";
6
+ import { KLnyx } from "../engine_license.js";
7
7
  import { Mathf } from "../engine_math.js";
8
8
  import { delay, DeviceUtilities } from "../engine_utils.js";
9
9
 
@@ -215,7 +215,7 @@ export class TemporaryXRContext {
215
215
  this._scene.background = new Color(0x000000);
216
216
 
217
217
  let logoSrc = needleLogoOnlySVG;
218
- if (_$IqaqwY()) {
218
+ if (KLnyx()) {
219
219
  const htmlComponent = document.querySelector("needle-engine");
220
220
  if (htmlComponent) {
221
221
  const licenseLogo = htmlComponent.getAttribute("logo-src");
@@ -1,5 +1,5 @@
1
1
  import { getRaycastMesh } from "@needle-tools/gltf-progressive";
2
- import { AxesHelper, Material, Mesh, MeshBasicMaterial, MeshPhysicalMaterial, MeshStandardMaterial, Object3D, RawShaderMaterial, ShaderMaterial, SkinnedMesh, Texture, Vector4 } from "three";
2
+ import { AxesHelper, Material, Mesh, MeshPhysicalMaterial, MeshStandardMaterial, Object3D, RawShaderMaterial, ShaderMaterial, SkinnedMesh, Texture, Vector4 } from "three";
3
3
 
4
4
  import { showBalloonWarning } from "../engine/debug/index.js";
5
5
  import { getComponent, getOrAddComponent } from "../engine/engine_components.js";
@@ -305,21 +305,12 @@ export class Renderer extends Behaviour implements IRenderer {
305
305
  // private _materialProperties: Array<MaterialProperties> | undefined = undefined;
306
306
  private _lightmaps?: RendererLightmap[];
307
307
 
308
- /** Get the mesh Object3D for this renderer
309
- * Warn: if this is a multimaterial object it will return the first mesh only
308
+ /** Get the mesh Object3D for this renderer
309
+ * Warn: if this is a multimaterial object it will return the first submesh only (same as `sharedMeshes[0]`), use {@link sharedMeshes} to get all of them
310
310
  * @returns a mesh object3D.
311
311
  * */
312
312
  get sharedMesh(): Mesh | SkinnedMesh | undefined {
313
- if (this.gameObject.type === "Mesh") {
314
- return this.gameObject as unknown as Mesh
315
- }
316
- else if (this.gameObject.type === "SkinnesMesh") {
317
- return this.gameObject as unknown as SkinnedMesh;
318
- }
319
- else if (this.gameObject.type === "Group") {
320
- return this.gameObject.children[0] as unknown as Mesh;
321
- }
322
- return undefined;
313
+ return this.sharedMeshes[0];
323
314
  }
324
315
 
325
316
  private readonly _sharedMeshes: Mesh[] = [];