@kite3d/engine 0.16.0 → 0.18.0

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.
@@ -1,4 +1,5 @@
1
1
  import { ComponentDefn, IObject3D, Object3DComponent, ThreeViewer } from 'threepipe';
2
+ import { GeneratorParamDefinition, GeneratorParamSchema } from '../generatorParams.ts';
2
3
  export interface GeneratorParams {
3
4
  [key: string]: unknown;
4
5
  }
@@ -10,6 +11,7 @@ export interface GeneratorContext {
10
11
  }
11
12
  export interface GeneratorModule {
12
13
  default?: (context: GeneratorContext) => unknown | Promise<unknown>;
14
+ params?: Record<string, GeneratorParamDefinition>;
13
15
  }
14
16
  export interface GeneratorViewerOptions {
15
17
  base: string | URL;
@@ -20,6 +22,7 @@ export declare class GeneratorComponent extends Object3DComponent {
20
22
  static StateProperties: ComponentDefn['StateProperties'];
21
23
  module: string;
22
24
  params: GeneratorParams;
25
+ schema: GeneratorParamSchema;
23
26
  private runRevision;
24
27
  static configureViewer(viewer: ThreeViewer, options: GeneratorViewerOptions): void;
25
28
  static waitForViewer(viewer: ThreeViewer): Promise<void>;
@@ -33,8 +36,9 @@ export interface RunGeneratorOptions extends Omit<GeneratorContext, 'engine'> {
33
36
  base: URL;
34
37
  revision?: number;
35
38
  isCurrent?: () => boolean;
39
+ onSchema?: (schema: GeneratorParamSchema) => void;
36
40
  }
37
- export declare function runGenerator({ node, params, viewer, module, base, revision, isCurrent, }: RunGeneratorOptions): Promise<IObject3D[]>;
41
+ export declare function runGenerator({ node, params, viewer, module, base, revision, isCurrent, onSchema, }: RunGeneratorOptions): Promise<IObject3D[]>;
38
42
  export declare function removeGeneratedChildren(node: IObject3D): void;
39
43
  export declare function markGenerated(object: IObject3D, sourceId?: string, outputIndex?: number): void;
40
44
  export declare function resolveGeneratorModule(module: string, base: URL): URL;
@@ -1,11 +1,26 @@
1
- import { parse as w } from "jsonc-parser";
2
- const b = "kite3d", S = `/${b}/`;
3
- function v(t, e) {
1
+ import { parse as j } from "jsonc-parser";
2
+ const S = "kite3d", y = `/${S}/`;
3
+ function O(t, e) {
4
+ const n = `${y}@`;
5
+ return (o) => {
6
+ var c;
7
+ if (o.startsWith(n)) {
8
+ const p = new URL(o, "https://kite3d.invalid"), a = decodeURIComponent(p.pathname.slice(n.length)), r = a.indexOf("/"), d = r < 0 ? a : a.slice(0, r), f = r < 0 ? "" : a.slice(r + 1), s = e.files[d];
9
+ if (!(s != null && s.path)) throw new Error(`Unknown asset id in URL: ${d}`);
10
+ const i = (c = s.files) == null ? void 0 : c[f];
11
+ if (i) return new URL(i, t).href;
12
+ if (s.files) throw new Error(`Unknown file for asset ${d}: ${f}`);
13
+ return /^f\.[^/]+$/i.test(f) ? new URL(s.path, t).href : new URL(f, new URL(s.path, t)).href;
14
+ }
15
+ return o.startsWith(y) ? new URL(o.slice(y.length), t).href : o;
16
+ };
17
+ }
18
+ function b(t, e) {
4
19
  const n = e.dependencies;
5
- return g(n) && Object.prototype.hasOwnProperty.call(n, t);
20
+ return h(n) && Object.prototype.hasOwnProperty.call(n, t);
6
21
  }
7
- function O(t) {
8
- const e = w(t);
22
+ function x(t) {
23
+ const e = j(t);
9
24
  if (!e || typeof e != "object" || Array.isArray(e))
10
25
  throw new Error("Invalid package.json file: expected an object");
11
26
  const n = e;
@@ -13,96 +28,98 @@ function O(t) {
13
28
  throw new Error("package.json mainScene must name a text .gltf file");
14
29
  return n;
15
30
  }
16
- function x(t) {
17
- const e = w(t);
31
+ function U(t) {
32
+ const e = j(t);
18
33
  if (e.files && typeof e.files != "object")
19
34
  throw new Error("Invalid assets.json file: files should be an object");
20
35
  if (e.version !== void 0 && typeof e.version != "number")
21
36
  throw new Error("Invalid assets.json file: version should be a number");
22
37
  return e.files || (e.files = {}), e.version || (e.version = 1), e;
23
38
  }
24
- function N(t, e) {
39
+ function k(t, e) {
25
40
  const n = JSON.parse(e);
26
41
  if (!n || typeof n != "object" || !n.asset)
27
42
  throw new Error(`${t} is not a JSON glTF document`);
28
43
  }
29
- function k(t) {
44
+ function P(t) {
30
45
  var e;
31
46
  try {
32
- const n = JSON.parse(t), i = [];
33
- for (const [c, a] of (n.nodes || []).entries())
34
- for (const [p, o] of Object.entries(((e = a.extras) == null ? void 0 : e.EntityComponentPlugin) || {}))
35
- o.type !== "Generator" || !g(o.state) || i.push({
36
- componentId: p,
37
- module: typeof o.state.module == "string" ? o.state.module : "",
47
+ const n = JSON.parse(t), o = [];
48
+ for (const [c, p] of (n.nodes || []).entries())
49
+ for (const [a, r] of Object.entries(((e = p.extras) == null ? void 0 : e.EntityComponentPlugin) || {}))
50
+ r.type !== "Generator" || !h(r.state) || o.push({
51
+ componentId: a,
52
+ module: typeof r.state.module == "string" ? r.state.module : "",
38
53
  nodeIndex: c,
39
- nodeName: typeof a.name == "string" ? a.name : `Node ${c}`,
40
- params: g(o.state.params) ? o.state.params : {}
54
+ nodeName: typeof p.name == "string" ? p.name : `Node ${c}`,
55
+ params: h(r.state.params) ? r.state.params : {},
56
+ schema: {}
41
57
  });
42
- return i;
58
+ return o;
43
59
  } catch {
44
60
  return [];
45
61
  }
46
62
  }
47
- function A(t, e, n) {
48
- var a, p, o, f, d;
49
- const i = JSON.parse(t), c = (d = (f = (o = (p = (a = i.nodes) == null ? void 0 : a[e.nodeIndex]) == null ? void 0 : p.extras) == null ? void 0 : o.EntityComponentPlugin) == null ? void 0 : f[e.componentId]) == null ? void 0 : d.state;
50
- if (!g(c)) throw new Error(`Generator component is missing on ${e.nodeName}`);
51
- return Object.assign(c, n), { text: JSON.stringify(i, null, 2), state: c };
63
+ function E(t, e, n) {
64
+ var p, a, r, d, f;
65
+ const o = JSON.parse(t), c = (f = (d = (r = (a = (p = o.nodes) == null ? void 0 : p[e.nodeIndex]) == null ? void 0 : a.extras) == null ? void 0 : r.EntityComponentPlugin) == null ? void 0 : d[e.componentId]) == null ? void 0 : f.state;
66
+ if (!h(c)) throw new Error(`Generator component is missing on ${e.nodeName}`);
67
+ return Object.assign(c, n), { text: JSON.stringify(o, null, 2), state: c };
52
68
  }
53
- async function E(t, e) {
54
- var f, d;
55
- const n = t[b] ?? {}, i = [], a = {
69
+ async function N(t, e) {
70
+ var d, f;
71
+ const n = t[S] ?? {}, o = [], p = {
56
72
  ...t.dependencies && typeof t.dependencies == "object" && !Array.isArray(t.dependencies) ? t.dependencies : {}
57
73
  };
58
- i.push(...Object.entries(a).map(([s, r]) => ({ key: s, version: r }))), n.imports && i.push(...Object.entries(n.imports).map(([s, r]) => ({
74
+ o.push(...Object.entries(p).map(([s, i]) => ({ key: s, version: i }))), n.imports && o.push(...Object.entries(n.imports).map(([s, i]) => ({
59
75
  key: s,
60
- url: r.startsWith("@") ? void 0 : r,
61
- version: r.startsWith("@") ? r.slice(1) : ""
76
+ url: i.startsWith("@") ? void 0 : i,
77
+ version: i.startsWith("@") ? i.slice(1) : ""
62
78
  })));
63
- const p = ((f = n.plugins) == null ? void 0 : f.map((s) => {
79
+ const a = ((d = n.plugins) == null ? void 0 : d.map((s) => {
64
80
  if (typeof s != "string") return s;
65
- const r = s.match(/\((.*)\)$/);
66
- let y, l = s;
67
- if (r) {
68
- const h = r[1].trim();
69
- if (l = s.slice(0, r.index).trim(), h)
81
+ const i = s.match(/\((.*)\)$/);
82
+ let g, l = s;
83
+ if (i) {
84
+ const w = i[1].trim();
85
+ if (l = s.slice(0, i.index).trim(), w)
70
86
  try {
71
87
  const m = [];
72
- if (y = w(`[${h}]`, m), !Array.isArray(y) || m.length)
88
+ if (g = j(`[${w}]`, m), !Array.isArray(g) || m.length)
73
89
  throw console.error(m), new Error("Plugin params is not a valid array");
74
90
  } catch (m) {
75
- return console.error("Unable to parse plugin params, skipping plugin", s, h, m), null;
91
+ return console.error("Unable to parse plugin params, skipping plugin", s, w, m), null;
76
92
  }
77
93
  }
78
94
  const u = l.lastIndexOf(":");
79
95
  return {
80
96
  import: u !== -1 ? l.slice(0, u) : l,
81
97
  className: u !== -1 ? l.slice(u + 1) : void 0,
82
- params: y
98
+ params: g
83
99
  };
84
- })) || [], o = ((d = n.scripts) == null ? void 0 : d.map(
100
+ })) || [], r = ((f = n.scripts) == null ? void 0 : f.map(
85
101
  (s) => typeof s == "string" ? { import: s } : s
86
102
  )) || [];
87
103
  return {
88
- plugins: p.filter(Boolean),
89
- scripts: o,
90
- dependencies: i,
104
+ plugins: a.filter(Boolean),
105
+ scripts: r,
106
+ dependencies: o,
91
107
  viewer: n.viewer || {}
92
108
  };
93
109
  }
94
- function g(t) {
110
+ function h(t) {
95
111
  return !!t && typeof t == "object" && !Array.isArray(t);
96
112
  }
97
113
  export {
98
- S as assetUrlPrefix,
99
- v as isDependencyModuleSpecifier,
100
- x as parseAssetsJSONManifest,
101
- O as parsePackageJSON,
102
- E as parsePackageJsonSettingsConfig,
103
- k as readProjectGeneratorStates,
104
- b as settingsKey,
105
- A as updateProjectGeneratorState,
106
- N as validateSceneSource
114
+ y as assetUrlPrefix,
115
+ O as createProjectAssetURLModifier,
116
+ b as isDependencyModuleSpecifier,
117
+ U as parseAssetsJSONManifest,
118
+ x as parsePackageJSON,
119
+ N as parsePackageJsonSettingsConfig,
120
+ P as readProjectGeneratorStates,
121
+ S as settingsKey,
122
+ E as updateProjectGeneratorState,
123
+ k as validateSceneSource
107
124
  };
108
125
  //# sourceMappingURL=projectFormat.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"projectFormat.js","sources":["../src/runtime/projectFormat.ts"],"sourcesContent":["import {parse, ParseError} from 'jsonc-parser'\n\nexport const settingsKey = 'kite3d'\nexport const assetUrlPrefix = `/${settingsKey}/`\n\nexport type JSONValue = string | number | boolean | null | JSONValue[] | {[key: string]: JSONValue}\nexport type ProjectPackageJSON = Record<string, JSONValue> & {mainScene: string}\n\nexport interface ProjectGeneratorState {\n componentId: string\n module: string\n nodeIndex: number\n nodeName: string\n params: Record<string, unknown>\n}\n\nexport interface AssetsJSONManifest {\n files: Record<string, {\n path: string\n }>\n version: number\n}\n\nexport interface ProjectDependency {\n key: string\n version: string\n url?: string\n}\n\nexport interface ExternalPlugin {\n import: string\n /** @default `default` */\n className?: string\n /** @default true */\n active?: boolean\n /** Constructor parameters. */\n params?: JSONValue[]\n}\n\nexport interface ExternalScript {\n import: string\n /** @default true */\n active?: boolean\n}\n\nexport interface ProjectViewerSettings {\n msaa?: boolean\n rgbm?: boolean\n zPrepass?: boolean\n renderScale?: number | 'auto'\n maxRenderScale?: number\n backgroundColor?: string | number | null\n modelRootScale?: number\n stencil?: boolean\n debug?: boolean\n tonemap?: boolean\n camera?: {\n type?: 'perspective' | 'orthographic'\n controlsMode?: string\n position?: [number, number, number]\n target?: [number, number, number]\n }\n maxHDRIntensity?: number\n powerPreference?: 'default' | 'high-performance' | 'low-power'\n}\n\nexport interface ProjectConfigSettings {\n plugins: ExternalPlugin[]\n scripts: ExternalScript[]\n dependencies: ProjectDependency[]\n viewer: ProjectViewerSettings\n}\n\nexport interface ProjectConfigSettingsJSON {\n plugins?: (ExternalPlugin | string)[]\n imports?: Record<string, string>\n scripts?: (ExternalScript | string)[]\n viewer?: ProjectViewerSettings\n}\n\n/** A configured script or plugin is package-backed only when it names a declared dependency exactly. */\nexport function isDependencyModuleSpecifier(\n specifier: string,\n packageJson: ProjectPackageJSON,\n): boolean {\n const dependencies = packageJson.dependencies\n return isRecord(dependencies) && Object.prototype.hasOwnProperty.call(dependencies, specifier)\n}\n\nexport function parsePackageJSON(text: string): ProjectPackageJSON {\n const json = parse(text) as unknown\n if (!json || typeof json !== 'object' || Array.isArray(json)) {\n throw new Error('Invalid package.json file: expected an object')\n }\n const packageJson = json as ProjectPackageJSON\n if (typeof packageJson.mainScene !== 'string' || !packageJson.mainScene.toLowerCase().endsWith('.gltf')) {\n throw new Error('package.json mainScene must name a text .gltf file')\n }\n return packageJson\n}\n\nexport function parseAssetsJSONManifest(text: string): AssetsJSONManifest {\n const json = parse(text) as AssetsJSONManifest\n\n if (json.files && typeof json.files !== 'object') {\n throw new Error('Invalid assets.json file: files should be an object')\n }\n if (json.version !== undefined && typeof json.version !== 'number') {\n throw new Error('Invalid assets.json file: version should be a number')\n }\n\n if (!json.files) json.files = {}\n if (!json.version) json.version = 1\n\n return json\n}\n\nexport function validateSceneSource(path: string, text: string): void {\n const document = JSON.parse(text) as {asset?: unknown}\n if (!document || typeof document !== 'object' || !document.asset) {\n throw new Error(`${path} is not a JSON glTF document`)\n }\n}\n\nexport function readProjectGeneratorStates(text: string): ProjectGeneratorState[] {\n try {\n const document = JSON.parse(text) as {\n nodes?: Array<{\n name?: unknown\n extras?: {EntityComponentPlugin?: Record<string, {type?: unknown, state?: unknown}>}\n }>\n }\n const generators: ProjectGeneratorState[] = []\n for (const [nodeIndex, node] of (document.nodes || []).entries()) {\n for (const [componentId, component] of Object.entries(node.extras?.EntityComponentPlugin || {})) {\n if (component.type !== 'Generator' || !isRecord(component.state)) continue\n generators.push({\n componentId,\n module: typeof component.state.module === 'string' ? component.state.module : '',\n nodeIndex,\n nodeName: typeof node.name === 'string' ? node.name : `Node ${nodeIndex}`,\n params: isRecord(component.state.params) ? component.state.params : {},\n })\n }\n }\n return generators\n } catch {\n return []\n }\n}\n\nexport function updateProjectGeneratorState(\n text: string,\n generator: Pick<ProjectGeneratorState, 'componentId' | 'nodeIndex' | 'nodeName'>,\n update: Partial<Pick<ProjectGeneratorState, 'module' | 'params'>>,\n): {text: string, state: Record<string, unknown>} {\n const document = JSON.parse(text) as {\n nodes?: Array<{extras?: {EntityComponentPlugin?: Record<string, {state?: unknown}>}}>\n }\n const state = document.nodes?.[generator.nodeIndex]?.extras?.EntityComponentPlugin?.[generator.componentId]?.state\n if (!isRecord(state)) throw new Error(`Generator component is missing on ${generator.nodeName}`)\n Object.assign(state, update)\n return {text: JSON.stringify(document, null, 2), state}\n}\n\nexport async function parsePackageJsonSettingsConfig(json: ProjectPackageJSON, _project?: unknown): Promise<ProjectConfigSettings> {\n const config = (json[settingsKey] ?? {}) as ProjectConfigSettingsJSON\n const dependencies: ProjectDependency[] = []\n const packageDependencies = json.dependencies && typeof json.dependencies === 'object' && !Array.isArray(json.dependencies)\n ? json.dependencies as Record<string, string>\n : {}\n const deps: Record<string, string> = {\n ...packageDependencies,\n }\n\n dependencies.push(...Object.entries(deps).map(([key, version]) => ({key, version})))\n\n if (config.imports) {\n dependencies.push(...Object.entries(config.imports).map(([key, url]) => ({\n key,\n url: !url.startsWith('@') ? url : undefined,\n version: url.startsWith('@') ? url.slice(1) : '',\n })))\n }\n\n const plugins = config.plugins?.map((entry) => {\n if (typeof entry !== 'string') return entry\n\n const match = entry.match(/\\((.*)\\)$/)\n let params: JSONValue[] | undefined\n let spec = entry\n\n if (match) {\n const paramString = match[1].trim()\n spec = entry.slice(0, match.index).trim()\n if (paramString) {\n try {\n const errors: ParseError[] = []\n params = parse(`[${paramString}]`, errors)\n if (!Array.isArray(params) || errors.length) {\n console.error(errors)\n throw new Error('Plugin params is not a valid array')\n }\n } catch (error) {\n console.error('Unable to parse plugin params, skipping plugin', entry, paramString, error)\n return null\n }\n }\n }\n\n const separator = spec.lastIndexOf(':')\n return {\n import: separator !== -1 ? spec.slice(0, separator) : spec,\n className: separator !== -1 ? spec.slice(separator + 1) : undefined,\n params,\n } satisfies ExternalPlugin\n }) || []\n\n const scripts = config.scripts?.map((entry) =>\n typeof entry === 'string' ? {import: entry} : entry\n ) || []\n\n return {\n plugins: plugins.filter(Boolean) as ExternalPlugin[],\n scripts,\n dependencies,\n viewer: config.viewer || {},\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n"],"names":["settingsKey","assetUrlPrefix","isDependencyModuleSpecifier","specifier","packageJson","dependencies","isRecord","parsePackageJSON","text","json","parse","parseAssetsJSONManifest","validateSceneSource","path","document","readProjectGeneratorStates","generators","nodeIndex","node","componentId","component","_a","updateProjectGeneratorState","generator","update","state","_e","_d","_c","_b","parsePackageJsonSettingsConfig","_project","config","deps","key","version","url","plugins","entry","match","params","spec","paramString","errors","error","separator","scripts","value"],"mappings":"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"}
1
+ {"version":3,"file":"projectFormat.js","sources":["../src/runtime/projectFormat.ts"],"sourcesContent":["import {parse, ParseError} from 'jsonc-parser'\nimport type {GeneratorParamSchema} from '../generatorParams.ts'\n\nexport const settingsKey = 'kite3d'\nexport const assetUrlPrefix = `/${settingsKey}/`\n\nexport type JSONValue = string | number | boolean | null | JSONValue[] | {[key: string]: JSONValue}\nexport type ProjectPackageJSON = Record<string, JSONValue> & {mainScene: string}\n\nexport interface ProjectGeneratorState {\n componentId: string\n module: string\n nodeIndex: number\n nodeName: string\n params: Record<string, unknown>\n schema: GeneratorParamSchema\n}\n\nexport interface AssetsJSONManifest {\n files: Record<string, {\n path: string\n files?: Record<string, string>\n }>\n version: number\n}\n\nexport function createProjectAssetURLModifier(base: URL, assets: AssetsJSONManifest) {\n const assetIdPrefix = `${assetUrlPrefix}@`\n return (url: string): string => {\n if (url.startsWith(assetIdPrefix)) {\n const request = new URL(url, 'https://kite3d.invalid')\n const relative = decodeURIComponent(request.pathname.slice(assetIdPrefix.length))\n const slash = relative.indexOf('/')\n const id = slash < 0 ? relative : relative.slice(0, slash)\n const assetPath = slash < 0 ? '' : relative.slice(slash + 1)\n const asset = assets.files[id]\n if (!asset?.path) throw new Error(`Unknown asset id in URL: ${id}`)\n const registered = asset.files?.[assetPath]\n if (registered) return new URL(registered, base).href\n if (asset.files) throw new Error(`Unknown file for asset ${id}: ${assetPath}`)\n if (/^f\\.[^/]+$/i.test(assetPath)) return new URL(asset.path, base).href\n return new URL(assetPath, new URL(asset.path, base)).href\n }\n if (url.startsWith(assetUrlPrefix)) {\n return new URL(url.slice(assetUrlPrefix.length), base).href\n }\n return url\n }\n}\n\nexport interface ProjectDependency {\n key: string\n version: string\n url?: string\n}\n\nexport interface ExternalPlugin {\n import: string\n /** @default `default` */\n className?: string\n /** @default true */\n active?: boolean\n /** Constructor parameters. */\n params?: JSONValue[]\n}\n\nexport interface ExternalScript {\n import: string\n /** @default true */\n active?: boolean\n}\n\nexport interface ProjectViewerSettings {\n msaa?: boolean\n rgbm?: boolean\n zPrepass?: boolean\n renderScale?: number | 'auto'\n maxRenderScale?: number\n backgroundColor?: string | number | null\n modelRootScale?: number\n stencil?: boolean\n debug?: boolean\n tonemap?: boolean\n camera?: {\n type?: 'perspective' | 'orthographic'\n controlsMode?: string\n position?: [number, number, number]\n target?: [number, number, number]\n }\n maxHDRIntensity?: number\n powerPreference?: 'default' | 'high-performance' | 'low-power'\n}\n\nexport interface ProjectConfigSettings {\n plugins: ExternalPlugin[]\n scripts: ExternalScript[]\n dependencies: ProjectDependency[]\n viewer: ProjectViewerSettings\n}\n\nexport interface ProjectConfigSettingsJSON {\n plugins?: (ExternalPlugin | string)[]\n imports?: Record<string, string>\n scripts?: (ExternalScript | string)[]\n viewer?: ProjectViewerSettings\n}\n\n/** A configured script or plugin is package-backed only when it names a declared dependency exactly. */\nexport function isDependencyModuleSpecifier(\n specifier: string,\n packageJson: ProjectPackageJSON,\n): boolean {\n const dependencies = packageJson.dependencies\n return isRecord(dependencies) && Object.prototype.hasOwnProperty.call(dependencies, specifier)\n}\n\nexport function parsePackageJSON(text: string): ProjectPackageJSON {\n const json = parse(text) as unknown\n if (!json || typeof json !== 'object' || Array.isArray(json)) {\n throw new Error('Invalid package.json file: expected an object')\n }\n const packageJson = json as ProjectPackageJSON\n if (typeof packageJson.mainScene !== 'string' || !packageJson.mainScene.toLowerCase().endsWith('.gltf')) {\n throw new Error('package.json mainScene must name a text .gltf file')\n }\n return packageJson\n}\n\nexport function parseAssetsJSONManifest(text: string): AssetsJSONManifest {\n const json = parse(text) as AssetsJSONManifest\n\n if (json.files && typeof json.files !== 'object') {\n throw new Error('Invalid assets.json file: files should be an object')\n }\n if (json.version !== undefined && typeof json.version !== 'number') {\n throw new Error('Invalid assets.json file: version should be a number')\n }\n\n if (!json.files) json.files = {}\n if (!json.version) json.version = 1\n\n return json\n}\n\nexport function validateSceneSource(path: string, text: string): void {\n const document = JSON.parse(text) as {asset?: unknown}\n if (!document || typeof document !== 'object' || !document.asset) {\n throw new Error(`${path} is not a JSON glTF document`)\n }\n}\n\nexport function readProjectGeneratorStates(text: string): ProjectGeneratorState[] {\n try {\n const document = JSON.parse(text) as {\n nodes?: Array<{\n name?: unknown\n extras?: {EntityComponentPlugin?: Record<string, {type?: unknown, state?: unknown}>}\n }>\n }\n const generators: ProjectGeneratorState[] = []\n for (const [nodeIndex, node] of (document.nodes || []).entries()) {\n for (const [componentId, component] of Object.entries(node.extras?.EntityComponentPlugin || {})) {\n if (component.type !== 'Generator' || !isRecord(component.state)) continue\n generators.push({\n componentId,\n module: typeof component.state.module === 'string' ? component.state.module : '',\n nodeIndex,\n nodeName: typeof node.name === 'string' ? node.name : `Node ${nodeIndex}`,\n params: isRecord(component.state.params) ? component.state.params : {},\n schema: {},\n })\n }\n }\n return generators\n } catch {\n return []\n }\n}\n\nexport function updateProjectGeneratorState(\n text: string,\n generator: Pick<ProjectGeneratorState, 'componentId' | 'nodeIndex' | 'nodeName'>,\n update: Partial<Pick<ProjectGeneratorState, 'module' | 'params'>>,\n): {text: string, state: Record<string, unknown>} {\n const document = JSON.parse(text) as {\n nodes?: Array<{extras?: {EntityComponentPlugin?: Record<string, {state?: unknown}>}}>\n }\n const state = document.nodes?.[generator.nodeIndex]?.extras?.EntityComponentPlugin?.[generator.componentId]?.state\n if (!isRecord(state)) throw new Error(`Generator component is missing on ${generator.nodeName}`)\n Object.assign(state, update)\n return {text: JSON.stringify(document, null, 2), state}\n}\n\nexport async function parsePackageJsonSettingsConfig(json: ProjectPackageJSON, _project?: unknown): Promise<ProjectConfigSettings> {\n const config = (json[settingsKey] ?? {}) as ProjectConfigSettingsJSON\n const dependencies: ProjectDependency[] = []\n const packageDependencies = json.dependencies && typeof json.dependencies === 'object' && !Array.isArray(json.dependencies)\n ? json.dependencies as Record<string, string>\n : {}\n const deps: Record<string, string> = {\n ...packageDependencies,\n }\n\n dependencies.push(...Object.entries(deps).map(([key, version]) => ({key, version})))\n\n if (config.imports) {\n dependencies.push(...Object.entries(config.imports).map(([key, url]) => ({\n key,\n url: !url.startsWith('@') ? url : undefined,\n version: url.startsWith('@') ? url.slice(1) : '',\n })))\n }\n\n const plugins = config.plugins?.map((entry) => {\n if (typeof entry !== 'string') return entry\n\n const match = entry.match(/\\((.*)\\)$/)\n let params: JSONValue[] | undefined\n let spec = entry\n\n if (match) {\n const paramString = match[1].trim()\n spec = entry.slice(0, match.index).trim()\n if (paramString) {\n try {\n const errors: ParseError[] = []\n params = parse(`[${paramString}]`, errors)\n if (!Array.isArray(params) || errors.length) {\n console.error(errors)\n throw new Error('Plugin params is not a valid array')\n }\n } catch (error) {\n console.error('Unable to parse plugin params, skipping plugin', entry, paramString, error)\n return null\n }\n }\n }\n\n const separator = spec.lastIndexOf(':')\n return {\n import: separator !== -1 ? spec.slice(0, separator) : spec,\n className: separator !== -1 ? spec.slice(separator + 1) : undefined,\n params,\n } satisfies ExternalPlugin\n }) || []\n\n const scripts = config.scripts?.map((entry) =>\n typeof entry === 'string' ? {import: entry} : entry\n ) || []\n\n return {\n plugins: plugins.filter(Boolean) as ExternalPlugin[],\n scripts,\n dependencies,\n viewer: config.viewer || {},\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n"],"names":["settingsKey","assetUrlPrefix","createProjectAssetURLModifier","base","assets","assetIdPrefix","url","request","relative","slash","id","assetPath","asset","registered","_a","isDependencyModuleSpecifier","specifier","packageJson","dependencies","isRecord","parsePackageJSON","text","json","parse","parseAssetsJSONManifest","validateSceneSource","path","document","readProjectGeneratorStates","generators","nodeIndex","node","componentId","component","updateProjectGeneratorState","generator","update","state","_e","_d","_c","_b","parsePackageJsonSettingsConfig","_project","config","deps","key","version","plugins","entry","match","params","spec","paramString","errors","error","separator","scripts","value"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { GeneratorParamSchema } from '../generatorParams.ts';
1
2
  export declare const settingsKey = "kite3d";
2
3
  export declare const assetUrlPrefix = "/kite3d/";
3
4
  export type JSONValue = string | number | boolean | null | JSONValue[] | {
@@ -12,13 +13,16 @@ export interface ProjectGeneratorState {
12
13
  nodeIndex: number;
13
14
  nodeName: string;
14
15
  params: Record<string, unknown>;
16
+ schema: GeneratorParamSchema;
15
17
  }
16
18
  export interface AssetsJSONManifest {
17
19
  files: Record<string, {
18
20
  path: string;
21
+ files?: Record<string, string>;
19
22
  }>;
20
23
  version: number;
21
24
  }
25
+ export declare function createProjectAssetURLModifier(base: URL, assets: AssetsJSONManifest): (url: string) => string;
22
26
  export interface ProjectDependency {
23
27
  key: string;
24
28
  version: string;