@needle-tools/engine 4.16.5 → 4.17.0-next.694aef7

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 (59) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/gltf-progressive-BJ9OrddA.js +28272 -0
  3. package/dist/gltf-progressive-Ck_bXBr_.umd.cjs +4022 -0
  4. package/dist/gltf-progressive-CqZYu6Hx.min.js +4022 -0
  5. package/dist/loader.worker-CCrD-Ycm.js +3 -0
  6. package/dist/{materialx-Dk-cjpFv.umd.cjs → materialx-C3cdjbh7.umd.cjs} +1 -1
  7. package/dist/{materialx-BgYphGV9.js → materialx-DQ6OMWe8.js} +6 -7
  8. package/dist/{materialx-bmTetdSz.min.js → materialx-DwkZECrV.min.js} +1 -1
  9. package/dist/{needle-engine.bundle-Cndz6kVg.min.js → needle-engine.bundle-BXFYDqlX.min.js} +121 -121
  10. package/dist/{needle-engine.bundle-_FYakfzP.js → needle-engine.bundle-XHfowyU9.js} +2456 -2495
  11. package/dist/{needle-engine.bundle-D7PAIzue.umd.cjs → needle-engine.bundle-y_bL1MYi.umd.cjs} +150 -150
  12. package/dist/needle-engine.d.ts +102 -193
  13. package/dist/needle-engine.js +3 -3
  14. package/dist/needle-engine.min.js +1 -1
  15. package/dist/needle-engine.umd.cjs +1 -1
  16. package/dist/three-examples.js +3294 -4643
  17. package/dist/three-examples.min.js +13 -47
  18. package/dist/three-examples.umd.cjs +12 -46
  19. package/dist/three.js +24892 -15999
  20. package/dist/three.min.js +214 -214
  21. package/dist/three.umd.cjs +208 -208
  22. package/dist/{vendor-DZ45lcA8.min.js → vendor-BPp9F5vR.min.js} +19 -19
  23. package/dist/{vendor-BsRxp-FT.js → vendor-CQMI3jTS.js} +862 -901
  24. package/dist/{vendor-BwxpsdCm.umd.cjs → vendor-CipoooTV.umd.cjs} +20 -20
  25. package/lib/engine/engine_application.d.ts +9 -0
  26. package/lib/engine/engine_application.js.map +1 -1
  27. package/lib/engine/engine_feature_flags.d.ts +3 -3
  28. package/lib/engine/engine_feature_flags.js +3 -5
  29. package/lib/engine/engine_feature_flags.js.map +1 -1
  30. package/lib/engine/engine_modules.d.ts +26 -30
  31. package/lib/engine/engine_modules.js +32 -103
  32. package/lib/engine/engine_modules.js.map +1 -1
  33. package/lib/engine/webcomponents/needle-engine.d.ts +57 -144
  34. package/lib/engine/webcomponents/needle-engine.js +1 -10
  35. package/lib/engine/webcomponents/needle-engine.js.map +1 -1
  36. package/lib/engine-components/postprocessing/PostProcessingHandler.js +1 -1
  37. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  38. package/package.json +4 -2
  39. package/plugins/next/meshbvhworker-import.cjs +40 -0
  40. package/plugins/next/next.js +34 -4
  41. package/plugins/vite/alias.d.ts +1 -1
  42. package/plugins/vite/alias.js +87 -82
  43. package/plugins/vite/build-pipeline.js +4 -3
  44. package/plugins/vite/dependencies.js +7 -5
  45. package/plugins/vite/drop.js +6 -8
  46. package/plugins/vite/editor-connection.js +2 -1
  47. package/plugins/vite/poster.js +2 -1
  48. package/plugins/vite/reload.js +7 -2
  49. package/plugins/vite/transform-codegen.js +6 -2
  50. package/src/engine/engine_application.ts +10 -0
  51. package/src/engine/engine_feature_flags.ts +3 -7
  52. package/src/engine/engine_modules.ts +39 -101
  53. package/src/engine/webcomponents/needle-engine.ts +59 -189
  54. package/src/engine-components/postprocessing/PostProcessingHandler.ts +1 -1
  55. package/dist/gltf-progressive-BacJPTD6.umd.cjs +0 -10
  56. package/dist/gltf-progressive-BmXoz_HR.min.js +0 -10
  57. package/dist/gltf-progressive-CzxjNmG6.js +0 -1537
  58. package/dist/loader.worker-BqODMeeW.js +0 -23
  59. package/plugins/next/meshbvhworker.cjs +0 -19
@@ -103,14 +103,16 @@ function handleManualChunks(config) {
103
103
  if (!config.build) {
104
104
  config.build = {};
105
105
  }
106
- if (!config.build.rollupOptions) {
107
- config.build.rollupOptions = {};
106
+ // Support both rolldownOptions (Vite 8+) and rollupOptions (Vite 7 and earlier)
107
+ const optionsKey = 'rolldownOptions' in (config.build) ? 'rolldownOptions' : 'rollupOptions';
108
+ if (!config.build[optionsKey]) {
109
+ config.build[optionsKey] = {};
108
110
  }
109
- if (!config.build.rollupOptions.output) {
110
- config.build.rollupOptions.output = {};
111
+ if (!config.build[optionsKey].output) {
112
+ config.build[optionsKey].output = {};
111
113
  }
112
114
 
113
- const rollupOutput = config.build.rollupOptions.output;
115
+ const rollupOutput = config.build[optionsKey].output;
114
116
 
115
117
  if (Array.isArray(rollupOutput)) {
116
118
  // append the manualChunks function to the array
@@ -42,16 +42,14 @@ export function needleDrop(command, config, userSettings) {
42
42
  ];
43
43
  },
44
44
  },
45
- configureServer(/** @type {{ ws: { on(event: string, cb: (...args: unknown[]) => void): void, send(type: string, data?: unknown): void } }} */ server) {
45
+ configureServer(/** @type {import('vite').ViteDevServer} */ server) {
46
+ const hot = server.hot ?? server.ws;
46
47
 
47
- server.ws.on('needle:drop-file', async (/** @type {unknown} */ data, /** @type {unknown} */ client) => {
48
- server.ws.send('needle-editor:drop-file', data);
48
+ hot.on('needle:drop-file', async (/** @type {unknown} */ data, /** @type {unknown} */ client) => {
49
+ hot.send('needle-editor:drop-file', data);
49
50
  });
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
- // })
54
51
 
52
+ // Raw WebSocket access for editor messages
55
53
  server.ws.on('connection', (/** @type {{ on(event: string, cb: (...args: unknown[]) => void): void }} */ socket, /** @type {unknown} */ request) => {
56
54
  socket.on('message', async (/** @type {Buffer | string} */ bytes) => {
57
55
  try {
@@ -59,7 +57,7 @@ export function needleDrop(command, config, userSettings) {
59
57
  if (message && message.startsWith("{")) {
60
58
  const obj = /** @type {{ type: string, data: unknown }} */ (JSON.parse(message));
61
59
  if (obj.type === "needle-editor:exported-file") {
62
- server.ws.send(obj.type, obj.data);
60
+ hot.send(obj.type, obj.data);
63
61
  }
64
62
  }
65
63
  }
@@ -86,8 +86,9 @@ 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
91
92
  server.ws.on('connection', (socket, _request) => {
92
93
 
93
94
  // console.log("Send editor sync status: " + isInstalled);
@@ -24,7 +24,8 @@ export function needlePoster(command, config, userSettings) {
24
24
  return {
25
25
  name: 'needle:poster',
26
26
  configureServer(server) {
27
- server.ws.on('needle:screenshot', async (data, client) => {
27
+ const hot = server.hot ?? server.ws;
28
+ hot.on('needle:screenshot', async (data, client) => {
28
29
  if (userSettings.noPoster) return;
29
30
  if (!data?.data) {
30
31
  console.warn("Received empty screenshot data, ignoring");
@@ -112,10 +112,15 @@ 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
+
115
120
  /** @param {import('vite').ViteDevServer} server @param {string} [file] */
116
121
  function notifyClientWillReload(server, file) {
117
122
  console.log("Send reload notification");
118
- server.ws.send('needle:reload', { type: 'will-reload', file: file });
123
+ getHot(server).send('needle:reload', { type: 'will-reload', file: file });
119
124
  }
120
125
 
121
126
  /**
@@ -236,7 +241,7 @@ async function scheduleReload(server, level = 0) {
236
241
  lastReloadTime = Date.now();
237
242
  const readableTime = new Date(lastReloadTime).toLocaleTimeString();
238
243
  console.log("< Reloading... " + readableTime)
239
- server.ws.send({
244
+ getHot(server).send({
240
245
  type: 'full-reload',
241
246
  path: '*'
242
247
  });
@@ -43,8 +43,12 @@ 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
47
- src = src.replaceAll(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');
48
52
  return {
49
53
  code: src,
50
54
  map: null
@@ -1,6 +1,16 @@
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
+
4
14
  export enum ApplicationEvents {
5
15
  Visible = "application-visible",
6
16
  Hidden = "application-hidden",
@@ -1,8 +1,4 @@
1
1
 
2
-
3
- export namespace NEEDLE_ENGINE_FEATURE_FLAGS {
4
-
5
- // eslint-disable-next-line prefer-const
6
- export let experimentalSmartHierarchyUpdate = false;
7
-
8
- }
2
+ export const NEEDLE_ENGINE_FEATURE_FLAGS = {
3
+ experimentalSmartHierarchyUpdate: false,
4
+ };
@@ -1,108 +1,46 @@
1
1
 
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> = [];
17
- /** Wait for the module to be loaded (doesn't trigger a load) */
18
- export function ready(): Promise<TYPE> {
19
- if (MODULE) return Promise.resolve(MODULE);
20
- return new Promise((resolve) => { callbacks.push(resolve); });
21
- };
22
- /** Load the 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));
29
- callbacks.length = 0;
30
- return module;
31
- }
32
-
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> = [];
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,
66
7
  /** 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
-
8
+ ready(): Promise<T> {
9
+ if (mod.MODULE) return Promise.resolve(mod.MODULE);
10
+ return new Promise(resolve => { callbacks.push(resolve); });
11
+ },
72
12
  /** 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));
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);
79
19
  callbacks.length = 0;
80
20
  return module;
81
21
  }
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
- };
22
+ };
23
+ return mod;
24
+ }
96
25
 
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
- }
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
+ };
@@ -38,6 +38,58 @@ 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
+
41
93
  // #region Observables
42
94
 
43
95
  /** Keep in sync with the overloads and docs here:
@@ -906,200 +958,18 @@ export class NeedleEngineWebComponent extends HTMLElement implements INeedleEngi
906
958
 
907
959
  // #region setAttribute
908
960
 
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
- */
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;
1001
964
  setAttribute(qualifiedName: string, value: string): void {
1002
- super.setAttribute(qualifiedName, value);
965
+ super.setAttribute(qualifiedName, typeof value === "string" ? value : String(value));
1003
966
  }
1004
967
 
1005
968
  // #region getAttribute
1006
969
 
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
-
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;
1103
973
  getAttribute(qualifiedName: string): string | null {
1104
974
  return super.getAttribute(qualifiedName);
1105
975
  }
@@ -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.env.VITE_NEEDLE_USE_POSTPROCESSING === "false") {
59
+ if ("env" in import.meta && (import.meta as any /* webpack support */ ).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();