@needle-tools/engine 4.16.5-next.c1731f4 → 4.16.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/gltf-progressive-BacJPTD6.umd.cjs +10 -0
  2. package/dist/gltf-progressive-BmXoz_HR.min.js +10 -0
  3. package/dist/gltf-progressive-CzxjNmG6.js +1537 -0
  4. package/dist/loader.worker-BqODMeeW.js +23 -0
  5. package/dist/{materialx-DQ6OMWe8.js → materialx-BgYphGV9.js} +7 -6
  6. package/dist/{materialx-C3cdjbh7.umd.cjs → materialx-Dk-cjpFv.umd.cjs} +1 -1
  7. package/dist/{materialx-DwkZECrV.min.js → materialx-bmTetdSz.min.js} +1 -1
  8. package/dist/{needle-engine.bundle-CccTL32C.js → needle-engine.bundle-BN_X4iTv.js} +2495 -2456
  9. package/dist/{needle-engine.bundle-DXd0yCBg.umd.cjs → needle-engine.bundle-D-slQEcs.umd.cjs} +152 -152
  10. package/dist/{needle-engine.bundle-XVF9W1_-.min.js → needle-engine.bundle-DY-lNV9M.min.js} +121 -121
  11. package/dist/needle-engine.d.ts +193 -102
  12. package/dist/needle-engine.js +3 -3
  13. package/dist/needle-engine.min.js +1 -1
  14. package/dist/needle-engine.umd.cjs +1 -1
  15. package/dist/three-examples.js +4643 -3294
  16. package/dist/three-examples.min.js +47 -13
  17. package/dist/three-examples.umd.cjs +46 -12
  18. package/dist/three.js +15999 -24892
  19. package/dist/three.min.js +214 -214
  20. package/dist/three.umd.cjs +208 -208
  21. package/dist/{vendor-CQMI3jTS.js → vendor-BsRxp-FT.js} +901 -862
  22. package/dist/{vendor-CipoooTV.umd.cjs → vendor-BwxpsdCm.umd.cjs} +20 -20
  23. package/dist/{vendor-BPp9F5vR.min.js → vendor-DZ45lcA8.min.js} +19 -19
  24. package/lib/engine/engine_application.d.ts +0 -9
  25. package/lib/engine/engine_application.js.map +1 -1
  26. package/lib/engine/engine_feature_flags.d.ts +3 -3
  27. package/lib/engine/engine_feature_flags.js +5 -3
  28. package/lib/engine/engine_feature_flags.js.map +1 -1
  29. package/lib/engine/engine_modules.d.ts +30 -26
  30. package/lib/engine/engine_modules.js +103 -32
  31. package/lib/engine/engine_modules.js.map +1 -1
  32. package/lib/engine/webcomponents/needle-engine.d.ts +144 -57
  33. package/lib/engine/webcomponents/needle-engine.js +10 -1
  34. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  35. package/lib/engine-components/postprocessing/PostProcessingHandler.js +1 -1
  36. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  37. package/package.json +2 -4
  38. package/plugins/next/meshbvhworker.cjs +19 -0
  39. package/plugins/next/next.js +4 -34
  40. package/plugins/vite/alias.d.ts +1 -1
  41. package/plugins/vite/alias.js +82 -87
  42. package/plugins/vite/build-pipeline.js +3 -4
  43. package/plugins/vite/dependencies.js +5 -7
  44. package/plugins/vite/drop.js +8 -6
  45. package/plugins/vite/editor-connection.js +1 -2
  46. package/plugins/vite/poster.js +1 -2
  47. package/plugins/vite/reload.js +2 -7
  48. package/plugins/vite/transform-codegen.js +2 -6
  49. package/src/engine/engine_application.ts +0 -10
  50. package/src/engine/engine_feature_flags.ts +7 -3
  51. package/src/engine/engine_modules.ts +101 -39
  52. package/src/engine/webcomponents/needle-engine.ts +189 -59
  53. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  54. package/dist/gltf-progressive-BJ9OrddA.js +0 -28272
  55. package/dist/gltf-progressive-Ck_bXBr_.umd.cjs +0 -4022
  56. package/dist/gltf-progressive-CqZYu6Hx.min.js +0 -4022
  57. package/dist/loader.worker-CCrD-Ycm.js +0 -3
  58. package/plugins/next/meshbvhworker-import.cjs +0 -40
@@ -42,14 +42,16 @@ export function needleDrop(command, config, userSettings) {
42
42
  ];
43
43
  },
44
44
  },
45
- configureServer(/** @type {import('vite').ViteDevServer} */ server) {
46
- const hot = server.hot ?? server.ws;
45
+ configureServer(/** @type {{ ws: { on(event: string, cb: (...args: unknown[]) => void): void, send(type: string, data?: unknown): void } }} */ server) {
47
46
 
48
- hot.on('needle:drop-file', async (/** @type {unknown} */ data, /** @type {unknown} */ client) => {
49
- hot.send('needle-editor:drop-file', data);
47
+ server.ws.on('needle:drop-file', async (/** @type {unknown} */ data, /** @type {unknown} */ client) => {
48
+ server.ws.send('needle-editor:drop-file', data);
50
49
  });
50
+ // TODO: not sure how we can receive it with the normal vite server
51
+ // server.ws.on("custom", (data, client) => {
52
+ // console.log(data);
53
+ // })
51
54
 
52
- // Raw WebSocket access for editor messages
53
55
  server.ws.on('connection', (/** @type {{ on(event: string, cb: (...args: unknown[]) => void): void }} */ socket, /** @type {unknown} */ request) => {
54
56
  socket.on('message', async (/** @type {Buffer | string} */ bytes) => {
55
57
  try {
@@ -57,7 +59,7 @@ export function needleDrop(command, config, userSettings) {
57
59
  if (message && message.startsWith("{")) {
58
60
  const obj = /** @type {{ type: string, data: unknown }} */ (JSON.parse(message));
59
61
  if (obj.type === "needle-editor:exported-file") {
60
- hot.send(obj.type, obj.data);
62
+ server.ws.send(obj.type, obj.data);
61
63
  }
62
64
  }
63
65
  }
@@ -86,9 +86,8 @@ function createPlugin(isInstalled) {
86
86
  },
87
87
 
88
88
  configureServer(server) {
89
- try
89
+ try
90
90
  {
91
- // Raw WebSocket access needed for direct socket communication
92
91
  server.ws.on('connection', (socket, _request) => {
93
92
 
94
93
  // console.log("Send editor sync status: " + isInstalled);
@@ -24,8 +24,7 @@ export function needlePoster(command, config, userSettings) {
24
24
  return {
25
25
  name: 'needle:poster',
26
26
  configureServer(server) {
27
- const hot = server.hot ?? server.ws;
28
- hot.on('needle:screenshot', async (data, client) => {
27
+ server.ws.on('needle:screenshot', async (data, client) => {
29
28
  if (userSettings.noPoster) return;
30
29
  if (!data?.data) {
31
30
  console.warn("Received empty screenshot data, ignoring");
@@ -112,15 +112,10 @@ const posterPath = getPosterPath();
112
112
  let reloadIsScheduled = false;
113
113
  const lockFileName = "needle.lock";
114
114
 
115
- /** @param {import('vite').ViteDevServer} server */
116
- function getHot(server) {
117
- return server.hot ?? server.ws;
118
- }
119
-
120
115
  /** @param {import('vite').ViteDevServer} server @param {string} [file] */
121
116
  function notifyClientWillReload(server, file) {
122
117
  console.log("Send reload notification");
123
- getHot(server).send('needle:reload', { type: 'will-reload', file: file });
118
+ server.ws.send('needle:reload', { type: 'will-reload', file: file });
124
119
  }
125
120
 
126
121
  /**
@@ -241,7 +236,7 @@ async function scheduleReload(server, level = 0) {
241
236
  lastReloadTime = Date.now();
242
237
  const readableTime = new Date(lastReloadTime).toLocaleTimeString();
243
238
  console.log("< Reloading... " + readableTime)
244
- getHot(server).send({
239
+ server.ws.send({
245
240
  type: 'full-reload',
246
241
  path: '*'
247
242
  });
@@ -43,12 +43,8 @@ export function needleTransformCodegen(command, config, userSettings) {
43
43
  // }
44
44
 
45
45
  console.log(`[needle-transform-files] - Transform codegen paths \"${configuredAssetsDirectory}\" → \"${assetsDir}\"`)
46
- // replace codegen paths, but only in non-import lines
47
- // (import lines use filesystem-relative paths for bundler awareness)
48
- src = src.split('\n').map(line => {
49
- if (line.trimStart().startsWith('import ')) return line;
50
- return line.replaceAll(configuredAssetsDirectory, assetsDir);
51
- }).join('\n');
46
+ // replace codegen paths
47
+ src = src.replaceAll(configuredAssetsDirectory, assetsDir);
52
48
  return {
53
49
  code: src,
54
50
  map: null
@@ -1,16 +1,6 @@
1
1
  import { isDevEnvironment } from "./debug/index.js";
2
2
  import { Context } from "./engine_setup.js";
3
3
 
4
- declare global {
5
- interface UserActivation {
6
- readonly hasBeenActive: boolean;
7
- readonly isActive: boolean;
8
- }
9
- interface Navigator {
10
- readonly userActivation: UserActivation;
11
- }
12
- }
13
-
14
4
  export enum ApplicationEvents {
15
5
  Visible = "application-visible",
16
6
  Hidden = "application-hidden",
@@ -1,4 +1,8 @@
1
1
 
2
- export const NEEDLE_ENGINE_FEATURE_FLAGS = {
3
- experimentalSmartHierarchyUpdate: false,
4
- };
2
+
3
+ export namespace NEEDLE_ENGINE_FEATURE_FLAGS {
4
+
5
+ // eslint-disable-next-line prefer-const
6
+ export let experimentalSmartHierarchyUpdate = false;
7
+
8
+ }
@@ -1,46 +1,108 @@
1
1
 
2
- function createModule<T>(loader: () => Promise<T>) {
3
- const callbacks: Array<(module: T) => void> = [];
4
- const mod = {
5
- MODULE: undefined as unknown as T,
6
- MAYBEMODULE: null as T | null,
2
+ /**
3
+ * External dependencies that are loaded on demand either by the engine automatically when needed or they can be loaded manually by calling the `load` function.
4
+ *
5
+ * Use the `ready` function to wait for the module to be loaded if you do not wand to trigger a load.
6
+ *
7
+ * If a module is already loaded it's also available in the `MODULE` variable.
8
+ */
9
+ export namespace MODULES {
10
+
11
+ export namespace MaterialX {
12
+ export type TYPE = typeof import("@needle-tools/materialx");
13
+ export let MODULE: TYPE;
14
+ export let MAYBEMODULE: TYPE | null = null;
15
+
16
+ const callbacks: Array<(module: TYPE) => void> = [];
7
17
  /** Wait for the module to be loaded (doesn't trigger a load) */
8
- ready(): Promise<T> {
9
- if (mod.MODULE) return Promise.resolve(mod.MODULE);
10
- return new Promise(resolve => { callbacks.push(resolve); });
11
- },
18
+ export function ready(): Promise<TYPE> {
19
+ if (MODULE) return Promise.resolve(MODULE);
20
+ return new Promise((resolve) => { callbacks.push(resolve); });
21
+ };
12
22
  /** Load the module */
13
- async load(): Promise<T> {
14
- if (mod.MODULE) return mod.MODULE;
15
- const module = await loader();
16
- mod.MODULE = module;
17
- mod.MAYBEMODULE = module;
18
- for (const cb of callbacks) cb(module);
23
+ export async function load(): Promise<TYPE> {
24
+ if (MODULE) return MODULE;
25
+ const module = await import("@needle-tools/materialx");
26
+ MODULE = module;
27
+ MAYBEMODULE = module;
28
+ callbacks.forEach((callback) => callback(module));
19
29
  callbacks.length = 0;
20
30
  return module;
21
31
  }
22
- };
23
- return mod;
24
- }
25
32
 
26
- /**
27
- * External dependencies that are loaded on demand either by the engine automatically when needed or they can be loaded manually by calling the `load` function.
28
- *
29
- * Use the `ready` function to wait for the module to be loaded if you do not wand to trigger a load.
30
- *
31
- * If a module is already loaded it's also available in the `MODULE` variable.
32
- */
33
- export const MODULES = {
34
- MaterialX: createModule<typeof import("@needle-tools/materialx")>(
35
- () => import("@needle-tools/materialx")
36
- ),
37
- RAPIER_PHYSICS: createModule<typeof import("@dimforge/rapier3d-compat")>(
38
- () => import("@dimforge/rapier3d-compat")
39
- ),
40
- POSTPROCESSING: createModule<typeof import("postprocessing")>(
41
- () => import("postprocessing")
42
- ),
43
- POSTPROCESSING_AO: createModule<typeof import("n8ao")>(
44
- () => import("n8ao")
45
- ),
46
- };
33
+ }
34
+
35
+ export namespace RAPIER_PHYSICS {
36
+ export type TYPE = typeof import("@dimforge/rapier3d-compat");
37
+ export let MODULE: TYPE;
38
+ export let MAYBEMODULE: TYPE | null = null;
39
+
40
+ const callbacks: Array<(module: TYPE) => void> = [];
41
+ /** Wait for the module to be loaded (doesn't trigger a load) */
42
+ export function ready(): Promise<TYPE> {
43
+ if (MODULE) return Promise.resolve(MODULE);
44
+ return new Promise((resolve) => { callbacks.push(resolve); });
45
+ };
46
+ /** Load the module */
47
+ export async function load(): Promise<TYPE> {
48
+ if (MODULE) return MODULE;
49
+ const module = await import("@dimforge/rapier3d-compat");
50
+ MODULE = module;
51
+ MAYBEMODULE = module;
52
+ callbacks.forEach((callback) => callback(module));
53
+ callbacks.length = 0;
54
+ return module;
55
+ }
56
+
57
+ }
58
+
59
+ export namespace POSTPROCESSING {
60
+
61
+ export type TYPE = typeof import("postprocessing");
62
+ export let MODULE: TYPE;
63
+ export let MAYBEMODULE: TYPE | null = null;
64
+
65
+ const callbacks: Array<(module: TYPE) => void> = [];
66
+ /** Wait for the module to be loaded (doesn't trigger a load) */
67
+ export function ready(): Promise<TYPE> {
68
+ if (MODULE) return Promise.resolve(MODULE);
69
+ return new Promise((resolve) => { callbacks.push(resolve); });
70
+ };
71
+
72
+ /** Load the module */
73
+ export async function load(): Promise<TYPE> {
74
+ if (MODULE) return MODULE;
75
+ const module = await import("postprocessing");
76
+ MODULE = module;
77
+ MAYBEMODULE = module;
78
+ callbacks.forEach((callback) => callback(module));
79
+ callbacks.length = 0;
80
+ return module;
81
+ }
82
+ }
83
+
84
+ export namespace POSTPROCESSING_AO {
85
+
86
+ export type TYPE = typeof import("n8ao");
87
+ export let MODULE: TYPE;
88
+ export let MAYBEMODULE: TYPE | null = null;
89
+
90
+ const callbacks: Array<(module: TYPE) => void> = [];
91
+ /** Wait for the module to be loaded (doesn't trigger a load) */
92
+ export function ready(): Promise<TYPE> {
93
+ if (MODULE) return Promise.resolve(MODULE);
94
+ return new Promise((resolve) => { callbacks.push(resolve); });
95
+ };
96
+
97
+ /** Load the module */
98
+ export async function load(): Promise<TYPE> {
99
+ if (MODULE) return MODULE;
100
+ const module = await import("n8ao");
101
+ MODULE = module;
102
+ MAYBEMODULE = module;
103
+ callbacks.forEach((callback) => callback(module));
104
+ callbacks.length = 0;
105
+ return module;
106
+ }
107
+ }
108
+ }
@@ -38,58 +38,6 @@ const desktopSessionActiveClassName = "desktop-session-active";
38
38
 
39
39
  type TonemappingAttributeOptions = "none" | "linear" | "neutral" | "agx";
40
40
 
41
- /** Supported attributes for the `<needle-engine>` web component. */
42
- export interface NeedleEngineAttributes {
43
- /** Change which model gets loaded. */
44
- 'src': string;
45
- /** String attached to the context for caching/identification. */
46
- 'hash': string;
47
- /** Set to automatically add OrbitControls to the loaded scene. */
48
- 'camera-controls': string;
49
- /** Override the default draco decoder path location. */
50
- 'dracoDecoderPath': string;
51
- /** Override the default draco library type. */
52
- 'dracoDecoderType': 'wasm' | 'js';
53
- /** Override the default KTX2 transcoder/decoder path. */
54
- 'ktx2DecoderPath': string;
55
- /** Prevent context from being disposed when element is removed from DOM. */
56
- 'keep-alive': 'true' | 'false';
57
- /** Loading overlay style. */
58
- 'loading-style': 'dark' | 'light' | 'auto';
59
- /** URL to .exr, .hdr, .png, .jpg to be used as skybox. */
60
- 'background-image': string;
61
- /** Rotation of the background image in degrees. */
62
- 'background-rotation': string | number;
63
- /** URL to .exr, .hdr, .png, .jpg to be used for lighting. */
64
- 'environment-image': string;
65
- /** Intensity multiplier for environment lighting. */
66
- 'environment-intensity': string;
67
- /** Blurs the background image. 0 (sharp) to 1 (fully blurred). */
68
- 'background-blurriness': string;
69
- /** Intensity multiplier for the background image. */
70
- 'background-intensity': string;
71
- /** CSS background color if no skybox/background image is provided. */
72
- 'background-color': string;
73
- /** Enable/disable renderer canvas transparency. */
74
- 'transparent': 'true' | 'false';
75
- /** Enable/disable contact shadows. */
76
- 'contact-shadows': 'true' | 'false';
77
- /** Tonemapping mode. */
78
- 'tone-mapping': TonemappingAttributeOptions;
79
- /** Exposure multiplier for tonemapping. */
80
- 'tone-mapping-exposure': string;
81
- /** CSS selector or HTMLElement for camera focus. */
82
- 'focus-rect': string | HTMLElement;
83
- /** Allow pointer events to pass through transparent parts. */
84
- 'clickthrough': 'true' | 'false';
85
- /** Automatically fit model into camera view on load. */
86
- 'auto-fit': 'true' | 'false';
87
- /** Auto-rotate model until user interacts. */
88
- 'auto-rotate': 'true' | 'false';
89
- /** Play animations automatically on scene load. */
90
- 'autoplay': 'true' | 'false';
91
- }
92
-
93
41
  // #region Observables
94
42
 
95
43
  /** Keep in sync with the overloads and docs here:
@@ -958,18 +906,200 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
958
906
 
959
907
  // #region setAttribute
960
908
 
961
- /** Set a known Needle Engine attribute. See {@link NeedleEngineAttributes} for available attributes. */
962
- setAttribute<K extends keyof NeedleEngineAttributes>(name: K, value: NeedleEngineAttributes[K]): void;
963
- setAttribute(qualifiedName: string, value: string): void;
909
+ // MainAttributes
910
+ /** Change which model gets loaded. This will trigger a reload of the scene.
911
+ * @example src="path/to/scene.glb"
912
+ * @example src="[./path/scene1.glb, myOtherScene.gltf]"
913
+ * */
914
+ setAttribute(name: 'src', value: string): void;
915
+ /** Optional. String attached to the context for caching/identification. */
916
+ setAttribute(name: 'hash', value: string): void;
917
+ /** Set to automatically add {@link OrbitControls} to the loaded scene */
918
+ setAttribute(name: 'camera-controls', value: string): void;
919
+ /** Override the default draco decoder path location. */
920
+ setAttribute(name: 'dracoDecoderPath', value: string): void;
921
+ /** Override the default draco library type. */
922
+ setAttribute(name: 'dracoDecoderType', value: 'wasm' | 'js'): void;
923
+ /** Override the default KTX2 transcoder/decoder path */
924
+ setAttribute(name: 'ktx2DecoderPath', value: string): void;
925
+ /** Prevent Needle Engine context from being disposed when the element is removed from the DOM */
926
+ setAttribute(name: 'keep-alive', value: 'true' | 'false'): void;
927
+
928
+ /** @private Public key used for licensing and feature gating. */
929
+ setAttribute(name: 'public-key', value: string): void;
930
+ /** @private Engine version string — usually set by the build/runtime. */
931
+ setAttribute(name: 'version', value: string): void;
932
+
933
+ // LoadingAttributes
934
+ // ...
935
+
936
+ // SkyboxAttributes
937
+ /** URL to .exr, .hdr, .png, .jpg to be used as skybox */
938
+ setAttribute(name: 'background-image', value: string): void;
939
+ /** @private Rotation of the background image in degrees. */
940
+ setAttribute(name: 'background-rotation', value: string | number): void;
941
+ /** @deprecated Use 'environment-image' instead. */
942
+ setAttribute(name: 'skybox-image', value: string): void;
943
+ /** URL to .exr, .hdr, .png, .jpg to be used for lighting */
944
+ setAttribute(name: 'environment-image', value: string): void;
945
+ /** Intensity multiplier for environment lighting. */
946
+ setAttribute(name: 'environment-intensity', value: string): void;
947
+ /** Blurs the background image. Strength between 0 (sharp) and 1 (fully blurred). */
948
+ setAttribute(name: 'background-blurriness', value: string): void;
949
+ /** Intensity multiplier for the background image. */
950
+ setAttribute(name: 'background-intensity', value: string): void;
951
+ /**
952
+ * CSS background color value to be used if no skybox or background image is provided.
953
+ * @example "background-color='#ff0000'" will set the background color to red.
954
+ */
955
+ setAttribute(name: 'background-color', value: string): void;
956
+
957
+ // RenderingAttributes
958
+ /** Enable/disable renderer canvas transparency. */
959
+ setAttribute(name: 'transparent', value: 'true' | 'false'): void;
960
+ /** Enable/disable contact shadows in the rendered scene */
961
+ setAttribute(name: 'contact-shadows', value: 'true' | 'false'): void;
962
+ /** Tonemapping mode. */
963
+ setAttribute(name: 'tone-mapping', value: TonemappingAttributeOptions): void;
964
+ /** Exposure multiplier for tonemapping. */
965
+ setAttribute(name: 'tone-mapping-exposure', value: string): void;
966
+
967
+ /** Defines a CSS selector or HTMLElement where the camera should be focused on. Content will be fit into this element. */
968
+ setAttribute(name: 'focus-rect', value: string | HTMLElement): void;
969
+ /** Allow pointer events to pass through transparent parts of the content to the underlying DOM elements. */
970
+ setAttribute(name: 'clickthrough', value: 'true' | 'false'): void;
971
+ /** Automatically fits the model into the camera view on load. */
972
+ setAttribute(name: 'auto-fit', value: 'true' | 'false'): void;
973
+ /** Automatically rotates the model until a user interacts with the scene. */
974
+ setAttribute(name: 'auto-rotate', value: 'true' | 'false'): void;
975
+ /** Play animations automatically on scene load */
976
+ setAttribute(name: "autoplay", value: 'true' | 'false'): void;
977
+ /** @private Used for switching the scene in SceneSwitcher */
978
+ setAttribute(name: 'scene', value: string): void;
979
+
980
+ // setAttribute(name: 'loadstart', value: string): void;
981
+
982
+ /** @private Experimental.*/
983
+ setAttribute(name: 'loading-blur', value: 'true' | 'false'): void;
984
+ /** @private */
985
+ setAttribute(name: 'alias', value: string): void;
986
+ /** @private */
987
+ setAttribute(name: 'hide-loading-overlay', value: 'true' | 'false'): void;
988
+ /** @private */
989
+ setAttribute(name: 'no-telemetry', value: 'true' | 'false'): void;
990
+
991
+ /** Generic typed setter for known Needle Engine attributes */
992
+ // Comment out to see errors inside NE for undocumented attributes
993
+ // setAttribute<T extends keyof NeedleEngineAttributes>(qualifiedName: T, value: NeedleEngineAttributes[T]): void;
994
+
995
+ setAttribute(qualifiedName: ({} & string), value: string): void;
996
+
997
+ // The ones we're using internally:
998
+ /*
999
+ setAttribute(name: "tabindex", value: string): void;
1000
+ */
964
1001
  setAttribute(qualifiedName: string, value: string): void {
965
- super.setAttribute(qualifiedName, typeof value === "string" ? value : String(value));
1002
+ super.setAttribute(qualifiedName, value);
966
1003
  }
967
1004
 
968
1005
  // #region getAttribute
969
1006
 
970
- /** Get a known Needle Engine attribute. See {@link NeedleEngineAttributes} for available attributes. */
971
- getAttribute<K extends keyof NeedleEngineAttributes>(qualifiedName: K): string | null;
972
- getAttribute(qualifiedName: string): string | null;
1007
+ // MainAttributes
1008
+ /** Change which model gets loaded. This will trigger a reload of the scene.
1009
+ * @example src="path/to/scene.glb"
1010
+ * @example src="[./path/scene1.glb, myOtherScene.gltf]"
1011
+ * */
1012
+ getAttribute(name: 'src'): string | null;
1013
+ /** Optional. String attached to the context for caching/identification. */
1014
+ getAttribute(name: 'hash'): string | null;
1015
+ /** Set to automatically add {@link OrbitControls} to the loaded scene */
1016
+ getAttribute(name: 'camera-controls'): "true" | "false" | "none" | null;
1017
+ /** Override the default draco decoder path location. */
1018
+ getAttribute(name: 'dracoDecoderPath'): string | null;
1019
+ /** Override the default draco library type. */
1020
+ getAttribute(name: 'dracoDecoderType'): "wasm" | "js" | null;
1021
+ /** Override the default KTX2 transcoder/decoder path */
1022
+ getAttribute(name: 'ktx2DecoderPath'): string | null;
1023
+ /** Prevent Needle Engine context from being disposed when the element is removed from the DOM */
1024
+ getAttribute(name: 'keep-alive'): string | null;
1025
+
1026
+ /** @private Public key used for licensing and feature gating. */
1027
+ getAttribute(name: 'public-key'): string | null;
1028
+ /** @private Engine version string — usually set by the build/runtime. */
1029
+ getAttribute(name: 'version'): string | null;
1030
+
1031
+ // LoadingAttributes
1032
+ // ...
1033
+
1034
+ // SkyboxAttributes
1035
+ /** URL to .exr, .hdr, .png, .jpg to be used as skybox */
1036
+ getAttribute(name: 'background-image'): string | null;
1037
+ /** @private Rotation of the background image in degrees. */
1038
+ getAttribute(name: 'background-rotation'): string | null;
1039
+ /** URL to .exr, .hdr, .png, .jpg to be used for lighting */
1040
+ getAttribute(name: 'environment-image'): string | null;
1041
+ /** Intensity multiplier for environment lighting. */
1042
+ getAttribute(name: 'environment-intensity'): string | null;
1043
+ /** Blurs the background image. Strength between 0 (sharp) and 1 (fully blurred). */
1044
+ getAttribute(name: 'background-blurriness'): string | null;
1045
+ /** Intensity multiplier for the background image. */
1046
+ getAttribute(name: 'background-intensity'): string | null;
1047
+ /**
1048
+ * CSS background color value to be used if no skybox or background image is provided.
1049
+ * @example "background-color='#ff0000'" will set the background color to red.
1050
+ */
1051
+ getAttribute(name: 'background-color'): string | null;
1052
+
1053
+ // RenderingAttributes
1054
+ /** Enable/disable renderer canvas transparency. */
1055
+ getAttribute(name: 'transparent'): string | null;
1056
+ /** Enable/disable contact shadows in the rendered scene */
1057
+ getAttribute(name: 'contact-shadows'): string | null;
1058
+ /** @deprecated Use 'contact-shadows' instead. */
1059
+ getAttribute(name: 'contactshadows'): string | null;
1060
+ /** Tonemapping mode. */
1061
+ getAttribute(name: 'tone-mapping'): TonemappingAttributeOptions | null;
1062
+ /** @deprecated Use 'tone-mapping' instead. */
1063
+ getAttribute(name: 'tonemapping'): TonemappingAttributeOptions | null;
1064
+ /** Exposure multiplier for tonemapping. */
1065
+ getAttribute(name: 'tone-mapping-exposure'): string | null;
1066
+
1067
+ /** Defines a CSS selector or HTMLElement where the camera should be focused on. Content will be fit into this element. */
1068
+ getAttribute(name: 'focus-rect'): string | null;
1069
+ /** Allow pointer events to pass through transparent parts of the content to the underlying DOM elements. */
1070
+ getAttribute(name: 'clickthrough'): string | null;
1071
+ /** Automatically fits the model into the camera view on load. */
1072
+ getAttribute(name: 'auto-fit'): string | null;
1073
+ /** @deprecated Use 'auto-fit' instead. */
1074
+ getAttribute(name: 'autofit'): string | null;
1075
+ /** Automatically rotates the model until a user interacts with the scene. */
1076
+ getAttribute(name: 'auto-rotate'): string | null;
1077
+ /** Play animations automatically on scene load */
1078
+ getAttribute(name: "autoplay"): string | null;
1079
+ /** @private Used for switching the scene in SceneSwitcher */
1080
+ getAttribute(name: 'scene'): string | null;
1081
+ // getAttribute(name: 'loadstart'): string | null;
1082
+
1083
+ /** @private Experimental.*/
1084
+ getAttribute(name: 'loading-blur'): string | null;
1085
+ /** @private */
1086
+ getAttribute(name: 'alias'): string | null;
1087
+ /** @private */
1088
+ getAttribute(name: 'hide-loading-overlay'): string | null;
1089
+ /** @private */
1090
+ getAttribute(name: 'no-telemetry'): string | null;
1091
+
1092
+ // Comment these out to get development errors for undocumented NE attributes
1093
+ /** Typed getter for known NeedleEngine attribute names; returns the typed shape declared in NeedleEngineAttributes or null. */
1094
+ // getAttribute<T extends keyof NeedleEngineAttributes>(qualifiedName: T): NeedleEngineAttributes[T] | null;
1095
+ getAttribute(qualifiedName: ({} & string)): string | null;
1096
+
1097
+ // The ones we're using interally:
1098
+ /*
1099
+ getAttribute(name: "autostart"): string | null;
1100
+ getAttribute(name: "tabindex"): string | null;
1101
+ */
1102
+
973
1103
  getAttribute(qualifiedName: string): string | null {
974
1104
  return super.getAttribute(qualifiedName);
975
1105
  }
@@ -56,7 +56,7 @@ export class PostProcessingHandler {
56
56
  }
57
57
 
58
58
  apply(components: PostProcessingEffect[]): Promise<void> {
59
- if ("env" in import.meta && (import.meta as any /* webpack support */ ).env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
59
+ if ("env" in import.meta && import.meta.env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
60
60
  if (debug) console.warn("Postprocessing is disabled via vite env setting");
61
61
  else console.debug("Postprocessing is disabled via vite env setting");
62
62
  return Promise.resolve();