@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.
- package/CHANGELOG.md +39 -0
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-DQCuBTVp.umd.cjs → needle-engine.bundle-5avtTUMM.umd.cjs} +149 -148
- package/dist/{needle-engine.bundle-AjVIot3d.min.js → needle-engine.bundle-BHcw4C8f.min.js} +187 -186
- package/dist/{needle-engine.bundle-B7cqsI4c.js → needle-engine.bundle-C0gPOq4m.js} +7522 -7092
- package/dist/needle-engine.d.ts +715 -176
- package/dist/needle-engine.js +595 -593
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- package/dist/three.js +1 -0
- package/dist/three.min.js +21 -21
- package/dist/three.umd.cjs +16 -16
- package/lib/engine/api.d.ts +3 -1
- package/lib/engine/api.js +3 -1
- package/lib/engine/api.js.map +1 -1
- package/lib/engine/codegen/register_types.js +10 -10
- package/lib/engine/codegen/register_types.js.map +1 -1
- package/lib/engine/engine_camera.fit.js +16 -4
- package/lib/engine/engine_camera.fit.js.map +1 -1
- package/lib/engine/engine_context.d.ts +20 -7
- package/lib/engine/engine_context.js +36 -14
- package/lib/engine/engine_context.js.map +1 -1
- package/lib/engine/engine_context_eventbus.d.ts +47 -0
- package/lib/engine/engine_context_eventbus.js +47 -0
- package/lib/engine/engine_context_eventbus.js.map +1 -0
- package/lib/engine/engine_init.js +2 -2
- package/lib/engine/engine_init.js.map +1 -1
- package/lib/engine/engine_input.d.ts +23 -4
- package/lib/engine/engine_input.js +2 -1
- package/lib/engine/engine_input.js.map +1 -1
- package/lib/engine/engine_license.d.ts +7 -7
- package/lib/engine/engine_license.js +185 -57
- 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_physics_rapier.d.ts +10 -0
- package/lib/engine/engine_physics_rapier.js +6 -0
- package/lib/engine/engine_physics_rapier.js.map +1 -1
- package/lib/engine/engine_types.d.ts +10 -0
- package/lib/engine/engine_utils_qrcode.js +2 -2
- package/lib/engine/engine_utils_qrcode.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
- package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
- package/lib/engine/webcomponents/needle menu/needle-menu.js +5 -5
- 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/TempXRContext.js +2 -2
- package/lib/engine/xr/TempXRContext.js.map +1 -1
- package/lib/engine-components/AnimationBuilder.d.ts +158 -0
- package/lib/engine-components/AnimationBuilder.js +305 -0
- package/lib/engine-components/AnimationBuilder.js.map +1 -0
- package/lib/engine-components/Animator.js +6 -1
- package/lib/engine-components/Animator.js.map +1 -1
- package/lib/engine-components/AnimatorController.builder.d.ts +101 -23
- package/lib/engine-components/AnimatorController.builder.js +88 -20
- package/lib/engine-components/AnimatorController.builder.js.map +1 -1
- package/lib/engine-components/AnimatorController.js +2 -0
- package/lib/engine-components/AnimatorController.js.map +1 -1
- package/lib/engine-components/ContactShadows.d.ts +1 -0
- package/lib/engine-components/ContactShadows.js +14 -1
- package/lib/engine-components/ContactShadows.js.map +1 -1
- package/lib/engine-components/DropListener.js +3 -0
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +0 -2
- package/lib/engine-components/OrbitControls.js +14 -1
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/SceneSwitcher.js +3 -0
- package/lib/engine-components/SceneSwitcher.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/codegen/components.d.ts +6 -6
- package/lib/engine-components/codegen/components.js +6 -6
- package/lib/engine-components/codegen/components.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/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
- package/lib/engine-components/timeline/PlayableDirector.d.ts +7 -7
- package/lib/engine-components/timeline/PlayableDirector.js +6 -6
- package/lib/engine-components/timeline/PlayableDirector.js.map +1 -1
- package/lib/engine-components/timeline/TimelineBuilder.d.ts +175 -9
- package/lib/engine-components/timeline/TimelineBuilder.js +108 -2
- package/lib/engine-components/timeline/TimelineBuilder.js.map +1 -1
- package/lib/engine-components/timeline/TimelineTracks.d.ts +15 -7
- package/lib/engine-components/timeline/TimelineTracks.js +22 -14
- package/lib/engine-components/timeline/TimelineTracks.js.map +1 -1
- package/lib/engine-components/web/CursorFollow.d.ts +0 -1
- package/lib/engine-components/web/CursorFollow.js +0 -1
- package/lib/engine-components/web/CursorFollow.js.map +1 -1
- package/lib/engine-components/webxr/WebXRImageTracking.d.ts +62 -1
- package/lib/engine-components/webxr/WebXRImageTracking.js +55 -2
- package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
- package/package.json +1 -1
- package/plugins/common/cloud.js +6 -1
- package/plugins/common/license.js +26 -8
- package/plugins/vite/license.js +42 -7
- package/src/engine/api.ts +4 -1
- package/src/engine/codegen/register_types.ts +10 -10
- package/src/engine/engine_camera.fit.ts +15 -4
- package/src/engine/engine_context.ts +41 -16
- package/src/engine/engine_context_eventbus.ts +73 -0
- package/src/engine/engine_init.ts +2 -2
- package/src/engine/engine_input.ts +27 -6
- package/src/engine/engine_license.ts +201 -55
- package/src/engine/engine_networking_blob.ts +3 -3
- package/src/engine/engine_physics_rapier.ts +20 -6
- package/src/engine/engine_types.ts +22 -12
- package/src/engine/engine_utils_qrcode.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -2
- package/src/engine/webcomponents/needle menu/needle-menu.ts +5 -5
- package/src/engine/webcomponents/needle-engine.loading.ts +6 -6
- package/src/engine/webcomponents/needle-engine.ts +2 -2
- package/src/engine/xr/TempXRContext.ts +2 -2
- package/src/engine-components/AnimationBuilder.ts +472 -0
- package/src/engine-components/Animator.ts +6 -1
- package/src/engine-components/AnimatorController.builder.ts +163 -37
- package/src/engine-components/AnimatorController.ts +1 -0
- package/src/engine-components/ContactShadows.ts +15 -1
- package/src/engine-components/DropListener.ts +3 -0
- package/src/engine-components/OrbitControls.ts +16 -5
- package/src/engine-components/SceneSwitcher.ts +3 -0
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/codegen/components.ts +6 -6
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
- package/src/engine-components/timeline/PlayableDirector.ts +20 -20
- package/src/engine-components/timeline/TimelineBuilder.ts +277 -17
- package/src/engine-components/timeline/TimelineTracks.ts +24 -16
- package/src/engine-components/web/CursorFollow.ts +0 -1
- package/src/engine-components/webxr/WebXRImageTracking.ts +77 -7
- 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("
|
|
10
|
+
const debug = getParam("__debuglic__");
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const qKUrR: ((result: boolean) => void)[] = [];
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
22
|
-
switch (
|
|
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
|
|
32
|
-
switch (
|
|
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
|
|
41
|
-
switch (
|
|
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
|
|
50
|
-
return
|
|
63
|
+
export function LynjGsV() {
|
|
64
|
+
return _cxKhKwDL() || __otwqOR() || __mPmwPS();
|
|
51
65
|
}
|
|
52
66
|
|
|
53
67
|
|
|
54
68
|
/** @internal */
|
|
55
|
-
export function
|
|
56
|
-
if (
|
|
69
|
+
export function $yRlAEF(cb: (result: boolean) => void) {
|
|
70
|
+
if (_cxKhKwDL() || __otwqOR() || __mPmwPS())
|
|
57
71
|
return cb(true);
|
|
58
|
-
|
|
72
|
+
qKUrR.push(cb);
|
|
59
73
|
}
|
|
60
74
|
|
|
61
|
-
function
|
|
62
|
-
for (const cb of
|
|
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 (
|
|
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
|
|
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
|
-
|
|
249
|
-
|
|
250
|
-
setTimeout(() =>
|
|
390
|
+
$vyRL(evt.context);
|
|
391
|
+
uZY(evt.context);
|
|
392
|
+
setTimeout(() => cEROvL(evt.context), 2000);
|
|
251
393
|
});
|
|
252
394
|
}
|
|
253
395
|
|
|
254
|
-
export let
|
|
396
|
+
export let _$oYJ: Promise<void> | undefined = undefined;
|
|
255
397
|
let applicationIsForbidden = false;
|
|
256
398
|
let applicationForbiddenText = "";
|
|
257
|
-
async function
|
|
399
|
+
async function __lVbhf() {
|
|
258
400
|
// Only perform the runtime license check once
|
|
259
|
-
if (
|
|
260
|
-
|
|
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
|
-
|
|
273
|
-
|
|
418
|
+
EzdGPQg = "pro";
|
|
419
|
+
cLH(true);
|
|
274
420
|
}
|
|
275
421
|
else if (res?.status === 403) {
|
|
276
|
-
|
|
422
|
+
cLH(false);
|
|
277
423
|
applicationIsForbidden = true;
|
|
278
424
|
applicationForbiddenText = await res.text();
|
|
279
425
|
}
|
|
280
426
|
else {
|
|
281
|
-
|
|
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
|
-
|
|
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 \"" +
|
|
436
|
+
else if (debug) console.log("Runtime license check is skipped because license is already applied as \"" + EzdGPQg + "\"");
|
|
291
437
|
}
|
|
292
|
-
|
|
438
|
+
_$oYJ = __lVbhf();
|
|
293
439
|
|
|
294
|
-
async function
|
|
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
|
|
505
|
+
async function $vyRL(ctx: IContext) {
|
|
360
506
|
try {
|
|
361
|
-
if (!
|
|
362
|
-
return
|
|
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
|
|
513
|
+
return LGWV(ctx)
|
|
368
514
|
}
|
|
369
|
-
if (debug)
|
|
515
|
+
if (debug) LGWV(ctx)
|
|
370
516
|
}
|
|
371
517
|
|
|
372
518
|
|
|
373
519
|
|
|
374
|
-
async function
|
|
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
|
|
526
|
+
await _$oYJ?.catch(() => { });
|
|
381
527
|
|
|
382
528
|
|
|
383
|
-
if (
|
|
384
|
-
if (
|
|
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
|
-
|
|
534
|
+
_$XDPaPw(ctx);
|
|
389
535
|
}
|
|
390
536
|
else {
|
|
391
537
|
ctx.domElement.addEventListener("ready", () => {
|
|
392
|
-
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 {
|
|
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 (
|
|
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 (!
|
|
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 {
|
|
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 =
|
|
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 {
|
|
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 &&
|
|
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 {
|
|
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(() =>
|
|
782
|
-
if (res == true &&
|
|
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 (!
|
|
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 (!
|
|
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;
|