@needle-tools/engine 4.5.0-alpha.1 → 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 (63) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/{needle-engine.bundle-c44e02c7.light.js → needle-engine.bundle-1526f05b.light.js} +4926 -4908
  3. package/dist/{needle-engine.bundle-b2e17f0e.light.min.js → needle-engine.bundle-15b19b2c.light.min.js} +125 -119
  4. package/dist/{needle-engine.bundle-e4ae93a2.min.js → needle-engine.bundle-2024e2b3.min.js} +125 -119
  5. package/dist/{needle-engine.bundle-3d05185b.js → needle-engine.bundle-53f80c62.js} +4924 -4906
  6. package/dist/{needle-engine.bundle-f496c70e.umd.cjs → needle-engine.bundle-a52706c5.umd.cjs} +135 -129
  7. package/dist/{needle-engine.bundle-d7d53476.light.umd.cjs → needle-engine.bundle-f3c8cffc.light.umd.cjs} +137 -131
  8. package/dist/needle-engine.js +467 -471
  9. package/dist/needle-engine.light.js +467 -471
  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_gltf.d.ts +2 -2
  18. package/lib/engine/engine_gltf_builtin_components.d.ts +5 -1
  19. package/lib/engine/engine_gltf_builtin_components.js +2 -2
  20. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  21. package/lib/engine/engine_loaders.callbacks.d.ts +62 -0
  22. package/lib/engine/engine_loaders.callbacks.js +56 -0
  23. package/lib/engine/engine_loaders.callbacks.js.map +1 -0
  24. package/lib/engine/engine_loaders.d.ts +44 -9
  25. package/lib/engine/engine_loaders.gltf.d.ts +13 -0
  26. package/lib/engine/engine_loaders.gltf.js +63 -0
  27. package/lib/engine/engine_loaders.gltf.js.map +1 -0
  28. package/lib/engine/engine_loaders.js +305 -48
  29. package/lib/engine/engine_loaders.js.map +1 -1
  30. package/lib/engine/engine_types.d.ts +7 -1
  31. package/lib/engine/engine_types.js +7 -0
  32. package/lib/engine/engine_types.js.map +1 -1
  33. package/lib/engine/engine_utils_format.d.ts +5 -3
  34. package/lib/engine/engine_utils_format.js +26 -10
  35. package/lib/engine/engine_utils_format.js.map +1 -1
  36. package/lib/engine/extensions/extensions.d.ts +3 -2
  37. package/lib/engine/extensions/extensions.js +10 -6
  38. package/lib/engine/extensions/extensions.js.map +1 -1
  39. package/lib/engine/webcomponents/needle-engine.attributes.d.ts +3 -6
  40. package/lib/engine/webcomponents/needle-engine.js +2 -2
  41. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  42. package/lib/engine/webcomponents/needle-engine.loading.js +26 -34
  43. package/lib/engine/webcomponents/needle-engine.loading.js.map +1 -1
  44. package/lib/engine-components/AvatarLoader.js +1 -1
  45. package/lib/engine-components/AvatarLoader.js.map +1 -1
  46. package/lib/engine-components/webxr/controllers/XRControllerModel.js +4 -3
  47. package/lib/engine-components/webxr/controllers/XRControllerModel.js.map +1 -1
  48. package/package.json +1 -1
  49. package/src/engine/api.ts +2 -1
  50. package/src/engine/engine_gltf.ts +2 -2
  51. package/src/engine/engine_gltf_builtin_components.ts +7 -7
  52. package/src/engine/engine_loaders.callbacks.ts +88 -0
  53. package/src/engine/engine_loaders.gltf.ts +82 -0
  54. package/src/engine/engine_loaders.ts +332 -54
  55. package/src/engine/engine_types.ts +34 -18
  56. package/src/engine/engine_utils_format.ts +32 -14
  57. package/src/engine/extensions/extensions.ts +12 -7
  58. package/src/engine/webcomponents/needle-engine.attributes.ts +3 -6
  59. package/src/engine/webcomponents/needle-engine.loading.ts +28 -36
  60. package/src/engine/webcomponents/needle-engine.ts +2 -2
  61. package/src/engine-components/AvatarLoader.ts +1 -1
  62. package/src/engine-components/webxr/controllers/XRControllerModel.ts +4 -3
  63. package/src/engine/engine_scenetools.ts +0 -379
@@ -1,5 +1,5 @@
1
1
  import type { QueryFilterFlags, World } from "@dimforge/rapier3d-compat";
2
- import { AnimationClip, Color, Material, Mesh, Object3D, Quaternion } from "three";
2
+ import { AnimationClip, Color, Loader, Material, Mesh, Object3D, Quaternion } from "three";
3
3
  import { Vector3 } from "three";
4
4
  import { type GLTF as THREE_GLTF } from "three/examples/jsm/loaders/GLTFLoader.js";
5
5
 
@@ -21,8 +21,10 @@ type NoInternals<T> = FilterStartingWith<T, "_">;
21
21
  type NoInternalNeedleEngineState<T> = Omit<T, "destroyed" | "gameObject" | "activeAndEnabled" | "context" | "isComponent" | "scene" | "up" | "forward" | "right" | "worldRotation" | "worldEuler" | "worldPosition" | "worldQuaternion">;
22
22
  export type ComponentInit<T> = Partial<NoInternalNeedleEngineState<NoInternals<NoUndefinedNoFunctions<T>>>>
23
23
 
24
+
24
25
  /** GLTF, GLB or VRM */
25
26
  export type GLTF = THREE_GLTF;
27
+
26
28
  /** FBX type */
27
29
  export type FBX = {
28
30
  animations: AnimationClip[];
@@ -35,8 +37,22 @@ export type OBJ = {
35
37
  scene: Object3D;
36
38
  scenes: Object3D[];
37
39
  }
40
+ export type CustomModel = {
41
+ animations: AnimationClip[];
42
+ scene: Object3D;
43
+ scenes: Object3D[];
44
+ }
45
+
38
46
  /** All possible model types that Needle Engine can load */
39
- export type Model = (GLTF | FBX | OBJ);
47
+ export type Model = (GLTF | FBX | OBJ | CustomModel);
48
+
49
+ export function isGLTFModel(model: Model): model is GLTF {
50
+ const gltf = model as GLTF;
51
+ if (gltf.parser && gltf.parser.json) {
52
+ return true;
53
+ }
54
+ return false;
55
+ }
40
56
 
41
57
  /** A loaded model */
42
58
  export type LoadedModel = {
@@ -218,7 +234,7 @@ export interface IComponent extends IHasGuid {
218
234
  get worldQuaternion(): Quaternion;
219
235
  }
220
236
 
221
- export function isComponent(obj:any) : obj is IComponent {
237
+ export function isComponent(obj: any): obj is IComponent {
222
238
  return obj && obj.isComponent;
223
239
  }
224
240
 
@@ -547,14 +563,14 @@ export interface IPhysicsEngine {
547
563
  * @param collider The collider component to add
548
564
  */
549
565
  addSphereCollider(collider: ICollider);
550
-
566
+
551
567
  /**
552
568
  * Adds a box collider to the physics world
553
569
  * @param collider The collider component to add
554
570
  * @param size The size of the box
555
571
  */
556
572
  addBoxCollider(collider: ICollider, size: Vector3);
557
-
573
+
558
574
  /**
559
575
  * Adds a capsule collider to the physics world
560
576
  * @param collider The collider component to add
@@ -562,7 +578,7 @@ export interface IPhysicsEngine {
562
578
  * @param height The height of the capsule
563
579
  */
564
580
  addCapsuleCollider(collider: ICollider, radius: number, height: number);
565
-
581
+
566
582
  /**
567
583
  * Adds a mesh collider to the physics world
568
584
  * @param collider The collider component to add
@@ -584,34 +600,34 @@ export interface IPhysicsEngine {
584
600
  * @param rb The rigidbody to wake up
585
601
  */
586
602
  wakeup(rb: IRigidbody);
587
-
603
+
588
604
  /**
589
605
  * Checks if a rigidbody is currently sleeping
590
606
  * @param rb The rigidbody to check
591
607
  * @returns Whether the rigidbody is sleeping or undefined if cannot be determined
592
608
  */
593
609
  isSleeping(rb: IRigidbody): boolean | undefined;
594
-
610
+
595
611
  /**
596
612
  * Updates the physical properties of a rigidbody or collider
597
613
  * @param rb The rigidbody or collider to update
598
614
  */
599
615
  updateProperties(rb: IRigidbody | ICollider);
600
-
616
+
601
617
  /**
602
618
  * Resets all forces acting on a rigidbody
603
619
  * @param rb The rigidbody to reset forces on
604
620
  * @param wakeup Whether to wake up the rigidbody
605
621
  */
606
622
  resetForces(rb: IRigidbody, wakeup: boolean);
607
-
623
+
608
624
  /**
609
625
  * Resets all torques acting on a rigidbody
610
626
  * @param rb The rigidbody to reset torques on
611
627
  * @param wakeup Whether to wake up the rigidbody
612
628
  */
613
629
  resetTorques(rb: IRigidbody, wakeup: boolean);
614
-
630
+
615
631
  /**
616
632
  * Adds a continuous force to a rigidbody
617
633
  * @param rb The rigidbody to add force to
@@ -619,7 +635,7 @@ export interface IPhysicsEngine {
619
635
  * @param wakeup Whether to wake up the rigidbody
620
636
  */
621
637
  addForce(rb: IRigidbody, vec: Vec3, wakeup: boolean);
622
-
638
+
623
639
  /**
624
640
  * Applies an instantaneous impulse to a rigidbody
625
641
  * @param rb The rigidbody to apply impulse to
@@ -627,21 +643,21 @@ export interface IPhysicsEngine {
627
643
  * @param wakeup Whether to wake up the rigidbody
628
644
  */
629
645
  applyImpulse(rb: IRigidbody, vec: Vec3, wakeup: boolean);
630
-
646
+
631
647
  /**
632
648
  * Gets the linear velocity of a rigidbody or the rigidbody attached to a collider
633
649
  * @param rb The rigidbody or collider to get velocity from
634
650
  * @returns The linear velocity vector or null if not available
635
651
  */
636
652
  getLinearVelocity(rb: IRigidbody | ICollider): Vec3 | null;
637
-
653
+
638
654
  /**
639
655
  * Gets the angular velocity of a rigidbody
640
656
  * @param rb The rigidbody to get angular velocity from
641
657
  * @returns The angular velocity vector or null if not available
642
658
  */
643
659
  getAngularVelocity(rb: IRigidbody): Vec3 | null;
644
-
660
+
645
661
  /**
646
662
  * Sets the angular velocity of a rigidbody
647
663
  * @param rb The rigidbody to set angular velocity for
@@ -649,7 +665,7 @@ export interface IPhysicsEngine {
649
665
  * @param wakeup Whether to wake up the rigidbody
650
666
  */
651
667
  setAngularVelocity(rb: IRigidbody, vec: Vec3, wakeup: boolean);
652
-
668
+
653
669
  /**
654
670
  * Sets the linear velocity of a rigidbody
655
671
  * @param rb The rigidbody to set linear velocity for
@@ -665,13 +681,13 @@ export interface IPhysicsEngine {
665
681
  * @param rotation Whether to update the rotation
666
682
  */
667
683
  updateBody(comp: ICollider | IRigidbody, translation: boolean, rotation: boolean);
668
-
684
+
669
685
  /**
670
686
  * Removes a physics body from the simulation
671
687
  * @param body The component whose physics body should be removed
672
688
  */
673
689
  removeBody(body: IComponent);
674
-
690
+
675
691
  /**
676
692
  * Gets the physics body for a component
677
693
  * @param obj The collider or rigidbody component
@@ -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";
@@ -9,7 +9,7 @@ import { setDontDestroy } from "../../../engine/engine_gameobject.js";
9
9
  import { Gizmos } from "../../../engine/engine_gizmos.js";
10
10
  import { getLoader } from "../../../engine/engine_gltf.js";
11
11
  import { createBuiltinComponents } from "../../../engine/engine_gltf_builtin_components.js";
12
- import { addDracoAndKTX2Loaders } from "../../../engine/engine_loaders.js";
12
+ import { addDracoAndKTX2Loaders } from "../../../engine/engine_loaders.gltf.js";
13
13
  import { serializable } from "../../../engine/engine_serialization_decorator.js";
14
14
  import type { IGameObject, SourceIdentifier } from "../../../engine/engine_types.js";
15
15
  import { getParam } from "../../../engine/engine_utils.js";
@@ -306,7 +306,7 @@ export class XRControllerModel extends Behaviour {
306
306
  // @ts-ignore
307
307
  const handmesh = new XRHandMeshModel(handObject, hand, loader.path, filename, loader, (object: Object3D) => {
308
308
 
309
- const gltf = componentsExtension.gltf;
309
+ const gltf = componentsExtension?.gltf;
310
310
  // The XRHandMeshController removes the hand from the gltf before calling this callback
311
311
  // we need this in the GLTF scene however for creating the builtin components
312
312
  if (gltf?.scene.children?.length === 0) {
@@ -314,7 +314,8 @@ export class XRControllerModel extends Behaviour {
314
314
  }
315
315
 
316
316
  // console.log(controller.side, componentsExtension.gltf, object, componentsExtension.gltf.scene?.children)
317
- getLoader().createBuiltinComponents(comp.context, comp.sourceId || filename, componentsExtension.gltf, null, componentsExtension);
317
+ if (componentsExtension?.gltf)
318
+ getLoader().createBuiltinComponents(comp.context, comp.sourceId || filename, componentsExtension.gltf, null, componentsExtension);
318
319
 
319
320
  // The hand mesh should not receive raycasts
320
321
  object.traverse(child => {