@needle-tools/engine 4.15.0-next.f391a30 → 4.15.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.
Files changed (150) hide show
  1. package/components.needle.json +1 -1
  2. package/dist/{gltf-progressive-CTlvpS3A.js → gltf-progressive-Bm_6aEi4.js} +1 -1
  3. package/dist/{gltf-progressive-CMwJPwEt.umd.cjs → gltf-progressive-BttGBXw6.umd.cjs} +1 -1
  4. package/dist/{gltf-progressive-DYL3SLVb.min.js → gltf-progressive-T5WKTux5.min.js} +1 -1
  5. package/dist/materialx-CJyQZtjt.min.js +90 -0
  6. package/dist/materialx-DMs1E08Z.js +4636 -0
  7. package/dist/materialx-DaKKOoVk.umd.cjs +90 -0
  8. package/dist/{needle-engine.bundle-DsTdfmeb.min.js → needle-engine.bundle-CBq_OMnI.min.js} +122 -124
  9. package/dist/{needle-engine.bundle-DB4kLWO_.js → needle-engine.bundle-DGyiwNWR.js} +3226 -3232
  10. package/dist/{needle-engine.bundle-C1BFRZDF.umd.cjs → needle-engine.bundle-JN3eiiYc.umd.cjs} +113 -115
  11. package/dist/needle-engine.d.ts +52 -33
  12. package/dist/needle-engine.js +288 -287
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/{postprocessing-BN-f4viE.min.js → postprocessing-06AXuvdv.min.js} +1 -1
  16. package/dist/{postprocessing-De9ZpJrk.js → postprocessing-CI2x8Cln.js} +1 -1
  17. package/dist/{postprocessing-DYmYOVm4.umd.cjs → postprocessing-CPDcA21P.umd.cjs} +1 -1
  18. package/dist/{three-examples-BHqRVpO_.umd.cjs → three-examples-BMmNgNCN.umd.cjs} +12 -12
  19. package/dist/{three-examples-C0ZCCA_K.js → three-examples-CMYCd5nH.js} +192 -182
  20. package/dist/{three-examples-DmTY8tGr.min.js → three-examples-CQl1fFZp.min.js} +14 -14
  21. package/lib/engine/api.d.ts +2 -0
  22. package/lib/engine/api.js +2 -0
  23. package/lib/engine/api.js.map +1 -1
  24. package/lib/engine/debug/debug.js +1 -1
  25. package/lib/engine/debug/debug.js.map +1 -1
  26. package/lib/engine/debug/debug_spatial_console.js +1 -1
  27. package/lib/engine/debug/debug_spatial_console.js.map +1 -1
  28. package/lib/engine/engine_accessibility.d.ts +1 -1
  29. package/lib/engine/engine_accessibility.js +1 -1
  30. package/lib/engine/engine_accessibility.js.map +1 -1
  31. package/lib/engine/engine_context.d.ts +1 -1
  32. package/lib/engine/engine_context.js +2 -2
  33. package/lib/engine/engine_context.js.map +1 -1
  34. package/lib/engine/engine_create_objects.js +1 -1
  35. package/lib/engine/engine_create_objects.js.map +1 -1
  36. package/lib/engine/engine_gizmos.js +1 -1
  37. package/lib/engine/engine_gizmos.js.map +1 -1
  38. package/lib/engine/engine_license.js +2 -7
  39. package/lib/engine/engine_license.js.map +1 -1
  40. package/lib/engine/engine_test_utils.d.ts +39 -0
  41. package/lib/engine/engine_test_utils.js +84 -0
  42. package/lib/engine/engine_test_utils.js.map +1 -0
  43. package/lib/engine/engine_utils.js +2 -2
  44. package/lib/engine/engine_utils.js.map +1 -1
  45. package/lib/engine/export/gltf/index.js +1 -1
  46. package/lib/engine/export/gltf/index.js.map +1 -1
  47. package/lib/engine/webcomponents/logo-element.d.ts +3 -6
  48. package/lib/engine/webcomponents/logo-element.js +0 -18
  49. package/lib/engine/webcomponents/logo-element.js.map +1 -1
  50. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js +2 -2
  51. package/lib/engine/webcomponents/needle menu/needle-menu-spatial.js.map +1 -1
  52. package/lib/engine/webcomponents/needle menu/needle-menu.d.ts +7 -10
  53. package/lib/engine/webcomponents/needle menu/needle-menu.js +4 -14
  54. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  55. package/lib/engine/webcomponents/needle-engine.ar-overlay.js +1 -10
  56. package/lib/engine/webcomponents/needle-engine.ar-overlay.js.map +1 -1
  57. package/lib/engine/webcomponents/needle-engine.d.ts +0 -3
  58. package/lib/engine/webcomponents/needle-engine.js +0 -10
  59. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  60. package/lib/engine-components/Component.js +1 -0
  61. package/lib/engine-components/Component.js.map +1 -1
  62. package/lib/engine-components/ReflectionProbe.d.ts +2 -24
  63. package/lib/engine-components/ReflectionProbe.js +2 -28
  64. package/lib/engine-components/ReflectionProbe.js.map +1 -1
  65. package/lib/engine-components/Skybox.js +2 -4
  66. package/lib/engine-components/Skybox.js.map +1 -1
  67. package/lib/engine-components/export/gltf/GltfExport.js +1 -1
  68. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  69. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
  70. package/lib/engine-components/export/usdz/USDZExporter.js +1 -1
  71. package/lib/engine-components/export/usdz/USDZExporter.js.map +1 -1
  72. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js +2 -2
  73. package/lib/engine-components/export/usdz/extensions/behavior/PhysicsExtension.js.map +1 -1
  74. package/lib/engine-components/postprocessing/Effects/Tonemapping.utils.d.ts +1 -1
  75. package/lib/include/three/EXT_mesh_gpu_instancing_exporter.js.map +1 -0
  76. package/package.json +14 -18
  77. package/plugins/common/buildinfo.js +10 -46
  78. package/plugins/common/files.js +1 -2
  79. package/plugins/common/license.js +69 -144
  80. package/plugins/common/logger.js +11 -172
  81. package/plugins/common/worker.js +4 -5
  82. package/plugins/types/userconfig.d.ts +2 -40
  83. package/plugins/vite/alias.js +5 -6
  84. package/plugins/vite/asap.js +5 -6
  85. package/plugins/vite/build-pipeline.js +41 -224
  86. package/plugins/vite/buildinfo.js +6 -66
  87. package/plugins/vite/copyfiles.js +12 -41
  88. package/plugins/vite/custom-element-data.js +16 -26
  89. package/plugins/vite/defines.js +5 -8
  90. package/plugins/vite/dependencies.js +10 -16
  91. package/plugins/vite/dependency-watcher.js +7 -35
  92. package/plugins/vite/drop-client.js +5 -7
  93. package/plugins/vite/drop.js +14 -16
  94. package/plugins/vite/editor-connection.js +16 -18
  95. package/plugins/vite/imports-logger.js +2 -12
  96. package/plugins/vite/index.js +3 -8
  97. package/plugins/vite/local-files.js +441 -2
  98. package/plugins/vite/logger.client.js +35 -45
  99. package/plugins/vite/logger.js +3 -6
  100. package/plugins/vite/meta.js +4 -18
  101. package/plugins/vite/needle-app.js +3 -4
  102. package/plugins/vite/peer.js +1 -2
  103. package/plugins/vite/pwa.js +17 -33
  104. package/plugins/vite/reload.js +2 -24
  105. package/src/engine/api.ts +3 -0
  106. package/src/engine/debug/debug.ts +1 -1
  107. package/src/engine/debug/debug_spatial_console.ts +1 -5
  108. package/src/engine/engine_accessibility.ts +1 -2
  109. package/src/engine/engine_context.ts +2 -2
  110. package/src/engine/engine_create_objects.ts +1 -1
  111. package/src/engine/engine_gizmos.ts +5 -9
  112. package/src/engine/engine_license.ts +2 -7
  113. package/src/engine/engine_test_utils.ts +109 -0
  114. package/src/engine/engine_utils.ts +2 -2
  115. package/src/engine/export/gltf/index.ts +1 -1
  116. package/src/engine/webcomponents/logo-element.ts +3 -20
  117. package/src/engine/webcomponents/needle menu/needle-menu-spatial.ts +2 -6
  118. package/src/engine/webcomponents/needle menu/needle-menu.ts +11 -23
  119. package/src/engine/webcomponents/needle-engine.ar-overlay.ts +2 -13
  120. package/src/engine/webcomponents/needle-engine.ts +1 -13
  121. package/src/engine-components/Component.ts +2 -1
  122. package/src/engine-components/ReflectionProbe.ts +9 -33
  123. package/src/engine-components/Skybox.ts +2 -4
  124. package/src/engine-components/export/gltf/GltfExport.ts +1 -1
  125. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
  126. package/src/engine-components/export/usdz/USDZExporter.ts +1 -1
  127. package/src/engine-components/export/usdz/extensions/behavior/PhysicsExtension.ts +2 -2
  128. package/src/include/draco/draco_decoder.js +34 -0
  129. package/src/include/draco/draco_decoder.wasm +0 -0
  130. package/src/include/draco/draco_wasm_wrapper.js +117 -0
  131. package/src/include/ktx2/basis_transcoder.js +19 -0
  132. package/src/include/ktx2/basis_transcoder.wasm +0 -0
  133. package/src/include/needle/arial-msdf.json +1472 -0
  134. package/src/include/needle/arial.png +0 -0
  135. package/src/include/needle/poweredbyneedle.webp +0 -0
  136. package/dist/materialx-4jJLLe9Q.js +0 -4174
  137. package/dist/materialx-Bt9FHwco.min.js +0 -158
  138. package/dist/materialx-NDD0y4JY.umd.cjs +0 -158
  139. package/lib/engine/export/gltf/EXT_mesh_gpu_instancing_exporter.js.map +0 -1
  140. package/plugins/common/needle-engine-skill.md +0 -175
  141. package/plugins/vite/ai.js +0 -71
  142. package/plugins/vite/local-files-analysis.js +0 -789
  143. package/plugins/vite/local-files-core.js +0 -992
  144. package/plugins/vite/local-files-internals.js +0 -28
  145. package/plugins/vite/local-files-types.d.ts +0 -111
  146. package/plugins/vite/local-files-utils.js +0 -359
  147. package/plugins/vite/logging.js +0 -129
  148. /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.d.ts +0 -0
  149. /package/lib/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.js +0 -0
  150. /package/src/{engine/export/gltf → include/three}/EXT_mesh_gpu_instancing_exporter.js +0 -0
@@ -1,4 +1,3 @@
1
- // @ts-check
2
1
  import { existsSync, readFileSync } from 'fs';
3
2
  import path from 'path';
4
3
  import { fileURLToPath } from 'url';
@@ -10,8 +9,6 @@ const __dirname = path.dirname(__filename);
10
9
 
11
10
  /**
12
11
  * write logs to local file
13
- * @param {string} command
14
- * @param {unknown} config
15
12
  * @param {import('../types/userconfig.js').userSettings} userSettings
16
13
  * @returns {import('vite').Plugin | null}
17
14
  */
@@ -21,7 +18,7 @@ export const needleLogger = (command, config, userSettings) => {
21
18
  return null;
22
19
  }
23
20
 
24
- patchConsoleLogs({ command });
21
+ patchConsoleLogs();
25
22
  captureLogMessage("server", "info", "Vite started with command \"" + command + "\" in " + __dirname, null);
26
23
 
27
24
  return {
@@ -54,7 +51,7 @@ export const needleLogger = (command, config, userSettings) => {
54
51
  }
55
52
  }
56
53
  },
57
- }
54
+ },
58
55
  }
59
56
  }
60
57
 
@@ -84,7 +81,7 @@ function logRequests(server, log_http_requests = false) {
84
81
  });
85
82
  });
86
83
  // Client log messages via websocket
87
- server.ws.on('needle:client-log', async (/** @type {{level: string, message: unknown}} */ data, /** @type {{socket: import('net').Socket}} */ client) => {
84
+ server.ws.on('needle:client-log', async (data, client) => {
88
85
  if (!data || !data.level || !data.message) {
89
86
  console.warn("Received empty log data, ignoring");
90
87
  return;
@@ -3,7 +3,6 @@ import fs from 'fs';
3
3
  import { tryGetNeedleEngineVersion } from '../common/version.js';
4
4
  import { loadConfig } from './config.js';
5
5
  import { getPosterPath } from './poster.js';
6
- import { needleGreenBold, needleLog } from './logging.js';
7
6
 
8
7
  /**
9
8
  * @param {string} command
@@ -26,7 +25,7 @@ export const needleMeta = (command, config, userSettings) => {
26
25
  name: 'needle:meta',
27
26
  transformIndexHtml: {
28
27
  order: 'pre',
29
- handler(/** @type {string} */ html, /** @type {unknown} */ _ctx) {
28
+ handler(html, _ctx) {
30
29
 
31
30
  if (userSettings.allowMetaPlugin === false) return [];
32
31
 
@@ -75,7 +74,7 @@ export const needleMeta = (command, config, userSettings) => {
75
74
  tags.push({ tag: 'meta', attrs: { name: 'og:image:height', content: 1080 } });
76
75
  }
77
76
  else if (isBuild) {
78
- needleLog("needle-meta", `meta.image is set but absolutePath is ${config.absolutePath} in userSettings. Skipping meta.image.`, "warn", { dimBody: false });
77
+ console.warn(`Needle: meta.image is set but absolutePath is ${config.absolutePath} in userSettings. Skipping meta.image.`);
79
78
  }
80
79
  }
81
80
 
@@ -115,10 +114,10 @@ export const needleMeta = (command, config, userSettings) => {
115
114
  const needleEngineVersion = tryGetNeedleEngineVersion();
116
115
  if (needleEngineVersion) {
117
116
  if (command === "build")
118
- needleLog("needle-meta", needleGreenBold(`✨ Needle Engine version: ${needleEngineVersion} 🌵`), "log", { dimBody: false });
117
+ console.log("Needle Engine version: " + needleEngineVersion);
119
118
  tags.push({ tag: 'meta', attrs: { name: 'needle-engine', content: needleEngineVersion } });
120
119
  }
121
- else needleLog("needle-meta", "Could not find needle engine package.json", "warn", { dimBody: false })
120
+ else console.log("WARN: could not find needle engine package.json")
122
121
 
123
122
  tags.push({ tag: 'meta', attrs: { name: 'needle:buildtime', content: new Date().toISOString() } });
124
123
 
@@ -129,11 +128,6 @@ export const needleMeta = (command, config, userSettings) => {
129
128
  }
130
129
 
131
130
 
132
- /**
133
- * @param {string} html
134
- * @param {string} url
135
- * @returns {string}
136
- */
137
131
  function updateUrlMetaTag(html, url) {
138
132
  const result = `<meta name="url" content="${url}">`;
139
133
  html = html.replace(`<meta name="url" content="https://needle.tools">`, result);
@@ -141,21 +135,14 @@ function updateUrlMetaTag(html, url) {
141
135
  return html;
142
136
  }
143
137
 
144
- /** @param {string} str @returns {string} */
145
138
  function appendVersion(str) {
146
139
  return str + "?v=" + Date.now();
147
140
  }
148
141
 
149
- /** @param {string} url @returns {string} */
150
142
  function removeDuplicateSlashesInUrl(url) {
151
143
  return url.replace(/([^:]\/)\/+/g, "$1");
152
144
  }
153
145
 
154
- /**
155
- * @param {string} html
156
- * @param {string} name
157
- * @returns {string}
158
- */
159
146
  function removeMetaTag(html, name) {
160
147
  // TODO: maybe we could also just replace the content
161
148
  const regex = new RegExp(`<meta (name|property)="${name}".+?\/?>`, 'gs');
@@ -167,7 +154,6 @@ function removeMetaTag(html, name) {
167
154
  return newHtml;
168
155
  }
169
156
 
170
- /** @param {string} html @returns {string} */
171
157
  function insertNeedleCredits(html) {
172
158
  const needleCredits = `<!-- 🌵 Made with Needle — https://needle.tools -->`;
173
159
  html = html.replace(
@@ -1,6 +1,5 @@
1
1
  import { writeFile } from 'fs';
2
2
  import { tryParseNeedleEngineSrcAttributeFromHtml } from '../common/needle-engine.js';
3
- import { needleLog } from './logging.js';
4
3
 
5
4
 
6
5
 
@@ -55,15 +54,15 @@ export const needleApp = (command, config, userSettings) => {
55
54
  const webComponent = generateNeedleEmbedWebComponent(path, main_asset);
56
55
  await writeFile(`${outputDir}/needle-app.js`, webComponent, (err) => {
57
56
  if (err) {
58
- needleLog("needle-app", "Could not create needle-app.js: " + err.message, "error", { dimBody: false });
57
+ console.error("[needle-app] could not create needle-app.js", err);
59
58
  }
60
59
  else {
61
- needleLog("needle-app", "Created needle-app.js", "log", { dimBody: false });
60
+ console.log("[needle-app] created needle-app.js");
62
61
  }
63
62
  });
64
63
  }
65
64
  catch (e) {
66
- needleLog("needle-app", "Could not create needle-app.js: " + e.message, "warn", { dimBody: false });
65
+ console.warn("WARN: could not create needle-app.js\n", e);
67
66
  }
68
67
  }
69
68
  }
@@ -1,5 +1,4 @@
1
1
  const peerjsString = `/* needle: fix for peerjs */ window.global = window; var parcelRequire;`
2
- import { needleLog } from './logging.js';
3
2
 
4
3
  /**
5
4
  * @param {import('../types').userSettings} userSettings
@@ -81,7 +80,7 @@ function patchWebRTCAdapterForGemini(code, id) {
81
80
  if(!didTransform) return undefined;
82
81
 
83
82
  if(!didLog) {
84
- needleLog("needle:peerjs", "Fixed WebRTC assignment", "log", { dimBody: false });
83
+ console.log("[needle:peerjs] Fixed WebRTC assignment");
85
84
  didLog = true;
86
85
  }
87
86
 
@@ -7,7 +7,6 @@ import { getPosterPath } from './poster.js';
7
7
  const pwaErrorWithInstructions = "It seems that you're trying to build a PWA using 'vite-plugin-pwa'!\nNeedle can manage PWA settings for you – just pass the same 'pwaOptions' to the needlePlugins and VitePWA plugins:\n\n1. Install the vite PWA plugin: npm install vite-plugin-pwa --save-dev\n\n2. Then update your vite.config.js:\n\n import { VitePWA } from 'vite-plugin-pwa';\n ...\n needlePlugins(command, needleConfig, { pwa: pwaOptions }),\n VitePWA(pwaOptions),\n\nIf you want to manage PWA building yourself and skip this check, please pass '{ pwa: false }' to needlePlugins.";
8
8
 
9
9
  /** Provides reasonable defaults for a PWA manifest and workbox settings.
10
- * @param {string} command
11
10
  * @param {import('../types').userSettings} userSettings
12
11
  * @param {import("../types/needleConfig").needleMeta | null} config
13
12
  * @returns {import('vite').Plugin | void}
@@ -72,7 +71,7 @@ export const needlePWA = (command, config, userSettings) => {
72
71
  const customManifest = manifests.length > 0 ? manifests[0] : {};
73
72
 
74
73
  // ensure we have proper icons/name/description to match user settings
75
- processPWA(customManifest, context, pwaOptions, config, userSettings).catch((/** @type {unknown} */ e) => log("Error post processing PWA", customManifest, e));
74
+ processPWA(customManifest, context, pwaOptions, config, userSettings).catch(e => log("Error post processing PWA", customManifest, e));
76
75
  // ensures we have a valid workbox config
77
76
  processWorkboxConfig(pwaOptions);
78
77
 
@@ -82,15 +81,14 @@ export const needlePWA = (command, config, userSettings) => {
82
81
  // for debugging
83
82
  // log("PWA options", pwaOptions);
84
83
 
85
- return /** @type {import('vite').Plugin} */ ({
84
+ return {
86
85
  name: 'needle:pwa',
87
86
  apply: 'build',
88
87
  enforce: "post",
89
- config(/** @type {{ plugins?: Array<Record<string,unknown>> }} */ viteConfig) {
88
+ config(viteConfig) {
90
89
  // Move the gzip plugin after PWA bundling
91
90
  let gzipPluginIndex = -1;
92
91
  let pwaPluginIndex = -1;
93
- /** @type {Record<string, unknown> | null} */
94
92
  let gzipPlugin = null;
95
93
  if (viteConfig.plugins) {
96
94
  for (let i = viteConfig.plugins.length - 1; i >= 0; i--) {
@@ -170,7 +168,7 @@ export const needlePWA = (command, config, userSettings) => {
170
168
  }
171
169
  }
172
170
  }
173
- catch (/** @type {unknown} */ err) {
171
+ catch (err) {
174
172
  cleanup(context);
175
173
  throw err;
176
174
  }
@@ -253,7 +251,7 @@ updateSW = registerSW({
253
251
  try {
254
252
  copyIcons(pwaOptions.manifest, outputDir);
255
253
  }
256
- catch (/** @type {unknown} */ e) {
254
+ catch (e) {
257
255
  log("Error post processing PWA", e);
258
256
  }
259
257
 
@@ -263,23 +261,20 @@ updateSW = registerSW({
263
261
  console.log(msg);
264
262
  }
265
263
  }
266
- })
264
+ }
267
265
  }
268
266
 
269
267
  /** Checks if the vite-plugin-pwa is present in the vite config
270
- * @param {{ plugins?: readonly unknown[] }} config
268
+ * @param {import('vite').ResolvedConfig} config
271
269
  * @returns {import('vite-plugin-pwa').VitePWAOptions | null}
272
270
  */
273
271
  function findVitePWAPlugin(config) {
274
- const plugins = /** @type {Array<Record<string,unknown>>} */ (config.plugins || []);
275
- /** @param {unknown} p
276
- * @returns {Record<string, unknown> | undefined}
277
- */
272
+ const plugins = config.plugins || [];
278
273
  function _findVitePWAPlugin(p) {
279
274
  if (Array.isArray(p))
280
- return /** @type {Array<unknown>} */ (p).find(_findVitePWAPlugin);
281
- if (/** @type {Record<string,unknown>} */(p)?.name === "vite-plugin-pwa")
282
- return /** @type {Record<string, unknown>} */ (p);
275
+ return p.find(_findVitePWAPlugin);
276
+ if (p?.name === "vite-plugin-pwa")
277
+ return p;
283
278
  }
284
279
  for (const plugin of plugins) {
285
280
  const foundVitePWAPlugin = _findVitePWAPlugin(plugin);
@@ -288,7 +283,6 @@ function findVitePWAPlugin(config) {
288
283
  return null;
289
284
  }
290
285
 
291
- /** @param {import('../types/index.d.ts').NeedlePWAProcessContext} context */
292
286
  function cleanup(context) {
293
287
  for (const file of context.generatedFiles) {
294
288
  log("Cleanup generated file", file);
@@ -297,7 +291,6 @@ function cleanup(context) {
297
291
  context.generatedFiles.length = 0;
298
292
  }
299
293
 
300
- /** @param {...unknown} args */
301
294
  function log(...args) {
302
295
  console.log("[needle-pwa]", ...args);
303
296
  }
@@ -344,16 +337,10 @@ async function processPWA(webmanifestPath, context, pwaOptions, config, userSett
344
337
  // pwaOptions.includeAssets = [...pwaOptions.includeAssets, ...manifest.icons?.map(i => i.src)];
345
338
 
346
339
  const packageJsonPath = process.cwd() + "/package.json";
347
- const packageJson = /** @type {{ name?: string, description?: string }} */ (existsSync(packageJsonPath) ? JSON.parse(readFileSync(packageJsonPath, 'utf8')) : {});
340
+ const packageJson = existsSync(packageJsonPath) ? JSON.parse(readFileSync(packageJsonPath, 'utf8')) : {};
348
341
 
342
+ const name = packageJson.name;
349
343
  const appName = config?.sceneName || packageJson.name || "Needle App";
350
- const packageName = typeof packageJson.name === "string" && packageJson.name.length > 0
351
- ? packageJson.name
352
- : appName;
353
- const packageNameSanitized = packageName
354
- .toLowerCase()
355
- .replace(/[^a-z0-9\/\-]/g, '')
356
- .replace("\/", ".");
357
344
  const description = typeof config?.meta === "string"
358
345
  ? config.meta : config?.meta?.description
359
346
  || packageJson.description
@@ -364,11 +351,9 @@ async function processPWA(webmanifestPath, context, pwaOptions, config, userSett
364
351
  // Use the same title as in NeedleMeta
365
352
  name: appName,
366
353
  short_name: appName,
367
- id: "app.made-with-needle." + packageNameSanitized,
354
+ id: "app.made-with-needle." + name.toLowerCase().replace(/[^a-z0-9\/\-]/g, '').replace("\/", "."),
368
355
  description,
369
356
  start_url: "./index.html",
370
- theme_color: "#000000",
371
- background_color: "#000000",
372
357
  display: "standalone",
373
358
  display_override: [
374
359
  "window-controls-overlay",
@@ -438,7 +423,7 @@ function processIcons(manifest, outDir, context) {
438
423
  modified = true;
439
424
  }
440
425
  }
441
- catch (/** @type {unknown} */ e) {
426
+ catch (e) {
442
427
  log("Error processing PWA icon[" + i + "]", e);
443
428
  }
444
429
  }
@@ -475,7 +460,6 @@ function generateIcons(manifest, context) {
475
460
  /** Tries to copy the icons to the output directory
476
461
  * TODO this should not be needed if we use pwaOptions.includeAssets
477
462
  * @param {Partial<import("vite-plugin-pwa").ManifestOptions>} manifest
478
- * @param {string} outDir
479
463
  */
480
464
  function copyIcons(manifest, outDir) {
481
465
  for (let i = 0; i < manifest.icons?.length; i++) {
@@ -508,7 +492,7 @@ function copyIcons(manifest, outDir) {
508
492
  copyFileSync(srcPath, targetPath);
509
493
  }
510
494
  }
511
- catch (/** @type {unknown} */ e) {
495
+ catch (e) {
512
496
  log("Error processing PWA icon[" + i + "]", e);
513
497
  }
514
498
  }
@@ -598,7 +582,7 @@ function processWorkboxConfig(manifest) {
598
582
  },
599
583
  // allow caching local resources
600
584
  {
601
- urlPattern: (/** @type {{ url: URL }} */ { url }) => url,
585
+ urlPattern: ({ url }) => url,
602
586
  // Apply a network-first strategy.
603
587
  handler: 'NetworkFirst',
604
588
  options: {
@@ -1,22 +1,17 @@
1
- // @ts-check
2
1
  import path from 'path';
3
2
  import { loadConfig, tryLoadProjectConfig } from './config.js';
4
3
  import { getPosterPath } from './poster.js';
5
4
  import * as crypto from 'crypto';
6
5
  import { existsSync, readFileSync, statSync } from 'fs';
7
6
  import { fileURLToPath } from 'url';
8
- import { needleLog } from './logging.js';
9
7
 
10
8
  const __filename = fileURLToPath(import.meta.url);
11
9
  const __dirname = path.dirname(__filename);
12
10
 
13
- /** @type {Set<string>} */
14
11
  const filesUsingHotReload = new Set();
15
12
  let assetsDirectory = "";
16
13
 
17
14
  /**
18
- * @param {string} command
19
- * @param {import('../types').userSettings | null} config
20
15
  * @param {import('../types').userSettings} userSettings
21
16
  */
22
17
  export const needleReload = (command, config, userSettings) => {
@@ -39,8 +34,7 @@ export const needleReload = (command, config, userSettings) => {
39
34
 
40
35
  const buildDirectory = projectConfig?.buildDirectory?.length ? process.cwd().replaceAll("\\", "/") + "/" + projectConfig?.buildDirectory : "";
41
36
  if (buildDirectory?.length) {
42
- const relativeBuildDirectory = path.relative(process.cwd(), buildDirectory).replaceAll("\\", "/") || ".";
43
- setTimeout(() => needleLog("needle-reload", "Build directory: " + relativeBuildDirectory), 100);
37
+ setTimeout(() => console.log("Build directory: ", buildDirectory), 100);
44
38
  }
45
39
 
46
40
  // These ignore patterns will be injected into user config to better control vite reloading
@@ -50,7 +44,6 @@ export const needleReload = (command, config, userSettings) => {
50
44
 
51
45
  return {
52
46
  name: 'needle:reload',
53
- /** @param {import('vite').UserConfig} config */
54
47
  config(config) {
55
48
  if (!config.server) config.server = { watch: { ignored: [] } };
56
49
  else if (!config.server.watch) config.server.watch = { ignored: [] };
@@ -58,14 +51,12 @@ export const needleReload = (command, config, userSettings) => {
58
51
  for (const pattern of ignorePatterns)
59
52
  config.server.watch.ignored.push(pattern);
60
53
  if (config?.debug === true || userSettings?.debug === true)
61
- setTimeout(() => needleLog("needle-reload", "Updated server ignore patterns: " + JSON.stringify(config.server.watch.ignored)), 100);
54
+ setTimeout(() => console.log("Updated server ignore patterns: ", config.server.watch.ignored), 100);
62
55
  },
63
- /** @param {{file: string, server: import('vite').ViteDevServer, modules: unknown[], read: (file?: string) => Promise<string>, buildDirectory?: string}} args */
64
56
  handleHotUpdate(args) {
65
57
  args.buildDirectory = buildDirectory;
66
58
  return handleReload(args);
67
59
  },
68
- /** @param {string} src @param {string} id */
69
60
  transform(src, id) {
70
61
  if (!id.includes(".ts")) return;
71
62
  updateConfig();
@@ -76,7 +67,6 @@ export const needleReload = (command, config, userSettings) => {
76
67
  },
77
68
  transformIndexHtml: {
78
69
  order: 'pre',
79
- /** @param {string} html @param {unknown} _ */
80
70
  handler(html, _) {
81
71
  if (config?.allowHotReload === false) return html;
82
72
  if (userSettings?.allowHotReload === false) return html;
@@ -101,7 +91,6 @@ export const needleReload = (command, config, userSettings) => {
101
91
  }
102
92
 
103
93
 
104
- /** @type {string[]} */
105
94
  const ignorePatterns = [];
106
95
  const ignoreRegex = new RegExp(ignorePatterns.join("|"));
107
96
 
@@ -110,15 +99,11 @@ const posterPath = getPosterPath();
110
99
  let reloadIsScheduled = false;
111
100
  const lockFileName = "needle.lock";
112
101
 
113
- /** @param {import('vite').ViteDevServer} server @param {string} [file] */
114
102
  function notifyClientWillReload(server, file) {
115
103
  console.log("Send reload notification");
116
104
  server.ws.send('needle:reload', { type: 'will-reload', file: file });
117
105
  }
118
106
 
119
- /**
120
- * @param {{file: string, server: import('vite').ViteDevServer, modules: unknown[], read: (file?: string) => Promise<string>, buildDirectory?: string}} param0
121
- */
122
107
  async function handleReload({ file, server, modules, read, buildDirectory }) {
123
108
 
124
109
  // dont reload the full page on css changes
@@ -206,7 +191,6 @@ async function handleReload({ file, server, modules, read, buildDirectory }) {
206
191
  }
207
192
 
208
193
 
209
- /** @param {import('vite').ViteDevServer} server @param {number} [level] */
210
194
  async function scheduleReload(server, level = 0) {
211
195
  if (reloadIsScheduled && level === 0) return;
212
196
  reloadIsScheduled = true;
@@ -240,7 +224,6 @@ async function scheduleReload(server, level = 0) {
240
224
 
241
225
  const projectDirectory = process.cwd().replaceAll("\\", "/");
242
226
 
243
- /** @param {string} file @returns {string} */
244
227
  function getFileNameLog(file) {
245
228
  if (file.startsWith(projectDirectory)) {
246
229
  return file.substring(projectDirectory.length);
@@ -248,11 +231,9 @@ function getFileNameLog(file) {
248
231
  return file;
249
232
  }
250
233
 
251
- /** @type {Map<string, string>} */
252
234
  const hashes = new Map();
253
235
  const hash256 = crypto.createHash('sha256');
254
236
 
255
- /** @param {string} file @param {(file?: string) => Promise<string>} read @returns {Promise<boolean>} */
256
237
  async function testIfFileContentChanged(file, read) {
257
238
  let content = await read(file);
258
239
  content = removeVersionQueryArgument(content);
@@ -271,7 +252,6 @@ async function testIfFileContentChanged(file, read) {
271
252
  }
272
253
  return false;
273
254
  }
274
- /** @param {string} content @returns {string} */
275
255
  function removeVersionQueryArgument(content) {
276
256
  if (typeof content === "string") {
277
257
  // Some codegen files include hashes for loading glb files (e.g. ?v=213213124)
@@ -286,7 +266,6 @@ function removeVersionQueryArgument(content) {
286
266
 
287
267
 
288
268
 
289
- /** @param {string} src @param {string} filePath @returns {string} */
290
269
  function insertScriptRegisterHotReloadCode(src, filePath) {
291
270
 
292
271
  // We only want to inject the hot reload code in the needle-engine root file
@@ -305,7 +284,6 @@ globalThis.NEEDLE_HOT_RELOAD_ENABLED = true;
305
284
  const HOT_RELOAD_START_MARKER = "NEEDLE_HOT_RELOAD_BEGIN";
306
285
  const HOT_RELOAD_END_MARKER = "NEEDLE_HOT_RELOAD_END";
307
286
 
308
- /** @param {string} src @param {string} filePath @returns {{code: string, map: null} | undefined} */
309
287
  function insertScriptHotReloadCode(src, filePath) {
310
288
  if (filePath.includes("engine_hot_reload")) return;
311
289
  if (filePath.includes(".vite")) return;
package/src/engine/api.ts CHANGED
@@ -354,6 +354,9 @@ export { type ISerializable } from "./engine_serialization_core.js";
354
354
  // General-purpose utility functions and helpers.
355
355
  // ============================================================================
356
356
 
357
+ /** Testing utilities for automated tests */
358
+ export * from "./engine_test_utils.js";
359
+
357
360
  /** Texture utilities and processing */
358
361
  export * from "./engine_texture.js";
359
362
 
@@ -8,7 +8,7 @@ export {
8
8
  clearMessages as clearOverlayMessages,
9
9
  LogType,
10
10
  setAllowBalloonMessages,
11
- // eslint-disable-next-line @typescript-eslint/no-deprecated
11
+ // eslint-disable-next-line deprecation/deprecation
12
12
  setAllowOverlayMessages,
13
13
  };
14
14
  export { enableSpatialConsole } from "./debug_spatial_console.js";
@@ -169,11 +169,7 @@ class SpatialMessagesHandler {
169
169
 
170
170
  if (!fontFamily) {
171
171
  fontFamily = ThreeMeshUI.FontLibrary.addFontFamily(this.familyName);
172
- const variant = fontFamily.addVariant(
173
- "normal",
174
- "normal",
175
- "https://cdn.needle.tools/static/fonts/msdf/arial/arial-msdf.json",
176
- "https://cdn.needle.tools/static/fonts/msdf/arial/arial.png") as any as ThreeMeshUI.FontVariant;
172
+ const variant = fontFamily.addVariant("normal", "normal", "./include/needle/arial-msdf.json", "./include/needle/arial.png") as any as ThreeMeshUI.FontVariant;
177
173
  /** @ts-ignore */
178
174
  variant?.addEventListener('ready', () => {
179
175
  ThreeMeshUI.update();
@@ -1,7 +1,6 @@
1
1
  import { Object3D } from "three";
2
-
3
2
  import type { Context } from "./engine_setup";
4
- import { IComponent, isComponent } from "./engine_types.js";
3
+ import { IComponent, isComponent } from "./engine_types";
5
4
 
6
5
 
7
6
 
@@ -15,7 +15,6 @@ import { nodeFrame } from "three/examples/jsm/renderers/webgl-legacy/nodes/WebGL
15
15
 
16
16
  import { initSpectorIfAvailable } from './debug/debug_spector.js';
17
17
  import { isDevEnvironment, LogType, showBalloonError, showBalloonMessage } from './debug/index.js';
18
- import { AccessibilityManager } from './engine_accessibility.js';
19
18
  import { Addressables } from './engine_addressables.js';
20
19
  import { AnimationsRegistry } from './engine_animation.js';
21
20
  import { Application } from './engine_application.js';
@@ -45,6 +44,7 @@ import { deepClone, delay, DeviceUtilities, getParam } from './engine_utils.js';
45
44
  import type { INeedleXRSessionEventReceiver, NeedleXRSession } from './engine_xr.js';
46
45
  import { NeedleMenu } from './webcomponents/needle menu/needle-menu.js';
47
46
  import type { NeedleEngineWebComponent } from './webcomponents/needle-engine.js';
47
+ import { AccessibilityManager } from './engine_accessibility.js';
48
48
 
49
49
  const debug = getParam("debugcontext");
50
50
  const stats = getParam("stats");
@@ -565,7 +565,7 @@ export class Context implements IContext {
565
565
  this.input = new Input(this);
566
566
  this.physics = new Physics(this);
567
567
  this.connection = new NetworkConnection(this);
568
- // eslint-disable-next-line @typescript-eslint/no-deprecated
568
+ // eslint-disable-next-line deprecation/deprecation
569
569
  this.assets = new AssetDatabase();
570
570
  this.sceneLighting = new SceneLighting(this);
571
571
  this.addressables = new Addressables(this);
@@ -338,7 +338,7 @@ function loadFont(family: string | null): Font | Promise<Font> {
338
338
  url = "https://cdn.needle.tools/static/fonts/facetype/Open Sans_Regular_ascii.json";
339
339
  break;
340
340
  case "Helvetiker":
341
- url = "https://cdn.needle.tools/static/fonts/facetype/Helvetiker_Regular_ascii.json";
341
+ url = "https://raw.githubusercontent.com/mrdoob/three.js/master/examples/fonts/helvetiker_regular.typeface.json";
342
342
  break;
343
343
  }
344
344
  if (fontsDict.has(url)) {
@@ -1,10 +1,10 @@
1
- import { Box3, BoxGeometry, BufferAttribute, BufferGeometry, Color, type ColorRepresentation, CylinderGeometry, EdgesGeometry, Line, LineBasicMaterial, LineSegments, Material, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, SphereGeometry, Vector3 } from 'three';
2
- import ThreeMeshUI, { Text } from "three-mesh-ui"
1
+ import { AxesHelper, Box3, BoxGeometry, BufferAttribute, BufferGeometry, Color, type ColorRepresentation, CylinderGeometry, EdgesGeometry, Line, LineBasicMaterial, LineSegments, Material, Matrix4, Mesh, MeshBasicMaterial, Object3D, Quaternion, SphereGeometry, Vector3 } from 'three';
2
+ import ThreeMeshUI, { Inline, Text } from "three-mesh-ui"
3
3
  import { type Options } from 'three-mesh-ui/build/types/core/elements/MeshUIBaseElement.js';
4
4
 
5
5
  import { isDestroyed } from './engine_gameobject.js';
6
- import { Context } from './engine_setup.js';
7
- import { getTempVector, lookAtObject, setWorldPositionXYZ } from './engine_three_utils.js';
6
+ import { Context, FrameEvent } from './engine_setup.js';
7
+ import { getTempVector, getWorldPosition, lookAtObject, setWorldPositionXYZ } from './engine_three_utils.js';
8
8
  import type { Vec3, Vec4 } from './engine_types.js';
9
9
  import { getParam } from './engine_utils.js';
10
10
  import { NeedleXRSession } from './engine_xr.js';
@@ -341,11 +341,7 @@ class Internal {
341
341
 
342
342
  if (!fontFamily) {
343
343
  fontFamily = ThreeMeshUI.FontLibrary.addFontFamily(this.familyName);
344
- const variant = fontFamily.addVariant(
345
- "normal",
346
- "normal",
347
- "https://cdn.needle.tools/static/fonts/msdf/arial/arial-msdf.json",
348
- "https://cdn.needle.tools/static/fonts/msdf/arial/arial.png");
344
+ const variant = fontFamily.addVariant("normal", "normal", "https://uploads.needle.tools/include/font-msdf.json", "https://uploads.needle.tools/include/font.png") as any as ThreeMeshUI.FontVariant;
349
345
  /** @ts-ignore */
350
346
  variant?.addEventListener('ready', () => {
351
347
  ThreeMeshUI.update();
@@ -407,12 +407,7 @@ function insertNonCommercialUseHint(ctx: IContext) {
407
407
  padding-left: 30px;
408
408
  `;
409
409
  if (NEEDLE_ENGINE_LICENSE_TYPE === "edu") {
410
- if (navigator.webdriver) {
411
- console.log("This project is supported by Needle for Education – https://needle.tools");
412
- }
413
- else {
414
- console.log("%c " + "This project is supported by Needle for Education – https://needle.tools", style);
415
- }
410
+ console.log("%c " + "This project is supported by Needle for Education – https://needle.tools", style);
416
411
  }
417
412
  else {
418
413
  // if the user has a basic license we already show the logo in the menu and log a license message
@@ -507,7 +502,7 @@ async function logNonCommercialUse(_logo?: string) {
507
502
  // url must contain https for firefox to make it clickable
508
503
  const version = VERSION;
509
504
  const licenseText = `Needle Engine — No license active, commercial use is not allowed. Visit https://needle.tools/pricing for more information and licensing options! v${version}`;
510
- if (Context.Current?.xr || navigator.webdriver) {
505
+ if (Context.Current?.xr) {
511
506
  console.log(licenseText);
512
507
  }
513
508
  else {