@needle-tools/engine 5.1.0-alpha.5 → 5.1.0-canary.02ccb45
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 +13 -1
- package/components.needle.json +1 -1
- package/dist/{needle-engine.bundle-OPkPmdUM.umd.cjs → needle-engine.bundle-BSJwg312.umd.cjs} +146 -145
- package/dist/{needle-engine.bundle-C-LG00ZZ.js → needle-engine.bundle-DLNnLj9B.js} +6650 -6494
- package/dist/{needle-engine.bundle-D7tzaiYE.min.js → needle-engine.bundle-I8Lv85MA.min.js} +175 -174
- package/dist/needle-engine.d.ts +95 -17
- package/dist/needle-engine.js +554 -553
- package/dist/needle-engine.min.js +1 -1
- package/dist/needle-engine.umd.cjs +1 -1
- 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 +7 -0
- 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 +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_utils_format.js +20 -14
- package/lib/engine/engine_utils_format.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/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/AudioSource.js +1 -1
- package/lib/engine-components/AudioSource.js.map +1 -1
- package/lib/engine-components/DropListener.js +1 -0
- package/lib/engine-components/DropListener.js.map +1 -1
- package/lib/engine-components/OrbitControls.d.ts +1 -0
- package/lib/engine-components/OrbitControls.js +7 -2
- package/lib/engine-components/OrbitControls.js.map +1 -1
- package/lib/engine-components/VideoPlayer.d.ts +8 -2
- package/lib/engine-components/VideoPlayer.js +42 -19
- package/lib/engine-components/VideoPlayer.js.map +1 -1
- package/lib/engine-components/Voip.d.ts +16 -7
- package/lib/engine-components/Voip.js +90 -53
- package/lib/engine-components/Voip.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/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 +2 -2
- package/plugins/common/license.js +50 -10
- package/plugins/types/userconfig.d.ts +4 -1
- package/plugins/vite/build-pipeline.js +57 -20
- package/plugins/vite/license.js +29 -12
- package/src/engine/api.ts +1 -1
- package/src/engine/engine_context.ts +11 -1
- package/src/engine/engine_init.ts +2 -2
- package/src/engine/engine_license.ts +201 -55
- package/src/engine/engine_networking_blob.ts +3 -3
- package/src/engine/engine_utils_format.ts +20 -14
- 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/AudioSource.ts +1 -1
- package/src/engine-components/DropListener.ts +1 -0
- package/src/engine-components/OrbitControls.ts +8 -2
- package/src/engine-components/VideoPlayer.ts +40 -17
- package/src/engine-components/Voip.ts +88 -53
- package/src/engine-components/api.ts +1 -0
- package/src/engine-components/export/usdz/USDZExporter.ts +4 -4
- package/src/engine-components/webxr/WebXRImageTracking.ts +77 -7
- package/src/vite-env.d.ts +0 -16
|
@@ -82,7 +82,10 @@ export type userSettings = {
|
|
|
82
82
|
*/
|
|
83
83
|
version?: string;
|
|
84
84
|
|
|
85
|
-
/** If defined the access token will be used to run compression on Needle Cloud
|
|
85
|
+
/** If defined the access token will be used to run compression on Needle Cloud.
|
|
86
|
+
*
|
|
87
|
+
* Expected to be a Needle Cloud access token (created in the Needle Cloud UI),
|
|
88
|
+
* NOT a JWT. Do not pass a licensing JWT here. */
|
|
86
89
|
accessToken?: string | undefined;
|
|
87
90
|
|
|
88
91
|
/**
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChildProcess, exec } from 'child_process';
|
|
2
2
|
import { NEEDLE_CLOUD_CLI_NAME } from '../common/cloud.js';
|
|
3
|
+
import { resolveLicense } from '../common/license.js';
|
|
3
4
|
import { getOutputDirectory, loadConfig } from './config.js';
|
|
4
5
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'fs';
|
|
5
6
|
import { relative } from 'path';
|
|
@@ -10,6 +11,8 @@ import { needleBlue, needleDim, needleLog, needleSupportsColor, setTransientLogL
|
|
|
10
11
|
const PIPELINE_SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
11
12
|
const PIPELINE_STRUCTURED_LOG_PREFIX = "__needle_pipeline_log__:";
|
|
12
13
|
|
|
14
|
+
// #region Validation
|
|
15
|
+
|
|
13
16
|
/**
|
|
14
17
|
* @param {import('../types').userSettings} config
|
|
15
18
|
* @returns {boolean}
|
|
@@ -37,8 +40,11 @@ env:
|
|
|
37
40
|
return true;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
// #endregion
|
|
44
|
+
|
|
40
45
|
// see https://linear.app/needle/issue/NE-3798
|
|
41
46
|
|
|
47
|
+
// #region State
|
|
42
48
|
|
|
43
49
|
/** @type {Promise<void>|null} */
|
|
44
50
|
let buildPipelineTask;
|
|
@@ -87,6 +93,10 @@ function increaseMaxWaitTime(debugLog) {
|
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
95
|
|
|
96
|
+
// #endregion
|
|
97
|
+
|
|
98
|
+
// #region Plugin
|
|
99
|
+
|
|
90
100
|
/** Runs the needle build pipeline as part of the vite build process.
|
|
91
101
|
* @param {"build" | "serve"} command
|
|
92
102
|
* @param {import('../types/needleConfig').needleMeta | null | undefined} config
|
|
@@ -237,9 +247,12 @@ export async function needleBuildPipeline(command, config, userSettings) {
|
|
|
237
247
|
}
|
|
238
248
|
}
|
|
239
249
|
|
|
250
|
+
// #endregion
|
|
251
|
+
|
|
252
|
+
// #region Migration
|
|
240
253
|
|
|
241
254
|
/**
|
|
242
|
-
* Previously we did always install the build pipeline and run an extra command to invoke the build pipeline.
|
|
255
|
+
* Previously we did always install the build pipeline and run an extra command to invoke the build pipeline.
|
|
243
256
|
* This is now done automatically by the needle build pipeline plugin - so we update all legacy projects to use the new method.
|
|
244
257
|
* @param {string} packageJsonPath
|
|
245
258
|
*/
|
|
@@ -258,6 +271,10 @@ async function fixPackageJson(packageJsonPath) {
|
|
|
258
271
|
writeFileSync(packageJsonPath, fixed);
|
|
259
272
|
}
|
|
260
273
|
|
|
274
|
+
// #endregion
|
|
275
|
+
|
|
276
|
+
// #region Logging
|
|
277
|
+
|
|
261
278
|
/** @param {...unknown} args */
|
|
262
279
|
function log(...args) {
|
|
263
280
|
needleLog("needle-buildpipeline", args.join(" "));
|
|
@@ -267,11 +284,15 @@ function warn(...args) {
|
|
|
267
284
|
needleLog("needle-buildpipeline", args.join(" "), "warn");
|
|
268
285
|
}
|
|
269
286
|
|
|
287
|
+
// #endregion
|
|
288
|
+
|
|
289
|
+
// #region Execution
|
|
290
|
+
|
|
270
291
|
/**
|
|
271
292
|
* @typedef {{ event?: string, phase?: string, target?: string, message?: string, level?: string }} BuildPipelinePayload
|
|
272
293
|
*/
|
|
273
294
|
/**
|
|
274
|
-
* @param {import('../types').userSettings} opts
|
|
295
|
+
* @param {import('../types').userSettings} opts
|
|
275
296
|
* @param {{verbose?:boolean}} [options]
|
|
276
297
|
* @returns {Promise<boolean>}
|
|
277
298
|
*/
|
|
@@ -283,12 +304,7 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
283
304
|
const supportsColor = needleSupportsColor();
|
|
284
305
|
const key = (/** @type {string} */ text) => supportsColor ? needleBlue(text) : text;
|
|
285
306
|
|
|
286
|
-
|
|
287
|
-
const fullInstallPath = process.cwd() + "/" + installPath;
|
|
288
|
-
const existsLocally = existsSync(fullInstallPath);
|
|
289
|
-
if (existsLocally) {
|
|
290
|
-
log("Found local installation at " + fullInstallPath);
|
|
291
|
-
}
|
|
307
|
+
// #region Wait for output
|
|
292
308
|
await delay(500);
|
|
293
309
|
const outputDirectory = getOutputDirectory() + "/assets";
|
|
294
310
|
const startWaitTime = Date.now();
|
|
@@ -332,17 +348,18 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
332
348
|
`${key("Files to process")}: ${files.length} in ${rel(outputDirectory)}, ${formatBytes(filesBytes)}`,
|
|
333
349
|
existsSync(process.cwd() + "/node_modules/.needle/build-pipeline/output") ? needleDim("Removing temporary output directory") : undefined,
|
|
334
350
|
].filter(Boolean), "log", { dimBody: false });
|
|
351
|
+
// #endregion
|
|
352
|
+
|
|
353
|
+
// #region Setup
|
|
335
354
|
|
|
336
355
|
/** @type {null | ChildProcess} */
|
|
337
356
|
let proc = null;
|
|
338
357
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
358
|
+
// Cloud token used by `${NEEDLE_CLOUD_CLI_NAME} optimize --token <token>`.
|
|
359
|
+
// This is a Needle Cloud access token (created in the Needle Cloud UI), NOT a JWT.
|
|
360
|
+
const cloudAccessToken = opts.buildPipeline?.accessToken;
|
|
343
361
|
const runInCloud = typeof cloudAccessToken === "string" && cloudAccessToken.length > 0;
|
|
344
|
-
|
|
345
|
-
// or perhaps log an error / prevent the build from running completely
|
|
362
|
+
|
|
346
363
|
if (opts.buildPipeline && !runInCloud && process.env.CI) {
|
|
347
364
|
warn(`No cloud access token found. Please set it via process.env.NEEDLE_CLOUD_TOKEN`);
|
|
348
365
|
return false;
|
|
@@ -367,6 +384,10 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
367
384
|
}
|
|
368
385
|
}
|
|
369
386
|
|
|
387
|
+
// #endregion
|
|
388
|
+
|
|
389
|
+
// #region Run
|
|
390
|
+
|
|
370
391
|
// allow running the build pipeline in the cloud. It requires and access token to be set in the vite.config.js
|
|
371
392
|
// this can be set via e.g. process.env.NEEDLE_CLOUD_TOKEN
|
|
372
393
|
const commandEnv = { ...process.env, NEEDLE_PIPELINE_STRUCTURED_LOGS: "1" };
|
|
@@ -393,11 +414,6 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
393
414
|
log(`Running compression in cloud ⛅ using access token: ${obfuscatedToken}`);
|
|
394
415
|
proc = exec(cmd, { env: commandEnv });
|
|
395
416
|
}
|
|
396
|
-
else if (existsLocally) {
|
|
397
|
-
const cmd = `needle-gltf transform "${outputDirectory}" \"${tempOutputPath}\"`;
|
|
398
|
-
log("Running command \"" + cmd + "\" at " + process.cwd() + "...");
|
|
399
|
-
proc = exec(cmd, { cwd: installPath, env: commandEnv });
|
|
400
|
-
}
|
|
401
417
|
else {
|
|
402
418
|
// First check if the user passed in a specific version to use via the vite config
|
|
403
419
|
let version = opts.buildPipeline?.version;
|
|
@@ -424,10 +440,21 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
424
440
|
if (!version) version = "stable";
|
|
425
441
|
|
|
426
442
|
const versionInfo = versionSource ? `'${version}' (${versionSource})` : `'${version}'`;
|
|
427
|
-
|
|
443
|
+
// needle-gltf 3.x requires a JWT via `--auth-token <jwt>` on every CLI invocation.
|
|
444
|
+
// The JWT comes from the needle license server — it is NOT the Needle Cloud access token.
|
|
445
|
+
const licenseResult = await resolveLicense({
|
|
446
|
+
team: opts.license?.team,
|
|
447
|
+
accessToken: opts.license?.accessToken,
|
|
448
|
+
loglevel: opts.debugLicense === true ? "verbose" : undefined,
|
|
449
|
+
});
|
|
450
|
+
const authTokenArg = licenseResult?.jwt ? ` --auth-token ${licenseResult.jwt}` : "";
|
|
451
|
+
const cmd = `npx --yes @needle-tools/gltf-build-pipeline@${version} transform "${outputDirectory}" \"${tempOutputPath}\"${authTokenArg}`;
|
|
428
452
|
log(`Running compression locally using version ${versionInfo}`);
|
|
429
453
|
proc = exec(cmd, { env: commandEnv });
|
|
430
454
|
}
|
|
455
|
+
// #endregion
|
|
456
|
+
|
|
457
|
+
// #region Output
|
|
431
458
|
let pipelineSpinnerIndex = 0;
|
|
432
459
|
let pipelineSpinnerActive = false;
|
|
433
460
|
let transformStepCount = 0;
|
|
@@ -550,6 +577,9 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
550
577
|
}
|
|
551
578
|
proc.stdout?.on('data', onLog);
|
|
552
579
|
proc.stderr?.on('data', onLog);
|
|
580
|
+
// #endregion
|
|
581
|
+
|
|
582
|
+
// #region Exit
|
|
553
583
|
return new Promise((resolve, reject) => {
|
|
554
584
|
proc.on('exit', (code) => {
|
|
555
585
|
clearPipelineProgress();
|
|
@@ -570,8 +600,13 @@ async function invokeBuildPipeline(opts, options = {}) {
|
|
|
570
600
|
resolve(success);
|
|
571
601
|
});
|
|
572
602
|
});
|
|
603
|
+
// #endregion
|
|
573
604
|
}
|
|
574
605
|
|
|
606
|
+
// #endregion
|
|
607
|
+
|
|
608
|
+
// #region Helpers
|
|
609
|
+
|
|
575
610
|
/** @param {string | null | undefined} directory */
|
|
576
611
|
function getDirectoryStats(directory) {
|
|
577
612
|
if (!directory || !existsSync(directory)) return { fileCount: 0, totalBytes: 0 };
|
|
@@ -597,3 +632,5 @@ function getDirectoryStats(directory) {
|
|
|
597
632
|
}
|
|
598
633
|
return { fileCount, totalBytes };
|
|
599
634
|
}
|
|
635
|
+
|
|
636
|
+
// #endregion
|
package/plugins/vite/license.js
CHANGED
|
@@ -8,7 +8,8 @@ import { loadConfig } from './config.js';
|
|
|
8
8
|
* @returns {import('vite').Plugin}
|
|
9
9
|
*/
|
|
10
10
|
export function needleLicense(command, config, userSettings) {
|
|
11
|
-
|
|
11
|
+
/** @type {import('../common/license.js').LicenseResult | null | undefined} */
|
|
12
|
+
let licenseResult = undefined;
|
|
12
13
|
let appliedLicense = false;
|
|
13
14
|
|
|
14
15
|
return {
|
|
@@ -24,7 +25,7 @@ export function needleLicense(command, config, userSettings) {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
licenseResult = await resolveLicense({
|
|
28
29
|
team: team,
|
|
29
30
|
accessToken: userSettings?.license?.accessToken,
|
|
30
31
|
loglevel: userSettings?.debugLicense === true ? "verbose" : undefined
|
|
@@ -32,10 +33,6 @@ export function needleLicense(command, config, userSettings) {
|
|
|
32
33
|
|
|
33
34
|
},
|
|
34
35
|
async transform(src, id) {
|
|
35
|
-
if (appliedLicense === true) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
36
|
// Vite 4 and 8 handling:
|
|
40
37
|
const isNeedleEngineFile = id.includes("engine/engine_license")
|
|
41
38
|
|| id.includes("needle-tools_engine")
|
|
@@ -45,22 +42,42 @@ export function needleLicense(command, config, userSettings) {
|
|
|
45
42
|
const isViteChunkFile = id.includes("chunk") && id.includes(".vite");
|
|
46
43
|
if (isNeedleEngineFile || isViteChunkFile) {
|
|
47
44
|
|
|
48
|
-
if (!
|
|
45
|
+
if (!licenseResult) {
|
|
49
46
|
return;
|
|
50
47
|
}
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
let modified = false;
|
|
50
|
+
|
|
51
|
+
// Replace license type
|
|
52
|
+
const index = src.indexOf("fFDtghiT");
|
|
53
53
|
if (index >= 0) {
|
|
54
54
|
const end = src.indexOf(";", index);
|
|
55
55
|
if (end >= 0) {
|
|
56
|
-
appliedLicense = true;
|
|
57
56
|
const line = src.substring(index, end);
|
|
58
|
-
const replaced = "
|
|
57
|
+
const replaced = "fFDtghiT = \"" + licenseResult.type + "\"";
|
|
59
58
|
src = src.replace(line, replaced);
|
|
60
|
-
|
|
59
|
+
modified = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Replace license JWT (same pattern)
|
|
64
|
+
if (licenseResult.jwt) {
|
|
65
|
+
const jwtIndex = src.indexOf("$NAqiWhRF");
|
|
66
|
+
if (jwtIndex >= 0) {
|
|
67
|
+
const jwtEnd = src.indexOf(";", jwtIndex);
|
|
68
|
+
if (jwtEnd >= 0) {
|
|
69
|
+
const jwtLine = src.substring(jwtIndex, jwtEnd);
|
|
70
|
+
const jwtReplaced = "$NAqiWhRF = \"" + licenseResult.jwt + "\"";
|
|
71
|
+
src = src.replace(jwtLine, jwtReplaced);
|
|
72
|
+
modified = true;
|
|
73
|
+
}
|
|
61
74
|
}
|
|
62
75
|
}
|
|
63
|
-
|
|
76
|
+
|
|
77
|
+
if (modified) {
|
|
78
|
+
appliedLicense = true;
|
|
79
|
+
return { code: src, map: null }
|
|
80
|
+
}
|
|
64
81
|
}
|
|
65
82
|
},
|
|
66
83
|
buildEnd() {
|
package/src/engine/api.ts
CHANGED
|
@@ -230,7 +230,7 @@ export * from "./engine_input.js";
|
|
|
230
230
|
export { InstancingUtil } from "./engine_instancing.js";
|
|
231
231
|
|
|
232
232
|
/** License checking utilities */
|
|
233
|
-
export {
|
|
233
|
+
export { _$HwXA, _$xxpfa, UsFaeEU } from "./engine_license.js";
|
|
234
234
|
|
|
235
235
|
|
|
236
236
|
// ============================================================================
|
|
@@ -1808,6 +1808,7 @@ export class Context implements IContext {
|
|
|
1808
1808
|
? (`${((window.performance as any).memory.usedJSHeapSize / 1024 / 1024).toFixed(2)} MB`)
|
|
1809
1809
|
: "n/a";
|
|
1810
1810
|
|
|
1811
|
+
const gl = this.renderer.getContext();
|
|
1811
1812
|
console.log(this.renderer.info.render.calls + " DrawCalls", "\nRender:",
|
|
1812
1813
|
{
|
|
1813
1814
|
shaders: this.renderer.info.programs?.length,
|
|
@@ -1817,7 +1818,16 @@ export class Context implements IContext {
|
|
|
1817
1818
|
{
|
|
1818
1819
|
usedMemory: usedJSHeapSize,
|
|
1819
1820
|
...this.renderer.info.memory
|
|
1820
|
-
},
|
|
1821
|
+
},
|
|
1822
|
+
"\nRenderer:",
|
|
1823
|
+
{
|
|
1824
|
+
dpr: this.renderer.getPixelRatio(),
|
|
1825
|
+
windowDpr: window.devicePixelRatio,
|
|
1826
|
+
antialias: gl.getContextAttributes()?.antialias,
|
|
1827
|
+
samples: gl.getParameter(gl.SAMPLES),
|
|
1828
|
+
resolution: `${this.renderer.domElement.width}x${this.renderer.domElement.height}`,
|
|
1829
|
+
},
|
|
1830
|
+
"\nTarget Framerate: " + this.targetFrameRate);
|
|
1821
1831
|
}
|
|
1822
1832
|
}
|
|
1823
1833
|
|
|
@@ -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 {
|
|
11
|
+
import { NJzpPtg } 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,5 +59,5 @@ export function initEngine() {
|
|
|
59
59
|
initPhysics();
|
|
60
60
|
initXR();
|
|
61
61
|
initSpatialConsole();
|
|
62
|
-
|
|
62
|
+
NJzpPtg();
|
|
63
63
|
}
|