@needle-tools/engine 4.5.0-alpha → 4.5.0-alpha.2

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 (74) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/dist/{needle-engine.bundle-a2aadea9.light.js → needle-engine.bundle-1526f05b.light.js} +4883 -4855
  3. package/dist/{needle-engine.bundle-ff2e699c.light.min.js → needle-engine.bundle-15b19b2c.light.min.js} +122 -116
  4. package/dist/{needle-engine.bundle-19ca6713.min.js → needle-engine.bundle-2024e2b3.min.js} +122 -116
  5. package/dist/{needle-engine.bundle-916d62ca.js → needle-engine.bundle-53f80c62.js} +4887 -4859
  6. package/dist/{needle-engine.bundle-8bee539f.umd.cjs → needle-engine.bundle-a52706c5.umd.cjs} +120 -114
  7. package/dist/{needle-engine.bundle-032ef70a.light.umd.cjs → needle-engine.bundle-f3c8cffc.light.umd.cjs} +131 -125
  8. package/dist/needle-engine.js +467 -470
  9. package/dist/needle-engine.light.js +467 -470
  10. package/dist/needle-engine.light.min.js +1 -1
  11. package/dist/needle-engine.light.umd.cjs +1 -1
  12. package/dist/needle-engine.min.js +1 -1
  13. package/dist/needle-engine.umd.cjs +1 -1
  14. package/lib/engine/api.d.ts +2 -1
  15. package/lib/engine/api.js +2 -1
  16. package/lib/engine/api.js.map +1 -1
  17. package/lib/engine/engine_context.js +5 -1
  18. package/lib/engine/engine_context.js.map +1 -1
  19. package/lib/engine/engine_gltf.d.ts +2 -2
  20. package/lib/engine/engine_gltf_builtin_components.d.ts +5 -1
  21. package/lib/engine/engine_gltf_builtin_components.js +2 -2
  22. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  23. package/lib/engine/engine_hot_reload.d.ts +1 -0
  24. package/lib/engine/engine_hot_reload.js +16 -3
  25. package/lib/engine/engine_hot_reload.js.map +1 -1
  26. package/lib/engine/engine_loaders.callbacks.d.ts +62 -0
  27. package/lib/engine/engine_loaders.callbacks.js +56 -0
  28. package/lib/engine/engine_loaders.callbacks.js.map +1 -0
  29. package/lib/engine/engine_loaders.d.ts +44 -9
  30. package/lib/engine/engine_loaders.gltf.d.ts +13 -0
  31. package/lib/engine/engine_loaders.gltf.js +63 -0
  32. package/lib/engine/engine_loaders.gltf.js.map +1 -0
  33. package/lib/engine/engine_loaders.js +305 -48
  34. package/lib/engine/engine_loaders.js.map +1 -1
  35. package/lib/engine/engine_types.d.ts +7 -1
  36. package/lib/engine/engine_types.js +7 -0
  37. package/lib/engine/engine_types.js.map +1 -1
  38. package/lib/engine/engine_utils_format.d.ts +5 -3
  39. package/lib/engine/engine_utils_format.js +26 -10
  40. package/lib/engine/engine_utils_format.js.map +1 -1
  41. package/lib/engine/extensions/extensions.d.ts +3 -2
  42. package/lib/engine/extensions/extensions.js +10 -6
  43. package/lib/engine/extensions/extensions.js.map +1 -1
  44. package/lib/engine/webcomponents/needle-engine.attributes.d.ts +3 -6
  45. package/lib/engine/webcomponents/needle-engine.js +2 -2
  46. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  47. package/lib/engine/webcomponents/needle-engine.loading.js +26 -34
  48. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  49. package/lib/engine-components/AvatarLoader.js +1 -1
  50. package/lib/engine-components/AvatarLoader.js.map +1 -1
  51. package/lib/engine-components/Component.js +5 -0
  52. package/lib/engine-components/Component.js.map +1 -1
  53. package/lib/engine-components/webxr/controllers/XRControllerModel.js +4 -3
  54. package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
  55. package/package.json +1 -1
  56. package/plugins/vite/reload.js +8 -20
  57. package/src/engine/api.ts +2 -1
  58. package/src/engine/engine_context.ts +5 -1
  59. package/src/engine/engine_gltf.ts +2 -2
  60. package/src/engine/engine_gltf_builtin_components.ts +7 -7
  61. package/src/engine/engine_hot_reload.ts +16 -4
  62. package/src/engine/engine_loaders.callbacks.ts +88 -0
  63. package/src/engine/engine_loaders.gltf.ts +82 -0
  64. package/src/engine/engine_loaders.ts +332 -54
  65. package/src/engine/engine_types.ts +34 -18
  66. package/src/engine/engine_utils_format.ts +32 -14
  67. package/src/engine/extensions/extensions.ts +12 -7
  68. package/src/engine/webcomponents/needle-engine.attributes.ts +3 -6
  69. package/src/engine/webcomponents/needle-engine.loading.ts +28 -36
  70. package/src/engine/webcomponents/needle-engine.ts +2 -2
  71. package/src/engine-components/AvatarLoader.ts +1 -1
  72. package/src/engine-components/Component.ts +51 -48
  73. package/src/engine-components/webxr/controllers/XRControllerModel.ts +4 -3
  74. package/src/engine/engine_scenetools.ts +0 -379
@@ -1,4 +1,5 @@
1
1
  import { isDevEnvironment } from "./debug/index.js";
2
+ import { NeedleEngineModelLoader, registeredFileTypeCallbacks } from "./engine_loaders.callbacks.js";
2
3
  import { getParam } from "./engine_utils.js";
3
4
 
4
5
  const debug = getParam("debugfileformat");
@@ -6,7 +7,7 @@ const debug = getParam("debugfileformat");
6
7
  /**
7
8
  * The supported file types that can be determined by the engine. Used in {@link tryDetermineFileTypeFromURL} and {@link tryDetermineFileTypeFromBinary}
8
9
  */
9
- export declare type FileType = "gltf" | "glb" | "vrm" | "fbx" | "obj" | "usdz" | "usd" | "usda" | "unknown";
10
+ export declare type FileType = "gltf" | "glb" | "vrm" | "fbx" | "obj" | "usdz" | "usd" | "usda" | "unknown" | ({} & string);
10
11
 
11
12
  /**
12
13
  * Tries to determine the file type of a file from its URL
@@ -20,7 +21,9 @@ export declare type FileType = "gltf" | "glb" | "vrm" | "fbx" | "obj" | "usdz" |
20
21
  * const fileType = await tryDetermineFileTypeFromURL(url);
21
22
  * console.log(fileType); // "glb"
22
23
  */
23
- export async function tryDetermineFileTypeFromURL(url: string, useExtension: boolean = true): Promise<FileType> {
24
+ export async function tryDetermineFileTypeFromURL(url: string, opts: { useExtension: boolean }): Promise<FileType> {
25
+
26
+ const { useExtension = true } = opts;
24
27
 
25
28
  if (useExtension) {
26
29
  // We want to save on requests so we first check the file extension if there's any
@@ -59,11 +62,12 @@ export async function tryDetermineFileTypeFromURL(url: string, useExtension: boo
59
62
  }
60
63
  }
61
64
 
62
-
65
+
63
66
  // If the URL doesnt contain a filetype we need to check the header
64
67
  // This is the case for example if we load a file from a data url
68
+ const originalUrl = url;
65
69
 
66
- if(url.startsWith("blob:")) {
70
+ if (url.startsWith("blob:")) {
67
71
  // We can't modify the blob URL
68
72
  }
69
73
  else {
@@ -84,7 +88,7 @@ export async function tryDetermineFileTypeFromURL(url: string, useExtension: boo
84
88
 
85
89
  if (header?.ok) {
86
90
  const data = await header.arrayBuffer();
87
- const res = tryDetermineFileTypeFromBinary(data, header);
91
+ const res = tryDetermineFileTypeFromBinary(originalUrl, data, header);
88
92
  if (debug) console.log("Determined file type from header: " + res);
89
93
  return res;
90
94
  }
@@ -96,7 +100,7 @@ export async function tryDetermineFileTypeFromURL(url: string, useExtension: boo
96
100
  /** Attempts to determine the file type of a binary file by looking at the first few bytes of the file.
97
101
  * @hidden
98
102
  */
99
- export function tryDetermineFileTypeFromBinary(data: ArrayBuffer, response: Response): FileType {
103
+ export function tryDetermineFileTypeFromBinary(url: string, data: ArrayBuffer, response: Response): FileType {
100
104
 
101
105
  if (data.byteLength < 4) {
102
106
  return "unknown";
@@ -193,14 +197,6 @@ export function tryDetermineFileTypeFromBinary(data: ArrayBuffer, response: Resp
193
197
  console.debug("OBJ detected (mtllib)");
194
198
  return "obj";
195
199
  }
196
-
197
- if (isDevEnvironment() || debug) {
198
- const text = new TextDecoder().decode(data.slice(0, 16));
199
- console.debug("Could not determine file type from binary data: \"" + text + "...\"", bytes);
200
- }
201
- else {
202
- console.debug("Could not determine file type from binary data", bytes);
203
- }
204
200
  // const text = new TextDecoder().decode(data);
205
201
  // if (text.startsWith("Kaydara FBX")) {
206
202
  // return "fbx";
@@ -209,5 +205,27 @@ export function tryDetermineFileTypeFromBinary(data: ArrayBuffer, response: Resp
209
205
  // return "gltf";
210
206
  // }
211
207
 
208
+ for (const callback of registeredFileTypeCallbacks) {
209
+ const mimetype = callback({
210
+ url: url,
211
+ response: response,
212
+ contentType: response.headers.get("content-type"),
213
+ bytes: bytes
214
+ })
215
+ if (mimetype) {
216
+ if (debug) console.debug(`Mimetype callback returned: ${mimetype}`);
217
+ return mimetype;
218
+ }
219
+ }
220
+
221
+
222
+ if (isDevEnvironment() || debug) {
223
+ const text = new TextDecoder().decode(data.slice(0, Math.min(data.byteLength, 32)));
224
+ console.warn(`Could not determine file type.\n\nConsider registering a custom loader via the 'onCreateCustomModelLoader' callback: 'NeedleEngineModelLoader.onCreateCustomModelLoader(args => { })'\n\nContent-Type: \"${response.headers.get("content-type")}\n\"Text: \"${text}\"\nBinary:`, bytes);
225
+ }
226
+ else {
227
+ console.debug(`Could not determine file type from binary data`);
228
+ }
229
+
212
230
  return "unknown";
213
231
  }
@@ -1,3 +1,4 @@
1
+ import { Loader } from "three";
1
2
  import { GLTFExporter } from "three/examples/jsm/exporters/GLTFExporter.js";
2
3
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
3
4
 
@@ -66,13 +67,17 @@ export function removeCustomImportExtensionType(ext: INeedleGLTFExtensionPlugin)
66
67
 
67
68
 
68
69
  /** Registers the Needle Engine components extension */
69
- export function registerComponentExtension(loader: GLTFLoader): NEEDLE_components {
70
- const ext = new NEEDLE_components();
71
- loader.register(p => {
72
- ext.parser = p;
70
+ export function registerComponentExtension(loader: GLTFLoader | Loader | object): NEEDLE_components | null {
71
+ if (loader instanceof GLTFLoader) {
72
+ const ext = new NEEDLE_components();
73
+ loader.register(p => {
74
+ ext.parser = p;
75
+ return ext;
76
+ });
73
77
  return ext;
74
- });
75
- return ext;
78
+ }
79
+
80
+ return null;
76
81
  }
77
82
 
78
83
 
@@ -130,7 +135,7 @@ export function registerExportExtensions(exp: GLTFExporter, context: Context) {
130
135
  }
131
136
 
132
137
  /** @internal */
133
- export function invokeAfterImportPluginHooks(url: string, gltf: GLTF, context: Context) {
138
+ export function invokeLoadedImportPluginHooks(url: string, gltf: GLTF, context: Context) {
134
139
  for (const ext of _plugins)
135
140
  if (ext.onLoaded) ext.onLoaded(url, gltf, context);
136
141
  }
@@ -31,19 +31,16 @@ type MainAttributes = {
31
31
  }
32
32
 
33
33
  type LoadingAttributes = {
34
- "loading-style"?: "light" | "dark",
35
- /** Pro feature */
34
+ /** Set a custom loading background color (e.g. "red" or "#dd00ff" or "rgba(18, 224, 224, 0.5)") */
35
+ "loading-background"?: string,
36
+ /** Pro features */
36
37
  "hide-loading-overlay"?: boolean,
37
38
  /** Pro feature */
38
- "loading-background-color"?: string,
39
- /** Pro feature */
40
39
  "loading-logo-src"?: string,
41
40
  /** Pro feature */
42
41
  "primary-color"?: string,
43
42
  /** Pro feature */
44
43
  "secondary-color"?: string,
45
- /** Pro feature */
46
- "loading-text-color"?: string,
47
44
  }
48
45
 
49
46
  type SkyboxAttributes = {
@@ -197,10 +197,12 @@ export class EngineLoadingView implements ILoadingViewHandler {
197
197
  this._loadingElement.style.height = "100%";
198
198
  this._loadingElement.style.left = "0";
199
199
  this._loadingElement.style.top = "0";
200
- if (loadingStyle === "light")
201
- this._loadingElement.style.backgroundColor = "#ddd";
200
+ const loadingBackgroundColor = this._element.getAttribute("loading-background");
201
+ if (loadingBackgroundColor) {
202
+ this._loadingElement.style.background = loadingBackgroundColor;
203
+ }
202
204
  else
203
- this._loadingElement.style.backgroundColor = "#222";
205
+ this._loadingElement.style.backgroundColor = "transparent";
204
206
  this._loadingElement.style.display = "flex";
205
207
  this._loadingElement.style.alignItems = "center";
206
208
  this._loadingElement.style.justifyContent = "center";
@@ -214,16 +216,6 @@ export class EngineLoadingView implements ILoadingViewHandler {
214
216
  this._loadingElement.style.color = "rgba(0,0,0,.6)";
215
217
  else
216
218
  this._loadingElement.style.color = "rgba(255,255,255,.3)";
217
- if (hasLicense && this._element) {
218
- const loadingBackgroundColor = this._element.getAttribute("loading-background-color");
219
- if (loadingBackgroundColor) {
220
- this._loadingElement.style.backgroundColor = loadingBackgroundColor;
221
- }
222
- const textColor = this._element.getAttribute("loading-text-color");
223
- if (textColor) {
224
- this._loadingElement.style.color = textColor;
225
- }
226
- }
227
219
  }
228
220
 
229
221
  const className = this._loadingElementOptions?.className ?? EngineLoadingView.LoadingContainerClassName;
@@ -302,8 +294,8 @@ export class EngineLoadingView implements ILoadingViewHandler {
302
294
  const getGradientPos = function (t: number): string {
303
295
  return Mathf.lerp(0, maxWidth, t) + "%";
304
296
  }
305
- this._loadingBar.style.background =
306
- `linear-gradient(90deg, #204f49 ${getGradientPos(0)}, #0BA398 ${getGradientPos(.3)}, #66A22F ${getGradientPos(.6)}, #D7DB0A ${getGradientPos(1)})`;
297
+ this._loadingBar.style.background = "#66A22F";
298
+ // `linear-gradient(90deg, #204f49 ${getGradientPos(0)}, #0BA398 ${getGradientPos(.3)}, #66A22F ${getGradientPos(.6)}, #D7DB0A ${getGradientPos(1)})`;
307
299
  this._loadingBar.style.backgroundAttachment = "fixed";
308
300
  this._loadingBar.style.width = "0%";
309
301
  this._loadingBar.style.height = "100%";
@@ -321,27 +313,27 @@ export class EngineLoadingView implements ILoadingViewHandler {
321
313
  }
322
314
  }
323
315
 
324
- this._loadingTextContainer = document.createElement("div");
325
- this._loadingTextContainer.style.display = "flex";
326
- this._loadingTextContainer.style.justifyContent = "center";
327
- this._loadingTextContainer.style.marginTop = ".2rem";
328
- details.appendChild(this._loadingTextContainer);
329
-
330
- const messageContainer = document.createElement("div");
331
- this._messageContainer = messageContainer;
332
- messageContainer.style.display = "flex";
333
- messageContainer.style.fontSize = ".8rem";
334
- messageContainer.style.paddingTop = ".1rem";
335
- // messageContainer.style.border = "1px solid rgba(255,255,255,.1)";
336
- messageContainer.style.justifyContent = "center";
337
- details.appendChild(messageContainer);
338
-
339
- if (hasLicense && this._element) {
340
- const loadingTextColor = this._element.getAttribute("loading-text-color");
341
- if (loadingTextColor) {
342
- messageContainer.style.color = loadingTextColor;
343
- }
344
- }
316
+ // this._loadingTextContainer = document.createElement("div");
317
+ // this._loadingTextContainer.style.display = "flex";
318
+ // this._loadingTextContainer.style.justifyContent = "center";
319
+ // this._loadingTextContainer.style.marginTop = ".2rem";
320
+ // details.appendChild(this._loadingTextContainer);
321
+
322
+ // const messageContainer = document.createElement("div");
323
+ // this._messageContainer = messageContainer;
324
+ // messageContainer.style.display = "flex";
325
+ // messageContainer.style.fontSize = ".8rem";
326
+ // messageContainer.style.paddingTop = ".1rem";
327
+ // // messageContainer.style.border = "1px solid rgba(255,255,255,.1)";
328
+ // messageContainer.style.justifyContent = "center";
329
+ // details.appendChild(messageContainer);
330
+
331
+ // if (hasLicense && this._element) {
332
+ // const loadingTextColor = this._element.getAttribute("loading-text-color");
333
+ // if (loadingTextColor) {
334
+ // messageContainer.style.color = loadingTextColor;
335
+ // }
336
+ // }
345
337
 
346
338
  this.handleRuntimeLicense(this._loadingElement);
347
339
 
@@ -4,8 +4,8 @@ import { isDevEnvironment, showBalloonWarning } from "../debug/index.js";
4
4
  import { PUBLIC_KEY, VERSION } from "../engine_constants.js";
5
5
  import { registerLoader } from "../engine_gltf.js";
6
6
  import { hasCommercialLicense } from "../engine_license.js";
7
- import { setDracoDecoderPath, setDracoDecoderType, setKtx2TranscoderPath } from "../engine_loaders.js";
8
- import { NeedleLoader } from "../engine_scenetools.js";
7
+ import { setDracoDecoderPath, setDracoDecoderType, setKtx2TranscoderPath } from "../engine_loaders.gltf.js";
8
+ import { NeedleLoader } from "../engine_loaders.js";
9
9
  import { Context, ContextCreateArgs } from "../engine_setup.js";
10
10
  import { type INeedleEngineComponent, type LoadedModel } from "../engine_types.js";
11
11
  import { getParam } from "../engine_utils.js";
@@ -3,7 +3,7 @@ import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
3
3
 
4
4
  import { InstantiateOptions } from "../engine/engine_gameobject.js";
5
5
  import { getLoader } from "../engine/engine_gltf.js";
6
- import * as loaders from "../engine/engine_loaders.js"
6
+ import * as loaders from "../engine/engine_loaders.gltf.js"
7
7
  import { Context } from "../engine/engine_setup.js";
8
8
  import * as utils from "../engine/engine_utils.js"
9
9
  import { GameObject } from "./Component.js";