@needle-tools/engine 5.1.0-next.1780579670.dramatic-pierogi.b8fa941 → 5.1.0
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.
- package/CHANGELOG.md +119 -0
- package/components.needle.json +1 -1
- package/dist/gltf-progressive-BGQ-cjly.umd.cjs +10 -0
- package/dist/gltf-progressive-BvQHrERj.min.js +10 -0
- package/dist/{gltf-progressive-CH7aqHHr.js → gltf-progressive-CtYnVfLc.js} +420 -351
- package/dist/{materialx-B85WjP7E.min.js → materialx-B5gKeM65.min.js} +1 -1
- package/dist/{materialx-B47Bz-xs.umd.cjs → materialx-CFRcCYWy.umd.cjs} +1 -1
- package/dist/{materialx-jkHmVPez.js → materialx-DqGmteNO.js} +1 -1
- package/dist/{needle-engine.bundle-WQeWxmZD.js → needle-engine.bundle-5oIL49YP.js} +6826 -6685
- package/dist/{needle-engine.bundle-BSPk6RkD.min.js → needle-engine.bundle-DAAfj8Cs.min.js} +161 -149
- package/dist/{needle-engine.bundle-DCPHDPAd.umd.cjs → needle-engine.bundle-DvOrfXws.umd.cjs} +159 -147
- package/dist/needle-engine.d.ts +106 -44
- package/dist/needle-engine.js +610 -608
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three.js +3 -0
- package/dist/three.min.js +22 -22
- package/dist/three.umd.cjs +24 -24
- package/dist/{vendor-BQ2Vuntm.min.js → vendor-2--bD1c9.min.js} +19 -19
- package/dist/{vendor-BslSKZPo.js → vendor-BNtcIZkv.js} +1141 -1138
- package/dist/{vendor-1UvpPPSB.umd.cjs → vendor-vbe9sv1t.umd.cjs} +20 -20
- package/lib/engine/api.d.ts +1 -1
- package/lib/engine/api.js +1 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/engine_context.js +16 -3
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_init.js +2 -2
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_license.d.ts +7 -7
- package/lib/engine/engine_license.js +72 -72
- package/lib/engine/engine_license.js.map +1 -1
- package/lib/engine/engine_networking_blob.js +3 -3
- package/lib/engine/engine_networking_blob.js.map +1 -1
- package/lib/engine/engine_utils_qrcode.js +2 -2
- package/lib/engine/engine_utils_qrcode.js.map +1 -1
- package/lib/engine/postprocessing/postprocessing.d.ts +2 -1
- package/lib/engine/postprocessing/postprocessing.js +3 -2
- package/lib/engine/postprocessing/postprocessing.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu.js +9 -9
- package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.js +2 -2
- package/lib/engine/webcomponents/needle-engine.js.map +1 -1
- package/lib/engine/webcomponents/needle-engine.loading.js +2 -2
- package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
- package/lib/engine/xr/NeedleXRSession.d.ts +24 -0
- package/lib/engine/xr/NeedleXRSession.js +52 -7
- package/lib/engine/xr/NeedleXRSession.js.map +1 -1
- package/lib/engine/xr/TempXRContext.js +2 -2
- package/lib/engine/xr/TempXRContext.js.map +1 -1
- package/lib/engine/xr/init.js +2 -3
- package/lib/engine/xr/init.js.map +1 -1
- package/lib/engine-components/Component.js +14 -1
- package/lib/engine-components/Component.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +7 -2
- package/lib/engine-components/ContactShadows.js +65 -45
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/GroundProjection.d.ts +6 -0
- package/lib/engine-components/GroundProjection.js +69 -7
- package/lib/engine-components/GroundProjection.js.map +1 -1
- package/lib/engine-components/NeedleMenu.d.ts +1 -1
- package/lib/engine-components/NeedleMenu.js +5 -2
- package/lib/engine-components/NeedleMenu.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.d.ts +2 -0
- package/lib/engine-components/SceneSwitcher.js +26 -14
- package/lib/engine-components/SceneSwitcher.js.map +1 -1
- package/lib/engine-components/SeeThrough.d.ts +39 -0
- package/lib/engine-components/SeeThrough.js +69 -1
- package/lib/engine-components/SeeThrough.js.map +1 -1
- package/lib/engine-components/Skybox.js +9 -0
- package/lib/engine-components/Skybox.js.map +1 -1
- package/lib/engine-components/api.d.ts +1 -0
- package/lib/engine-components/api.js +1 -0
- package/lib/engine-components/api.js.map +1 -1
- package/lib/engine-components/export/usdz/USDZExporter.js +4 -4
- package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js +9 -5
- package/lib/engine-components/export/usdz/extensions/behavior/BehaviourComponents.js.map +1 -1
- package/lib/engine-components/particlesystem/ParticleSystem.js +4 -0
- package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
- package/lib/engine-components/postprocessing/Volume.d.ts +1 -9
- package/lib/engine-components/postprocessing/Volume.js +2 -14
- package/lib/engine-components/postprocessing/Volume.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +3 -0
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +4 -4
- package/plugins/common/license.js +4 -4
- package/plugins/types/userconfig.d.ts +10 -0
- package/plugins/vite/build-pipeline.d.ts +19 -0
- package/plugins/vite/build-pipeline.js +67 -5
- package/plugins/vite/license.js +4 -4
- package/src/engine/api.ts +1 -1
- package/src/engine/engine_context.ts +15 -2
- package/src/engine/engine_gameobject.ts +1 -1
- package/src/engine/engine_init.ts +2 -2
- package/src/engine/engine_license.ts +69 -69
- package/src/engine/engine_networking_blob.ts +3 -3
- package/src/engine/engine_utils_qrcode.ts +2 -2
- package/src/engine/postprocessing/postprocessing.ts +3 -2
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu.ts +10 -10
- package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
- package/src/engine/webcomponents/needle-engine.ts +2 -2
- package/src/engine/xr/NeedleXRSession.ts +53 -7
- package/src/engine/xr/TempXRContext.ts +2 -2
- package/src/engine/xr/init.ts +2 -3
- package/src/engine-components/Component.ts +13 -1
- package/src/engine-components/ContactShadows.ts +75 -49
- package/src/engine-components/GroundProjection.ts +71 -7
- package/src/engine-components/NeedleMenu.ts +6 -3
- package/src/engine-components/SceneSwitcher.ts +23 -13
- package/src/engine-components/SeeThrough.ts +75 -1
- package/src/engine-components/Skybox.ts +8 -0
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
- package/src/engine-components/export/usdz/extensions/behavior/BehaviourComponents.ts +12 -5
- package/src/engine-components/particlesystem/ParticleSystem.ts +4 -0
- package/src/engine-components/postprocessing/Volume.ts +2 -13
- package/src/engine-components/webxr/WebXRImageTracking.ts +1 -0
- package/dist/gltf-progressive-9tlS5iCx.umd.cjs +0 -10
- package/dist/gltf-progressive-CVg80COO.min.js +0 -10
|
@@ -9,19 +9,19 @@ import { getParam } from "./engine_utils.js";
|
|
|
9
9
|
|
|
10
10
|
const debug = getParam("__debuglic__");
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const __HMYWc: ((result: boolean) => void)[] = [];
|
|
13
13
|
|
|
14
14
|
// DO NOT EDIT MANUALLY
|
|
15
|
-
let
|
|
15
|
+
let _LquBhwVh: string = "";
|
|
16
16
|
// eslint-disable-next-line prefer-const
|
|
17
|
-
let
|
|
17
|
+
let BEvs: string = "";
|
|
18
18
|
|
|
19
19
|
if (debug) {
|
|
20
|
-
console.log("License Type: " +
|
|
21
|
-
if (
|
|
22
|
-
console.log("License JWT: " +
|
|
20
|
+
console.log("License Type: " + _LquBhwVh);
|
|
21
|
+
if (BEvs) {
|
|
22
|
+
console.log("License JWT: " + BEvs);
|
|
23
23
|
try {
|
|
24
|
-
const payload = JSON.parse(atob(
|
|
24
|
+
const payload = JSON.parse(atob(BEvs.split(".")[1].replace(/-/g, '+').replace(/_/g, '/')));
|
|
25
25
|
console.log("License JWT payload:", payload);
|
|
26
26
|
}
|
|
27
27
|
catch { console.log("License JWT payload: (failed to decode)"); }
|
|
@@ -32,8 +32,8 @@ if (debug) {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/** @internal */
|
|
35
|
-
export function
|
|
36
|
-
switch (
|
|
35
|
+
export function rXELCf() {
|
|
36
|
+
switch (_LquBhwVh) {
|
|
37
37
|
case "pro":
|
|
38
38
|
case "enterprise":
|
|
39
39
|
return true;
|
|
@@ -42,8 +42,8 @@ export function _$zFmYj() {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/** @internal */
|
|
45
|
-
export function
|
|
46
|
-
switch (
|
|
45
|
+
export function $RHhhju() {
|
|
46
|
+
switch (_LquBhwVh) {
|
|
47
47
|
case "indie":
|
|
48
48
|
return true;
|
|
49
49
|
}
|
|
@@ -51,8 +51,8 @@ export function _$DeHzisx() {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
/** @internal */
|
|
54
|
-
export function
|
|
55
|
-
switch (
|
|
54
|
+
export function FeDU() {
|
|
55
|
+
switch (_LquBhwVh) {
|
|
56
56
|
case "edu":
|
|
57
57
|
return true;
|
|
58
58
|
}
|
|
@@ -60,20 +60,20 @@ export function $nFnGL() {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
/** @internal */
|
|
63
|
-
export function
|
|
64
|
-
return
|
|
63
|
+
export function $iujBhf() {
|
|
64
|
+
return rXELCf() || $RHhhju() || FeDU();
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
/** @internal */
|
|
69
|
-
export function
|
|
70
|
-
if (
|
|
69
|
+
export function _$GTZ(cb: (result: boolean) => void) {
|
|
70
|
+
if (rXELCf() || $RHhhju() || FeDU())
|
|
71
71
|
return cb(true);
|
|
72
|
-
|
|
72
|
+
__HMYWc.push(cb);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function
|
|
76
|
-
for (const cb of
|
|
75
|
+
function _zbDz(result: boolean) {
|
|
76
|
+
for (const cb of __HMYWc) {
|
|
77
77
|
try {
|
|
78
78
|
cb(result);
|
|
79
79
|
}
|
|
@@ -88,7 +88,7 @@ function _hpBlmJnZ(result: boolean) {
|
|
|
88
88
|
|
|
89
89
|
// ECDSA P-256 public key for verifying license JWTs (verification-only, safe to ship)
|
|
90
90
|
/* eslint-disable no-secrets/no-secrets -- public key, not a secret */
|
|
91
|
-
const
|
|
91
|
+
const _FzlE = {
|
|
92
92
|
kty: "EC",
|
|
93
93
|
crv: "P-256",
|
|
94
94
|
x: "A34nyKMjhQYVgzeE4tyLUYdx34TAKogDa7v7PRaO9Lg",
|
|
@@ -112,7 +112,7 @@ function base64urlDecode(str: string): Uint8Array {
|
|
|
112
112
|
* Verify a JWT license token and return the `type` claim if valid.
|
|
113
113
|
* Returns null if the JWT is missing, malformed, or has an invalid signature.
|
|
114
114
|
*/
|
|
115
|
-
async function
|
|
115
|
+
async function _$jmD(jwt: string): Promise<string | null> {
|
|
116
116
|
if (!jwt) return null;
|
|
117
117
|
try {
|
|
118
118
|
const parts = jwt.split(".");
|
|
@@ -122,7 +122,7 @@ async function __ChbkwvSj(jwt: string): Promise<string | null> {
|
|
|
122
122
|
|
|
123
123
|
const key = await crypto.subtle.importKey(
|
|
124
124
|
"jwk",
|
|
125
|
-
|
|
125
|
+
_FzlE,
|
|
126
126
|
{ name: "ECDSA", namedCurve: "P-256" },
|
|
127
127
|
false,
|
|
128
128
|
["verify"]
|
|
@@ -182,24 +182,24 @@ async function __ChbkwvSj(jwt: string): Promise<string | null> {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/** Verify the injected JWT and update the license type if valid.
|
|
185
|
-
* The engine ONLY trusts the JWT — the plain
|
|
185
|
+
* The engine ONLY trusts the JWT — the plain _LquBhwVh string is ignored. */
|
|
186
186
|
let _jwtVerificationPromise: Promise<void> | undefined = undefined;
|
|
187
|
-
async function
|
|
188
|
-
// NOTE: do NOT add an `if (!
|
|
187
|
+
async function _gclCQI(): Promise<void> {
|
|
188
|
+
// NOTE: do NOT add an `if (!BEvs) return` guard here.
|
|
189
189
|
// esbuild (Vite dependency pre-bundling) would see the variable as constant ""
|
|
190
190
|
// and tree-shake the entire JWT verification code path.
|
|
191
|
-
const jwt =
|
|
191
|
+
const jwt = BEvs;
|
|
192
192
|
// Clear after reading — this reassignment also prevents esbuild from
|
|
193
193
|
// constant-folding the variable (it now has multiple assignment sites).
|
|
194
|
-
|
|
195
|
-
const verifiedType = await
|
|
194
|
+
BEvs = "";
|
|
195
|
+
const verifiedType = await _$jmD(jwt);
|
|
196
196
|
if (verifiedType) {
|
|
197
|
-
|
|
197
|
+
_LquBhwVh = verifiedType;
|
|
198
198
|
if (debug) console.log("License type set from verified JWT: " + verifiedType);
|
|
199
|
-
|
|
199
|
+
_zbDz($iujBhf());
|
|
200
200
|
}
|
|
201
201
|
else {
|
|
202
|
-
|
|
202
|
+
_LquBhwVh = "basic";
|
|
203
203
|
if (debug && jwt) console.warn("JWT verification failed — license reset to basic");
|
|
204
204
|
}
|
|
205
205
|
}
|
|
@@ -271,7 +271,7 @@ export namespace Telemetry {
|
|
|
271
271
|
|
|
272
272
|
const attribute = domElement?.getAttribute("no-telemetry");
|
|
273
273
|
if (attribute === "" || attribute === "true" || attribute === "1") {
|
|
274
|
-
if (
|
|
274
|
+
if (_LquBhwVh === "pro" || _LquBhwVh === "enterprise") {
|
|
275
275
|
if (debug) console.debug("Telemetry is disabled via no-telemetry attribute");
|
|
276
276
|
return false;
|
|
277
277
|
}
|
|
@@ -378,32 +378,32 @@ export namespace Telemetry {
|
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
|
|
381
|
-
export function
|
|
381
|
+
export function __tBFssqnm() {
|
|
382
382
|
|
|
383
|
-
if(
|
|
383
|
+
if(_LquBhwVh === "") _LquBhwVh = "basic";
|
|
384
384
|
|
|
385
385
|
// Start JWT verification — must be here (not top-level) to avoid tree-shaking
|
|
386
|
-
_jwtVerificationPromise =
|
|
386
|
+
_jwtVerificationPromise = _gclCQI();
|
|
387
387
|
|
|
388
388
|
Telemetry.init();
|
|
389
389
|
ContextRegistry.registerCallback(ContextEvent.ContextRegistered, evt => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
setTimeout(() =>
|
|
390
|
+
IiDral(evt.context);
|
|
391
|
+
_ZrecT(evt.context);
|
|
392
|
+
setTimeout(() => bdYvL(evt.context), 2000);
|
|
393
393
|
});
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
export let
|
|
396
|
+
export let $rKLNDMS: Promise<void> | undefined = undefined;
|
|
397
397
|
let applicationIsForbidden = false;
|
|
398
398
|
let applicationForbiddenText = "";
|
|
399
|
-
async function
|
|
399
|
+
async function _$aKpvmr() {
|
|
400
400
|
// Only perform the runtime license check once
|
|
401
|
-
if (
|
|
401
|
+
if ($rKLNDMS) return $rKLNDMS;
|
|
402
402
|
// Wait for JWT verification to complete first (if running)
|
|
403
403
|
if (_jwtVerificationPromise) {
|
|
404
404
|
await _jwtVerificationPromise;
|
|
405
405
|
}
|
|
406
|
-
if (
|
|
406
|
+
if (_LquBhwVh === "basic") {
|
|
407
407
|
try {
|
|
408
408
|
const licenseUrl = "https://needle.tools/api/v1/needle-engine/check?location=" + encodeURIComponent(window.location.href) + "&version=" + VERSION + "&generator=" + encodeURIComponent(GENERATOR);
|
|
409
409
|
const res = await fetch(licenseUrl, {
|
|
@@ -415,29 +415,29 @@ async function GNE() {
|
|
|
415
415
|
if (res?.status === 200) {
|
|
416
416
|
applicationIsForbidden = false;
|
|
417
417
|
if (debug) console.log("License check succeeded");
|
|
418
|
-
|
|
419
|
-
|
|
418
|
+
_LquBhwVh = "pro";
|
|
419
|
+
_zbDz(true);
|
|
420
420
|
}
|
|
421
421
|
else if (res?.status === 403) {
|
|
422
|
-
|
|
422
|
+
_zbDz(false);
|
|
423
423
|
applicationIsForbidden = true;
|
|
424
424
|
applicationForbiddenText = await res.text();
|
|
425
425
|
}
|
|
426
426
|
else {
|
|
427
|
-
|
|
427
|
+
_zbDz(false);
|
|
428
428
|
if (debug) console.log("License check failed with status " + res?.status);
|
|
429
429
|
}
|
|
430
430
|
}
|
|
431
431
|
catch (err) {
|
|
432
|
-
|
|
432
|
+
_zbDz(false);
|
|
433
433
|
if (debug) console.error("License check failed", err);
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
-
else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" +
|
|
436
|
+
else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + _LquBhwVh + "\"");
|
|
437
437
|
}
|
|
438
|
-
|
|
438
|
+
$rKLNDMS = _$aKpvmr();
|
|
439
439
|
|
|
440
|
-
async function
|
|
440
|
+
async function _ZrecT(ctx: IContext) {
|
|
441
441
|
function createForbiddenElement() {
|
|
442
442
|
const div = document.createElement("div");
|
|
443
443
|
div.className = "needle-forbidden";
|
|
@@ -502,40 +502,40 @@ async function nJF(ctx: IContext) {
|
|
|
502
502
|
}, 500)
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
async function
|
|
505
|
+
async function IiDral(ctx: IContext) {
|
|
506
506
|
try {
|
|
507
|
-
if (!
|
|
508
|
-
return
|
|
507
|
+
if (!rXELCf() && !$RHhhju()) {
|
|
508
|
+
return __CidXaFe(ctx);
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
511
|
catch (err) {
|
|
512
512
|
if (debug) console.log("License check failed", err)
|
|
513
|
-
return
|
|
513
|
+
return __CidXaFe(ctx)
|
|
514
514
|
}
|
|
515
|
-
if (debug)
|
|
515
|
+
if (debug) __CidXaFe(ctx)
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
|
|
519
519
|
|
|
520
|
-
async function
|
|
520
|
+
async function __CidXaFe(ctx: IContext) {
|
|
521
521
|
|
|
522
522
|
// if the engine loads faster than the license check, we need to capture the ready event here
|
|
523
523
|
let isReady = false;
|
|
524
524
|
ctx.domElement.addEventListener("ready", () => isReady = true);
|
|
525
525
|
|
|
526
|
-
await
|
|
526
|
+
await $rKLNDMS?.catch(() => { });
|
|
527
527
|
|
|
528
528
|
|
|
529
|
-
if (
|
|
530
|
-
if (
|
|
529
|
+
if (rXELCf() || $RHhhju()) return;
|
|
530
|
+
if ($iujBhf() === false) _$vPpCic();
|
|
531
531
|
|
|
532
532
|
// check if the engine is already ready (meaning has finished loading)
|
|
533
533
|
if (isReady) {
|
|
534
|
-
|
|
534
|
+
_UnZAOAPG(ctx);
|
|
535
535
|
}
|
|
536
536
|
else {
|
|
537
537
|
ctx.domElement.addEventListener("ready", () => {
|
|
538
|
-
|
|
538
|
+
_UnZAOAPG(ctx);
|
|
539
539
|
});
|
|
540
540
|
}
|
|
541
541
|
}
|
|
@@ -543,7 +543,7 @@ async function __hjIiBVlU(ctx: IContext) {
|
|
|
543
543
|
// const licenseElementIdentifier = "needle-license-element";
|
|
544
544
|
// const licenseDuration = 10000;
|
|
545
545
|
// const licenseDelay = 1200;
|
|
546
|
-
function
|
|
546
|
+
function _UnZAOAPG(ctx: IContext) {
|
|
547
547
|
|
|
548
548
|
const style = `
|
|
549
549
|
position: relative;
|
|
@@ -556,7 +556,7 @@ function wQoTi(ctx: IContext) {
|
|
|
556
556
|
padding: 10px;
|
|
557
557
|
padding-left: 30px;
|
|
558
558
|
`;
|
|
559
|
-
if (
|
|
559
|
+
if (_LquBhwVh === "edu") {
|
|
560
560
|
if (navigator.webdriver) {
|
|
561
561
|
console.log("This project is supported by Needle for Education – https://needle.tools");
|
|
562
562
|
}
|
|
@@ -613,7 +613,7 @@ function wQoTi(ctx: IContext) {
|
|
|
613
613
|
}
|
|
614
614
|
}, 1000);
|
|
615
615
|
|
|
616
|
-
if (
|
|
616
|
+
if (FeDU()) {
|
|
617
617
|
const removeDelay = 20_000;
|
|
618
618
|
setTimeout(() => {
|
|
619
619
|
clearInterval(interval);
|
|
@@ -622,7 +622,7 @@ function wQoTi(ctx: IContext) {
|
|
|
622
622
|
const intervalInMinutes = 5;
|
|
623
623
|
setTimeout(() => {
|
|
624
624
|
if (ctx.domElement.parentNode)
|
|
625
|
-
|
|
625
|
+
_UnZAOAPG(ctx);
|
|
626
626
|
}, 1000 * 60 * intervalInMinutes)
|
|
627
627
|
}, removeDelay);
|
|
628
628
|
}
|
|
@@ -633,7 +633,7 @@ function wQoTi(ctx: IContext) {
|
|
|
633
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=";
|
|
634
634
|
|
|
635
635
|
let lastLogTime = 0;
|
|
636
|
-
async function
|
|
636
|
+
async function _$vPpCic(_logo?: string) {
|
|
637
637
|
const now = Date.now();
|
|
638
638
|
if (now - lastLogTime < 2000) return;
|
|
639
639
|
lastLogTime = now;
|
|
@@ -666,7 +666,7 @@ async function __IemeBi(_logo?: string) {
|
|
|
666
666
|
}
|
|
667
667
|
|
|
668
668
|
|
|
669
|
-
async function
|
|
669
|
+
async function bdYvL(context: IContext) {
|
|
670
670
|
// We can't send beacons from cross-origin isolated pages
|
|
671
671
|
if (window.crossOriginIsolated) return;
|
|
672
672
|
|
|
@@ -681,7 +681,7 @@ async function _fqbFnUXZ(context: IContext) {
|
|
|
681
681
|
|
|
682
682
|
// current url without query parameters
|
|
683
683
|
const currentUrl = window.location.href.split("?")[0];
|
|
684
|
-
const license =
|
|
684
|
+
const license = _LquBhwVh;
|
|
685
685
|
|
|
686
686
|
const beaconData = {
|
|
687
687
|
license,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FileLoader } from "three";
|
|
2
2
|
|
|
3
3
|
import { showBalloonWarning } from "./debug/index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { $iujBhf } 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 (
|
|
48
|
+
if ($iujBhf()) {
|
|
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 (
|
|
103
|
+
else if (!$iujBhf() && 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 {
|
|
7
|
+
import { $iujBhf } 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 =
|
|
138
|
+
const canUseCustomLogo = $iujBhf();
|
|
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)
|
|
@@ -62,9 +62,10 @@ export class PostProcessing {
|
|
|
62
62
|
|
|
63
63
|
/** When enabled, the device pixel ratio will be gradually reduced when FPS is low
|
|
64
64
|
* and restored when performance recovers.
|
|
65
|
-
* @
|
|
65
|
+
* @experimental
|
|
66
|
+
* @default false
|
|
66
67
|
*/
|
|
67
|
-
adaptiveResolution: boolean =
|
|
68
|
+
adaptiveResolution: boolean = false;
|
|
68
69
|
|
|
69
70
|
constructor(context: Context) {
|
|
70
71
|
this._context = context;
|
|
@@ -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 {
|
|
5
|
+
import { $iujBhf } 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 &&
|
|
324
|
+
if (!this._showNeedleLogo && $iujBhf()) {
|
|
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 {
|
|
3
|
+
import { $iujBhf, _$GTZ, 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";
|
|
@@ -208,14 +208,14 @@ export class NeedleMenu {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
/**
|
|
211
|
-
* Call to show or hide the menu.
|
|
212
|
-
* NOTE: Hiding the menu
|
|
211
|
+
* Call to show or hide the menu.
|
|
212
|
+
* NOTE: Hiding the menu requires a commercial license. Hiding the menu will not work in production without a license.
|
|
213
213
|
*/
|
|
214
214
|
setVisible(visible: boolean) {
|
|
215
215
|
this._menu.setVisible(visible);
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
/** When set to false, the Needle Engine logo will be hidden. Hiding the logo requires a
|
|
218
|
+
/** When set to false, the Needle Engine logo will be hidden. Hiding the logo requires a commercial license */
|
|
219
219
|
showNeedleLogo(visible: boolean) {
|
|
220
220
|
this._menu.showNeedleLogo(visible);
|
|
221
221
|
this._spatialMenu?.showNeedleLogo(visible);
|
|
@@ -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(() =>
|
|
782
|
-
if (res == true &&
|
|
781
|
+
window.requestAnimationFrame(() => _$GTZ(res => {
|
|
782
|
+
if (res == true && $iujBhf() && !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 (
|
|
833
|
+
if (!$iujBhf()) {
|
|
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) {
|
|
@@ -841,7 +841,7 @@ export class NeedleMenuElement extends HTMLElementBase {
|
|
|
841
841
|
}
|
|
842
842
|
// warn only once
|
|
843
843
|
if (change === 1) {
|
|
844
|
-
console.warn(`Needle Menu Warning: You need a
|
|
844
|
+
console.warn(`Needle Menu Warning: You need a commercial license to hide the Needle Engine menu → The menu will be visible in your deployed website without one. See https://needle.tools/pricing for details.`);
|
|
845
845
|
}
|
|
846
846
|
}
|
|
847
847
|
else {
|
|
@@ -918,8 +918,8 @@ export class NeedleMenuElement extends HTMLElementBase {
|
|
|
918
918
|
showNeedleLogo(visible: boolean) {
|
|
919
919
|
this._userRequestedLogoVisible = visible;
|
|
920
920
|
if (!visible) {
|
|
921
|
-
if (
|
|
922
|
-
console.warn("[Needle Engine] You need a
|
|
921
|
+
if (!$iujBhf() || debugNonCommercial) {
|
|
922
|
+
console.warn("[Needle Engine] You need a commercial license to hide the Needle Engine logo in production.");
|
|
923
923
|
const localNetwork = isLocalNetwork()
|
|
924
924
|
if (!localNetwork) return;
|
|
925
925
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { needleLogoOnlySVG } from "../assets/index.js"
|
|
2
2
|
import { isDevEnvironment, showBalloonWarning } from "../debug/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { $iujBhf, rXELCf, $rKLNDMS } 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";
|
|
@@ -205,7 +205,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
|
|
208
|
-
const hasLicense =
|
|
208
|
+
const hasLicense = rXELCf();
|
|
209
209
|
if (!existing) {
|
|
210
210
|
this._loadingElement.style.position = "absolute";
|
|
211
211
|
this._loadingElement.style.width = "100%";
|
|
@@ -373,7 +373,7 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
373
373
|
|
|
374
374
|
// private async handleRuntimeLicense(loadingElement: HTMLElement) {
|
|
375
375
|
// // First check if we have a commercial license
|
|
376
|
-
// let commercialLicense =
|
|
376
|
+
// let commercialLicense = $iujBhf();
|
|
377
377
|
// // if it's the case then we don't need to perform a runtime check
|
|
378
378
|
// if (commercialLicense) return;
|
|
379
379
|
|
|
@@ -393,10 +393,10 @@ export class EngineLoadingView implements ILoadingViewHandler {
|
|
|
393
393
|
// loadingElement.appendChild(nonCommercialContainer);
|
|
394
394
|
|
|
395
395
|
// // Use the runtime license check
|
|
396
|
-
// if (!isDevEnvironment() &&
|
|
396
|
+
// if (!isDevEnvironment() && $rKLNDMS) {
|
|
397
397
|
// if (debugLicense) console.log("Waiting for runtime license check");
|
|
398
|
-
// await
|
|
399
|
-
// commercialLicense =
|
|
398
|
+
// await $rKLNDMS;
|
|
399
|
+
// commercialLicense = $iujBhf();
|
|
400
400
|
// }
|
|
401
401
|
// if (commercialLicense) return;
|
|
402
402
|
// nonCommercialContainer.style.transition = "opacity .5s ease-in-out";
|
|
@@ -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 {
|
|
6
|
+
import { $iujBhf } 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";
|
|
@@ -579,7 +579,7 @@ export class NeedleEngineWebComponent extends HTMLElementBase implements INeedle
|
|
|
579
579
|
|
|
580
580
|
|
|
581
581
|
// Loading start events
|
|
582
|
-
const allowOverridingDefaultLoading =
|
|
582
|
+
const allowOverridingDefaultLoading = $iujBhf();
|
|
583
583
|
// default loading can be overriden by calling preventDefault in the onload start event
|
|
584
584
|
this.ensureLoadStartIsRegistered();
|
|
585
585
|
let useDefaultLoading = this.dispatchEvent(new CustomEvent("loadstart", {
|
|
@@ -291,6 +291,49 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
291
291
|
static get currentSessionRequest(): XRSessionMode | null { return this._currentSessionRequestMode; }
|
|
292
292
|
private static _currentSessionRequestMode: XRSessionMode | null = null;
|
|
293
293
|
|
|
294
|
+
/** Base URL for branded Needle AppClip experiences */
|
|
295
|
+
private static readonly appClipBaseUrl = "https://appclip.needle.tools/x/";
|
|
296
|
+
private static _appClipUrl: string | null = null;
|
|
297
|
+
/**
|
|
298
|
+
* Optionally provide a custom Needle AppClip experience to open on iOS instead of the default Needle AppClip.
|
|
299
|
+
* This enables custom App Clip card branding (your own title and image) when launching AR on iPhone and iPad.
|
|
300
|
+
*
|
|
301
|
+
* You can provide either:
|
|
302
|
+
* - the full URL, e.g. `https://appclip.needle.tools/x/your-experience`
|
|
303
|
+
* - or just the experience id, e.g. `your-experience` (expanded to `https://appclip.needle.tools/x/your-experience`)
|
|
304
|
+
*
|
|
305
|
+
* **IMPORTANT**: the resulting URL must exactly match an App Clip experience URL you have registered (with custom card metadata).
|
|
306
|
+
* For this reason the URL is opened as-is, without appending any query parameters.
|
|
307
|
+
* @link https://appclip.needle.tools
|
|
308
|
+
*/
|
|
309
|
+
static get appClipUrl(): string | null { return this._appClipUrl; }
|
|
310
|
+
static set appClipUrl(value: string | null) {
|
|
311
|
+
if (!value) {
|
|
312
|
+
this._appClipUrl = null;
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const trimmed = value.trim();
|
|
316
|
+
// accept a full URL as-is, otherwise treat the value as an experience id and expand it using the base url
|
|
317
|
+
this._appClipUrl = /^https?:\/\//i.test(trimmed)
|
|
318
|
+
? trimmed
|
|
319
|
+
: this.appClipBaseUrl + trimmed.replace(/^\/+/, "");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @internal
|
|
324
|
+
* Returns the AppClip launch URL to open (or prefetch) on iOS for the current page.
|
|
325
|
+
* When a custom {@link appClipUrl} is set this is the branded experience URL (opened as-is so it matches the registered URL);
|
|
326
|
+
* otherwise it is the default Needle AppClip launch URL with the current page forwarded via the `url` parameter.
|
|
327
|
+
*/
|
|
328
|
+
static getAppClipLaunchUrl(): URL {
|
|
329
|
+
if (this._appClipUrl) return new URL(this._appClipUrl);
|
|
330
|
+
// Forward to the default Needle AppClip experience (using the apple.com url the appclip overlay shows immediately)
|
|
331
|
+
// alternative: `https://appclip.needle.tools/ar?url=${location.href}`
|
|
332
|
+
const url = new URL("https://appclip.apple.com/id?p=tools.needle.launch-app.Clip");
|
|
333
|
+
url.searchParams.set("url", location.href);
|
|
334
|
+
return url;
|
|
335
|
+
}
|
|
336
|
+
|
|
294
337
|
/**
|
|
295
338
|
* @returns the active @type {NeedleXRSession} (if any active) or null
|
|
296
339
|
*/
|
|
@@ -498,10 +541,10 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
498
541
|
const topWindow = window.top || window;
|
|
499
542
|
const originalUrl = topWindow.location.href;
|
|
500
543
|
|
|
501
|
-
// Forward to the AppClip experience
|
|
502
|
-
//
|
|
503
|
-
const
|
|
504
|
-
url.
|
|
544
|
+
// Forward to the AppClip experience. By default this is the Needle AppClip; a custom branded
|
|
545
|
+
// experience can be set via NeedleXRSession.appClipUrl (which is then opened as-is so it matches the registered URL).
|
|
546
|
+
const customAppClip = NeedleXRSession.appClipUrl !== null;
|
|
547
|
+
const url = NeedleXRSession.getAppClipLaunchUrl();
|
|
505
548
|
const urlStr = url.toString();
|
|
506
549
|
|
|
507
550
|
Telemetry.sendEvent(Context.Current, "xr", {
|
|
@@ -513,12 +556,15 @@ export class NeedleXRSession implements INeedleXRSession {
|
|
|
513
556
|
try {
|
|
514
557
|
console.debug("iOS device detected - opening Needle App Clip for AR experience", { mode, init, url });
|
|
515
558
|
|
|
516
|
-
// Prewarm the appclip by opening the URL
|
|
559
|
+
// Prewarm the appclip by opening the URL (with an extra ?prewarm=1 param) to fetch the app clip
|
|
560
|
+
// metadata faster - this fixes a double-tap issue on iOS.
|
|
517
561
|
// BUT on safari triggering this with multiple URLs causes the
|
|
518
562
|
// Browser to show the dialogue AGAIN in the background
|
|
519
563
|
// SO: we don't do it here...
|
|
520
|
-
|
|
521
|
-
|
|
564
|
+
// We also skip prewarming for a custom branded experience: that URL must match the registered
|
|
565
|
+
// App Clip experience URL exactly, so we must not append any query parameters to it.
|
|
566
|
+
const key = "appclip-prewarm:" + url.origin;
|
|
567
|
+
const allowMultipleNavigations = !customAppClip && sessionStorage.getItem(key) === null;
|
|
522
568
|
if (allowMultipleNavigations) {
|
|
523
569
|
const secondUrl = new URL(url);
|
|
524
570
|
secondUrl.searchParams.set("prewarm", "1");
|
|
@@ -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 {
|
|
6
|
+
import { $iujBhf } 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 (
|
|
218
|
+
if ($iujBhf()) {
|
|
219
219
|
const htmlComponent = document.querySelector("needle-engine");
|
|
220
220
|
if (htmlComponent) {
|
|
221
221
|
const licenseLogo = htmlComponent.getAttribute("logo-src");
|