@kite3d/engine 0.17.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;
@@ -52,7 +52,8 @@ function P(t) {
52
52
  module: typeof r.state.module == "string" ? r.state.module : "",
53
53
  nodeIndex: c,
54
54
  nodeName: typeof p.name == "string" ? p.name : `Node ${c}`,
55
- params: h(r.state.params) ? r.state.params : {}
55
+ params: h(r.state.params) ? r.state.params : {},
56
+ schema: {}
56
57
  });
57
58
  return o;
58
59
  } catch {
@@ -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 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 })\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
+ {"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,6 +13,7 @@ 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, {