@needle-tools/engine 5.1.0-canary.30cc545 → 5.1.0-canary.52c25a9

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 (48) hide show
  1. package/dist/{needle-engine.bundle-d_9mSxN4.js → needle-engine.bundle-CrgBME0J.js} +2853 -2847
  2. package/dist/{needle-engine.bundle-BXPPQRer.min.js → needle-engine.bundle-IDh1TTjW.min.js} +131 -131
  3. package/dist/{needle-engine.bundle-BMlLSACE.umd.cjs → needle-engine.bundle-Is0BeJVS.umd.cjs} +121 -121
  4. package/dist/needle-engine.d.ts +7 -7
  5. package/dist/needle-engine.js +2 -2
  6. package/dist/needle-engine.min.js +1 -1
  7. package/dist/needle-engine.umd.cjs +1 -1
  8. package/lib/engine/api.d.ts +1 -1
  9. package/lib/engine/engine_context.d.ts +1 -1
  10. package/lib/engine/engine_init.js +5 -0
  11. package/lib/engine/engine_init.js.map +1 -1
  12. package/lib/engine/engine_license.d.ts +2 -0
  13. package/lib/engine/engine_license.js +14 -6
  14. package/lib/engine/engine_license.js.map +1 -1
  15. package/lib/engine/engine_lifecycle_functions_internal.js +5 -0
  16. package/lib/engine/engine_lifecycle_functions_internal.js.map +1 -1
  17. package/lib/engine/engine_scenedata.d.ts +1 -1
  18. package/lib/engine/engine_ssr.d.ts +2 -0
  19. package/lib/engine/engine_ssr.js +2 -0
  20. package/lib/engine/engine_ssr.js.map +1 -1
  21. package/lib/needle-engine.js +1 -0
  22. package/lib/needle-engine.js.map +1 -1
  23. package/package.json +1 -1
  24. package/plugins/dts-generator/dts.codegen.js +2 -2
  25. package/plugins/dts-generator/dts.writer.js +1 -1
  26. package/plugins/dts-generator/index.js +1 -1
  27. package/plugins/types/needle-bindings.d.ts +9 -5
  28. package/plugins/vite/asap.js +1 -1
  29. package/plugins/vite/dependency-watcher.d.ts +2 -2
  30. package/plugins/vite/dependency-watcher.js +3 -4
  31. package/plugins/vite/drop.d.ts +2 -2
  32. package/plugins/vite/drop.js +3 -4
  33. package/plugins/vite/dts-generator.js +23 -6
  34. package/plugins/vite/index.d.ts +9 -3
  35. package/plugins/vite/index.js +23 -10
  36. package/plugins/vite/meta.js +4 -2
  37. package/plugins/vite/poster.d.ts +2 -2
  38. package/plugins/vite/poster.js +3 -5
  39. package/plugins/vite/reload.d.ts +2 -2
  40. package/plugins/vite/reload.js +4 -5
  41. package/src/engine/api.ts +1 -1
  42. package/src/engine/engine_context.ts +1 -1
  43. package/src/engine/engine_init.ts +4 -0
  44. package/src/engine/engine_license.ts +12 -10
  45. package/src/engine/engine_lifecycle_functions_internal.ts +7 -0
  46. package/src/engine/engine_scenedata.ts +1 -1
  47. package/src/engine/engine_ssr.ts +3 -0
  48. package/src/needle-engine.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"engine_ssr.js","sourceRoot":"","sources":["../../src/engine/engine_ssr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,8CAA8C;AAC9C,MAAM,CAAC,MAAM,eAAe,GACxB,OAAO,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAE;CAA2C,CAAC;AAEpG,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GACzB,OAAO,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAE;CAA4C,CAAC;AAEvG,+CAA+C;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAC1B,OAAO,aAAa,KAAK,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAE;CAA6C,CAAC;AAK1G,4BAA4B;AAC5B,oEAAoE;AACpE,0EAA0E;AAC1E,IAAI,OAAO,UAAU,CAAC,aAAa,KAAK,WAAW,EAAE,CAAC;IACjD,UAAkB,CAAC,aAAa,GAAG,MAAM,aAAa;QAC1C,IAAI,CAAS;QACb,gBAAgB,CAAU;QAC1B,MAAM,CAAS;QACf,KAAK,CAAS;QACvB,YAAY,IAAY,EAAE,IAAsE;YAC5F,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,gBAAgB,GAAG,IAAI,EAAE,gBAAgB,IAAI,KAAK,CAAC;YACxD,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC;QAClC,CAAC;KACJ,CAAC;AACN,CAAC;AACD,aAAa"}
1
+ {"version":3,"file":"engine_ssr.js","sourceRoot":"","sources":["../../src/engine/engine_ssr.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,yEAAyE;AACzE,MAAM,CAAC,MAAM,GAAG,GAAY,OAAO,MAAM,KAAK,WAAW,CAAC;AAE1D,8CAA8C;AAC9C,MAAM,CAAC,MAAM,eAAe,GACxB,OAAO,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAE;CAA2C,CAAC;AAEpG,8CAA8C;AAC9C,MAAM,CAAC,MAAM,gBAAgB,GACzB,OAAO,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAE;CAA4C,CAAC;AAEvG,+CAA+C;AAC/C,MAAM,CAAC,MAAM,iBAAiB,GAC1B,OAAO,aAAa,KAAK,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAE;CAA6C,CAAC;AAK1G,4BAA4B;AAC5B,oEAAoE;AACpE,0EAA0E;AAC1E,IAAI,OAAO,UAAU,CAAC,aAAa,KAAK,WAAW,EAAE,CAAC;IACjD,UAAkB,CAAC,aAAa,GAAG,MAAM,aAAa;QAC1C,IAAI,CAAS;QACb,gBAAgB,CAAU;QAC1B,MAAM,CAAS;QACf,KAAK,CAAS;QACvB,YAAY,IAAY,EAAE,IAAsE;YAC5F,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,gBAAgB,GAAG,IAAI,EAAE,gBAAgB,IAAI,KAAK,CAAC;YACxD,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC;YAChC,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,CAAC,CAAC;QAClC,CAAC;KACJ,CAAC;AACN,CAAC;AACD,aAAa"}
@@ -1,3 +1,4 @@
1
+ /// <reference path="../plugins/types/needle-bindings.d.ts" />
1
2
  import { initEngine } from "./engine/engine_init.js";
2
3
  initEngine();
3
4
  import "./engine/webcomponents/needle-engine.js";
@@ -1 +1 @@
1
- {"version":3,"file":"needle-engine.js","sourceRoot":"","sources":["../src/needle-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,UAAU,EAAE,CAAC;AACb,OAAO,yCAAyC,CAAC;AACjD,OAAO,0BAA0B,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yCAAyC,CAAC;AACxD,cAAc,yBAAyB,CAAC;AAExC,0CAA0C;AAC1C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/K,MAAM,MAAM,GAAG;IACX,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,eAAe,EAAE,eAAe;IAChC,MAAM,EAAE;QACJ,WAAW,EAAE,SAAS;KACzB;IACD,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,cAAc;IAC9B,aAAa,EAAE,aAAa;IAC5B,oBAAoB,EAAE,aAAa;IACnC,gBAAgB,EAAE,SAAS;IAC3B,cAAc,EAAE,OAAO;CACjB,CAAC;AAEX,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,sCAAsC,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACvF,CAAC;AACD,SAAS,cAAc,CAAC,GAAW;IAC/B,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;AACL,CAAC;AACD,OAAO,KAAK,SAAS,MAAM,kCAAkC,CAAC;AAC9D,cAAc,CAAC,SAAS,CAAC,CAAC;AAE1B,OAAO,KAAK,UAAU,MAAM,2CAA2C,CAAC;AACxE,cAAc,CAAC,UAAU,CAAC,CAAC;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1D,QAAQ,MAAM,EAAE,CAAC;QACb,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACP,SAAS;QACb;YACI,MAAM,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM;IACd,CAAC;AACL,CAAC;AAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;IACxB,UAAU,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;AAClC,CAAC;KACI,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACvB,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC;AAGD,wBAAwB;AACxB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACvB,UAAU,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;AAChC,CAAC;;IACI,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC"}
1
+ {"version":3,"file":"needle-engine.js","sourceRoot":"","sources":["../src/needle-engine.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,UAAU,EAAE,CAAC;AACb,OAAO,yCAAyC,CAAC;AACjD,OAAO,0BAA0B,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yCAAyC,CAAC;AACxD,cAAc,yBAAyB,CAAC;AAExC,0CAA0C;AAC1C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/K,MAAM,MAAM,GAAG;IACX,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,eAAe,EAAE,eAAe;IAChC,MAAM,EAAE;QACJ,WAAW,EAAE,SAAS;KACzB;IACD,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,OAAO;IAChB,QAAQ,EAAE,QAAQ;IAClB,cAAc,EAAE,cAAc;IAC9B,aAAa,EAAE,aAAa;IAC5B,oBAAoB,EAAE,aAAa;IACnC,gBAAgB,EAAE,SAAS;IAC3B,cAAc,EAAE,OAAO;CACjB,CAAC;AAEX,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,SAAS,EAAE,CAAC;IAC9C,OAAO,CAAC,IAAI,CAAC,sCAAsC,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AACvF,CAAC;AACD,SAAS,cAAc,CAAC,GAAW;IAC/B,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;AACL,CAAC;AACD,OAAO,KAAK,SAAS,MAAM,kCAAkC,CAAC;AAC9D,cAAc,CAAC,SAAS,CAAC,CAAC;AAE1B,OAAO,KAAK,UAAU,MAAM,2CAA2C,CAAC;AACxE,cAAc,CAAC,UAAU,CAAC,CAAC;AAE3B,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,mBAAmB,CAAC,UAAU,CAAC,EAAE,CAAC;IAC1D,QAAQ,MAAM,EAAE,CAAC;QACb,KAAK,WAAW,CAAC;QACjB,KAAK,aAAa,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,MAAM;YACP,SAAS;QACb;YACI,MAAM,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;YACpC,MAAM;IACd,CAAC;AACL,CAAC;AAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;IACxB,UAAU,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;AAClC,CAAC;KACI,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACvB,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;AACL,CAAC;AAGD,wBAAwB;AACxB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;IACvB,UAAU,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;AAChC,CAAC;;IACI,OAAO,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/engine",
3
- "version": "5.1.0-canary.30cc545",
3
+ "version": "5.1.0-canary.52c25a9",
4
4
  "description": "Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.",
5
5
  "main": "dist/needle-engine.min.js",
6
6
  "exports": {
@@ -43,8 +43,8 @@ export function generateDts(entries) {
43
43
  const lines = [
44
44
  `// Auto-generated by @needle-tools/engine — do not edit`,
45
45
  `// Regenerated on each vite dev-server start and GLB change.`,
46
- `// Augments the base "needle:bindings" declaration in @needle-tools/engine.`,
47
- `declare module "needle:bindings" {`,
46
+ `// Augments the base "needle-bindings" declaration in @needle-tools/engine.`,
47
+ `declare module "needle-bindings" {`,
48
48
  ` interface SceneData {`,
49
49
  ];
50
50
 
@@ -20,7 +20,7 @@ import { generateDts, generateHtmlCustomData } from './dts.codegen.js';
20
20
  * @param {string} opts.assetsDir Absolute path to assets directory
21
21
  * @param {string} opts.outputPath Absolute path to write needle-bindings.d.ts
22
22
  * @param {string} [opts.projectRoot] Project root — enables entrypoint GLB detection
23
- * @param {string} [opts.codegenDir] Codegen directory — used to find gen.js
23
+ * @param {string} [opts.codegenDir] Codegen directory — used to find gen.js and write needle-html-data.json
24
24
  * @returns {Promise<number | false>}
25
25
  */
26
26
  export async function generateBindingsDts({ assetsDir, outputPath, projectRoot, codegenDir }) {
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Typical generated output:
10
10
  *
11
- * declare module "needle:bindings" {
11
+ * declare module "needle-bindings" {
12
12
  * interface SceneData {
13
13
  * Sphere: {
14
14
  * MyBall: { speed: number; label: string; };
@@ -1,17 +1,21 @@
1
1
  /**
2
- * Ambient module declaration for `needle:bindings`.
2
+ * Ambient module declaration for `needle-bindings`.
3
3
  *
4
4
  * The `SceneData` interface is empty by default.
5
5
  * When the `needle:dts-generator` Vite plugin is active it writes
6
- * `src/generated/needle-bindings.d.ts` into the user's project, which
7
- * augments this interface with the actual component bindings extracted
8
- * from the project's GLB files at build time.
6
+ * `.needle/needle-bindings.gen.d.ts` next to the installed package,
7
+ * which augments this interface with the actual component bindings
8
+ * extracted from the project's GLB files at build time.
9
9
  *
10
10
  * @example
11
11
  * import type { SceneData } from "@needle-tools/engine";
12
12
  * type MyBallData = SceneData["RedBall"]["MyBall"];
13
13
  */
14
- declare module "needle:bindings" {
14
+
15
+ // Pull in the project-local generated augmentation (written by needle:dts-generator).
16
+ /// <reference path="../../.needle/generated/needle-bindings.gen.d.ts" />
17
+
18
+ declare module "needle-bindings" {
15
19
  interface SceneData {
16
20
  /** Fallback for nodes not present in the generated bindings — no type info, but no crash. */
17
21
  [nodeName: string]: Record<string, unknown> | undefined;
@@ -22,7 +22,7 @@ export async function needleAsap(command, config, userSettings) {
22
22
 
23
23
  fixMainTs();
24
24
 
25
- if (command != "build") {
25
+ if (command === "serve") {
26
26
  return null;
27
27
  }
28
28
 
@@ -1,10 +1,10 @@
1
1
  /**
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {unknown} _config
4
4
  * @param {import('../types').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | null}
6
6
  */
7
- export function needleDependencyWatcher(command: "build" | "serve", _config: unknown, userSettings: import("../types").userSettings): import("vite").Plugin | null;
7
+ export function needleDependencyWatcher(_command: "build" | "serve" | undefined, _config: unknown, userSettings: import("../types").userSettings): import("vite").Plugin | null;
8
8
  export type PackageJson = {
9
9
  dependencies?: Record<string, string>;
10
10
  devDependencies?: Record<string, string>;
@@ -12,14 +12,12 @@ function log(...msg) {
12
12
  }
13
13
 
14
14
  /**
15
- * @param {"build" | "serve"} command
15
+ * @param {"build" | "serve" | undefined} _command
16
16
  * @param {unknown} _config
17
17
  * @param {import('../types').userSettings} userSettings
18
18
  * @returns {import('vite').Plugin | null}
19
19
  */
20
- export function needleDependencyWatcher(command, _config, userSettings) {
21
- if (command === "build") return null;
22
-
20
+ export function needleDependencyWatcher(_command, _config, userSettings) {
23
21
  if (userSettings?.noDependencyWatcher === true) return null;
24
22
 
25
23
  const dir = process.cwd();
@@ -28,6 +26,7 @@ export function needleDependencyWatcher(command, _config, userSettings) {
28
26
 
29
27
  return /** @type {import('vite').Plugin} */ ({
30
28
  name: 'needle-dependency-watcher',
29
+ apply: 'serve',
31
30
  /** @param {import('vite').ViteDevServer} server */
32
31
  configureServer(server) {
33
32
  manageClients(server);
@@ -1,7 +1,7 @@
1
1
  /** Experimental, allow dropping files from Unity into the running scene.
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
4
4
  * @param {import('../types/userconfig.js').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | null | undefined}
6
6
  */
7
- export function needleDrop(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types/userconfig.js").userSettings): import("vite").Plugin | null | undefined;
7
+ export function needleDrop(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types/userconfig.js").userSettings): import("vite").Plugin | null | undefined;
@@ -7,18 +7,17 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
9
  /** Experimental, allow dropping files from Unity into the running scene.
10
- * @param {"build" | "serve"} command
10
+ * @param {"build" | "serve" | undefined} _command
11
11
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
12
12
  * @param {import('../types/userconfig.js').userSettings} userSettings
13
13
  * @returns {import('vite').Plugin | null | undefined}
14
14
  */
15
- export function needleDrop(command, config, userSettings) {
16
- if (command === "build") return;
17
-
15
+ export function needleDrop(_command, config, userSettings) {
18
16
  if(userSettings.useDrop !== true) return null;
19
17
 
20
18
  return {
21
19
  name: "needle:drop",
20
+ apply: 'serve',
22
21
  config(/** @type {{ server?: { hmr?: { port?: number } } }} */ viteConfig) {
23
22
  if(userSettings)
24
23
  if (!viteConfig.server) viteConfig.server = {};
@@ -16,12 +16,24 @@
16
16
  * needleDtsGenerator(command, needleConfig, userSettings)
17
17
  */
18
18
 
19
- import { join, resolve } from 'path';
20
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
19
+ import { join, resolve, dirname } from 'path';
20
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, realpathSync } from 'fs';
21
21
  import { tryLoadProjectConfig } from './config.js';
22
22
  import { generateBindingsDts } from '../dts-generator/index.js';
23
23
  import { needleLog } from './logging.js';
24
24
 
25
+ // Two dirs up from plugins/vite/ → package root.
26
+ // Use fileURLToPath so %7E and other URL-encoded characters in the path are decoded correctly.
27
+ // realpathSync follows symlinks so the path is stable even in npm link / monorepo setups.
28
+ import { fileURLToPath } from 'url';
29
+ let _packageRoot = /** @type {string | null} */ (null);
30
+ try {
31
+ _packageRoot = realpathSync(join(dirname(fileURLToPath(import.meta.url)), '..', '..'));
32
+ } catch (_e) {
33
+ // If we can't resolve the package root (e.g. unusual install layout), the plugin
34
+ // will silently skip generation rather than crashing the dev server.
35
+ }
36
+
25
37
  /**
26
38
  * Ensure `.vscode/settings.json` references the generated `needle-html-data.json`
27
39
  * so VS Code provides `data-bind-needle` completions in HTML files automatically.
@@ -73,7 +85,11 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
73
85
  }
74
86
 
75
87
  function resolveOutputPath() {
76
- return join(resolveCodegenDir(), "needle-bindings.d.ts");
88
+ // Write to a .needle dotfolder at the package root.
89
+ // Not in the `files` allowlist → never npm-published.
90
+ // ../../.needle/ from plugins/types/ resolves correctly for both
91
+ // symlinked (js/package~/) and published (node_modules/@needle-tools/engine/) layouts.
92
+ return join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-bindings.gen.d.ts");
77
93
  }
78
94
 
79
95
  function resolveAssetsDir() {
@@ -88,12 +104,13 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
88
104
 
89
105
  async function run() {
90
106
  try {
107
+ if (!_packageRoot) return;
91
108
  const assetsDir = resolveAssetsDir();
92
109
  const outputPath = resolveOutputPath();
93
110
  const codegenDir = resolveCodegenDir();
94
111
  const count = await generateBindingsDts({ assetsDir, outputPath, projectRoot, codegenDir });
95
- // Always register HTML custom data — the file is written on every run
96
- const htmlDataPath = join(codegenDir, "needle-html-data.json");
112
+ // HTML custom data sits next to the generated dts in .needle/generated/
113
+ const htmlDataPath = join(/** @type {string} */ (_packageRoot), ".needle", "generated", "needle-html-data.json");
97
114
  ensureVscodeHtmlCustomData(projectRoot, htmlDataPath);
98
115
  if (count !== false) {
99
116
  needleLog("needle:dts-generator", `${count} binding(s) → ${outputPath.replace(process.cwd(), ".")}`);
@@ -102,7 +119,7 @@ export function needleDtsGenerator(_command, _config, _userSettings) {
102
119
  hot.send({ type: "full-reload", path: "*" });
103
120
  }
104
121
  } else {
105
- needleLog("needle:dts-generator", `up-to-date`);
122
+ needleLog("needle:dts-generator", `up-to-date → ${outputPath.replace(process.cwd(), ".")}`);
106
123
  }
107
124
  } catch (err) {
108
125
  needleLog("needle:dts-generator", "Failed: " + (/** @type {any} */ (err)?.message ?? err));
@@ -19,12 +19,18 @@
19
19
  * ],
20
20
  * }
21
21
  * ```
22
- * @param {"build" | "serve"} command
23
- * @param {import('../types/needleConfig').needleMeta | null | undefined} config
22
+ * When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
23
+ * the command is resolved automatically from Vite's `configResolved` hook.
24
+ * ```js
25
+ * // SvelteKit — no command needed:
26
+ * export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
27
+ * ```
28
+ * @param {"build" | "serve" | undefined} [command]
29
+ * @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
24
30
  * @param {import('../types/index.js').userSettings} [userSettings]
25
31
  * @returns {Promise<import('vite').Plugin[]>}
26
32
  */
27
- export function needlePlugins(command: "build" | "serve", config?: import("../types/needleConfig").needleMeta | null | undefined, userSettings?: import("../types/index.js").userSettings): Promise<import("vite").Plugin[]>;
33
+ export function needlePlugins(command?: "build" | "serve" | undefined, config?: import("../types/needleConfig").needleMeta | null | undefined, userSettings?: import("../types/index.js").userSettings): Promise<import("vite").Plugin[]>;
28
34
  export { needleAI } from "./ai.js";
29
35
  export { needleDtsGenerator } from "./dts-generator.js";
30
36
  export { needleAsap } from "./asap.js";
@@ -116,12 +116,18 @@ const defaultUserSettings = {
116
116
  * ],
117
117
  * }
118
118
  * ```
119
- * @param {"build" | "serve"} command
120
- * @param {import('../types/needleConfig').needleMeta | null | undefined} config
119
+ * When used without arguments (e.g. in a SvelteKit `defineConfig({})` plain object),
120
+ * the command is resolved automatically from Vite's `configResolved` hook.
121
+ * ```js
122
+ * // SvelteKit — no command needed:
123
+ * export default defineConfig({ plugins: [sveltekit(), needlePlugins()] });
124
+ * ```
125
+ * @param {"build" | "serve" | undefined} [command]
126
+ * @param {import('../types/needleConfig').needleMeta | null | undefined} [config]
121
127
  * @param {import('../types/index.js').userSettings} [userSettings]
122
128
  * @returns {Promise<import('vite').Plugin[]>}
123
129
  */
124
- export async function needlePlugins(command, config = undefined, userSettings = {}) {
130
+ export async function needlePlugins(command = undefined, config = undefined, userSettings = {}) {
125
131
 
126
132
  if (!config) config = {}
127
133
 
@@ -168,14 +174,21 @@ export async function needlePlugins(command, config = undefined, userSettings =
168
174
  array.push(await editorConnection(command, config, userSettings, array));
169
175
  array.push(needleDependencyWatcher(command, config, userSettings));
170
176
 
171
- // Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive
172
- if (command === "serve") {
177
+ // Ensure the process exits on SIGINT (Ctrl+C) since plugin timers/sockets can keep the event loop alive.
178
+ // If command is unknown at call time (e.g. SvelteKit plain defineConfig), defer to configResolved.
179
+ const registerSigint = () => {
173
180
  process.on('SIGINT', () => {
174
- // Wait a moment to allow plugins to clean up if needed, then exit
175
- setTimeout(() => {
176
- console.debug('\nGoodbye!');
177
- process.exit();
178
- }, 1000);
181
+ setTimeout(() => { console.debug('\nGoodbye!'); process.exit(); }, 1000);
182
+ });
183
+ };
184
+ if (command === "serve") {
185
+ registerSigint();
186
+ } else if (command === undefined) {
187
+ array.push({
188
+ name: "needle:sigint",
189
+ configResolved(config) {
190
+ if (config.command === "serve") registerSigint();
191
+ }
179
192
  });
180
193
  }
181
194
 
@@ -13,8 +13,7 @@ import { needleGreenBold, needleLog } from './logging.js';
13
13
  */
14
14
  export function needleMeta(command, config, userSettings) {
15
15
 
16
- // we can check if this is a build
17
- const isBuild = command === 'build';
16
+ let isBuild = command === 'build';
18
17
 
19
18
  async function updateConfig() {
20
19
  config = await loadConfig();
@@ -25,6 +24,9 @@ export function needleMeta(command, config, userSettings) {
25
24
  return {
26
25
  // replace meta tags
27
26
  name: 'needle:meta',
27
+ configResolved(resolvedConfig) {
28
+ isBuild = resolvedConfig.command === 'build';
29
+ },
28
30
  transformIndexHtml: {
29
31
  order: 'pre',
30
32
  handler(/** @type {string} */ html, /** @type {unknown} */ _ctx) {
@@ -1,8 +1,8 @@
1
1
  export function getPosterPath(): string;
2
2
  /**
3
- * @param {"build" | "serve"} command
3
+ * @param {"build" | "serve" | undefined} _command
4
4
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
5
5
  * @param {import('../types').userSettings} userSettings
6
6
  * @returns {import('vite').Plugin | undefined}
7
7
  */
8
- export function needlePoster(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
8
+ export function needlePoster(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null | undefined, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
@@ -10,19 +10,17 @@ export function getPosterPath() {
10
10
  }
11
11
 
12
12
  /**
13
- * @param {"build" | "serve"} command
13
+ * @param {"build" | "serve" | undefined} _command
14
14
  * @param {import('../types/needleConfig').needleMeta | null | undefined} config
15
15
  * @param {import('../types').userSettings} userSettings
16
16
  * @returns {import('vite').Plugin | undefined}
17
17
  */
18
- export function needlePoster(command, config, userSettings) {
19
- // only relevant for local development
20
- if (command === 'build') return [];
21
-
18
+ export function needlePoster(_command, config, userSettings) {
22
19
  if (userSettings.noPoster) return;
23
20
 
24
21
  return {
25
22
  name: 'needle:poster',
23
+ apply: 'serve',
26
24
  configureServer(server) {
27
25
  const hot = server.hot ?? server.ws;
28
26
  hot.on('needle:screenshot', async (data, client) => {
@@ -1,7 +1,7 @@
1
1
  /**
2
- * @param {"build" | "serve"} command
2
+ * @param {"build" | "serve" | undefined} _command
3
3
  * @param {import('../types/needleConfig').needleMeta | null} config
4
4
  * @param {import('../types').userSettings} userSettings
5
5
  * @returns {import('vite').Plugin | undefined}
6
6
  */
7
- export function needleReload(command: "build" | "serve", config: import("../types/needleConfig").needleMeta | null, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
7
+ export function needleReload(_command: "build" | "serve" | undefined, config: import("../types/needleConfig").needleMeta | null, userSettings: import("../types").userSettings): import("vite").Plugin | undefined;
@@ -15,14 +15,12 @@ const filesUsingHotReload = new Set();
15
15
  let assetsDirectory = "";
16
16
 
17
17
  /**
18
- * @param {"build" | "serve"} command
18
+ * @param {"build" | "serve" | undefined} _command
19
19
  * @param {import('../types/needleConfig').needleMeta | null} config
20
20
  * @param {import('../types').userSettings} userSettings
21
21
  * @returns {import('vite').Plugin | undefined}
22
22
  */
23
- export function needleReload(command, config, userSettings) {
24
- if (command === "build") return undefined;
25
-
23
+ export function needleReload(_command, config, userSettings) {
26
24
  if (userSettings?.noReload === true) return undefined;
27
25
 
28
26
 
@@ -51,6 +49,7 @@ export function needleReload(command, config, userSettings) {
51
49
 
52
50
  return {
53
51
  name: 'needle:reload',
52
+ apply: 'serve',
54
53
  /** @param {import('vite').UserConfig} config */
55
54
  config(config) {
56
55
  if (!config.server) config.server = { watch: { ignored: [] } };
@@ -174,7 +173,7 @@ async function handleReload({ file, server, modules: _modules, read, buildDirect
174
173
  // meaning if its the first export after the server starts those will not trigger a reload
175
174
  // Ignore d.ts
176
175
  const shouldCheckIfContentChanged = file.includes("/codegen/") || file.includes("/generated/") || file.endsWith("gen.js");// || file.endsWith(".glb") || file.endsWith(".gltf") || file.endsWith(".bin");
177
- if (shouldCheckIfContentChanged && !file.endsWith(".d.ts") && !file.endsWith("needle-html-data.json")) {
176
+ if (!file.includes("/.svelte-kit/") && !file.endsWith(".d.ts") && !file.endsWith("needle-html-data.json") && shouldCheckIfContentChanged) {
178
177
  if (reloadIsScheduled) {
179
178
  return [];
180
179
  }
package/src/engine/api.ts CHANGED
@@ -450,4 +450,4 @@ export * from "./xr/api.js"
450
450
  * import type { SceneData } from "@needle-tools/engine";
451
451
  * type OrbitSettings = SceneData["Camera"]["OrbitControls"];
452
452
  */
453
- export type { SceneData } from "needle:bindings";
453
+ export type { SceneData } from "needle-bindings";
@@ -38,7 +38,7 @@ import { Physics } from './engine_physics.js';
38
38
  import { PlayerViewManager } from './engine_playerview.js';
39
39
  import { RendererData as SceneLighting } from './engine_scenelighting.js';
40
40
  import { getSceneData } from './engine_scenedata.js';
41
- import type { SceneData } from 'needle:bindings';
41
+ import type { SceneData } from 'needle-bindings';
42
42
  import { getTempColor, logHierarchy } from './engine_three_utils.js';
43
43
  import { Time } from './engine_time.js';
44
44
  import { patchTonemapping } from './engine_tonemapping.js';
@@ -11,6 +11,8 @@ import { initCameraExtensions } from "./js-extensions/Camera.js";
11
11
  import { patchLayers } from "./js-extensions/Layers.js";
12
12
  import { initObject3DExtensions } from "./js-extensions/Object3D.js";
13
13
  import { initVectorExtensions } from "./js-extensions/Vector.js";
14
+ import { SSR } from "./engine_ssr.js";
15
+ import { initLicense } from "./engine_license.js";
14
16
  import { initWebComponents } from "./webcomponents/init.js";
15
17
  import { initPhysics } from "./engine_physics_rapier.js";
16
18
  import { initXR } from "./xr/init.js";
@@ -28,6 +30,7 @@ let initialized = false;
28
30
  */
29
31
  export function initEngine() {
30
32
  if (initialized) return;
33
+ if (SSR) return;
31
34
  initialized = true;
32
35
 
33
36
  initWebComponents();
@@ -46,4 +49,5 @@ export function initEngine() {
46
49
  initSceneSwitcherAttributes();
47
50
  initPhysics();
48
51
  initXR();
52
+ initLicense();
49
53
  }
@@ -1,6 +1,3 @@
1
- import { dof } from "three/src/nodes/TSL.js";
2
-
3
- import { isDevEnvironment } from "./debug/index.js";
4
1
  import { BUILD_TIME, GENERATOR, PUBLIC_KEY, VERSION } from "./engine_constants.js";
5
2
  import { ContextEvent, ContextRegistry } from "./engine_context_registry.js";
6
3
  import { onInitialized } from "./engine_lifecycle_api.js";
@@ -8,7 +5,7 @@ import { isLocalNetwork } from "./engine_networking_utils.js";
8
5
  import { Context } from "./engine_setup.js";
9
6
  import type { IContext } from "./engine_types.js";
10
7
  import { getParam } from "./engine_utils.js";
11
- import { InternalAttributeUtils } from "./engine_utils_attributes.js";
8
+ import { SSR } from "./engine_ssr.js";
12
9
 
13
10
  const debug = getParam("debuglicense");
14
11
 
@@ -90,7 +87,9 @@ export namespace Telemetry {
90
87
  });
91
88
  }
92
89
 
93
- onInitialized((ctx => sendPageViewEvent(ctx)), { once: true });
90
+ export function init() {
91
+ if(!SSR) onInitialized((ctx => sendPageViewEvent(ctx)), { once: true });
92
+ }
94
93
 
95
94
  function sendPageViewEvent(ctx: IContext): Promise<void> | void {
96
95
  if (!isAllowed(ctx)) {
@@ -243,11 +242,14 @@ export namespace Telemetry {
243
242
  }
244
243
 
245
244
 
246
- ContextRegistry.registerCallback(ContextEvent.ContextRegistered, evt => {
247
- showLicenseInfo(evt.context);
248
- handleForbidden(evt.context);
249
- setTimeout(() => sendUsageMessageToAnalyticsBackend(evt.context), 2000);
250
- });
245
+ export function initLicense() {
246
+ Telemetry.init();
247
+ ContextRegistry.registerCallback(ContextEvent.ContextRegistered, evt => {
248
+ showLicenseInfo(evt.context);
249
+ handleForbidden(evt.context);
250
+ setTimeout(() => sendUsageMessageToAnalyticsBackend(evt.context), 2000);
251
+ });
252
+ }
251
253
 
252
254
  export let runtimeLicenseCheckPromise: Promise<void> | undefined = undefined;
253
255
  let applicationIsForbidden = false;
@@ -1,5 +1,6 @@
1
1
  import { type Context, FrameEvent } from "./engine_context.js";
2
2
  import { ContextEvent } from "./engine_context_registry.js";
3
+ import { SSR } from "./engine_ssr.js";
3
4
 
4
5
  export declare type Event = ContextEvent | FrameEvent;
5
6
 
@@ -38,6 +39,12 @@ let methodsWarningCounter = 0;
38
39
  * @param evt the event to call the function at
39
40
  */
40
41
  export function registerFrameEventCallback(cb: LifecycleMethod, evt: Event, opts?: LifecycleMethodOptions) {
42
+
43
+ // Don't register the callback if we are in SSR, because it will never be called and might cause memory leaks
44
+ if(SSR) {
45
+ return;
46
+ }
47
+
41
48
  if (!newMethods.has(evt)) {
42
49
  newMethods.set(evt, new Array());
43
50
  }
@@ -1,4 +1,4 @@
1
- import type { SceneData } from "needle:bindings";
1
+ import type { SceneData } from "needle-bindings";
2
2
  import type { IContext } from "./engine_types.js";
3
3
  import { getComponent } from "./engine_components.js";
4
4
  import { TypeStore } from "./engine_typestore.js";
@@ -10,6 +10,9 @@
10
10
  */
11
11
 
12
12
 
13
+ /** True when running in an SSR/Node environment (no browser globals). */
14
+ export const SSR: boolean = typeof window === "undefined";
15
+
13
16
  /** SSR-safe base class for web components. */
14
17
  export const HTMLElementBase: typeof HTMLElement =
15
18
  typeof HTMLElement !== "undefined" ? HTMLElement : (class { } as unknown as typeof HTMLElement);
@@ -1,3 +1,5 @@
1
+ /// <reference path="../plugins/types/needle-bindings.d.ts" />
2
+
1
3
  import { initEngine } from "./engine/engine_init.js";
2
4
  initEngine();
3
5
  import "./engine/webcomponents/needle-engine.js";