@vgai/engine 0.5.42 → 0.5.45

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 (114) hide show
  1. package/dist/adapter/adapter-module.d.ts +28 -29
  2. package/dist/adapter/adapter-module.d.ts.map +1 -1
  3. package/dist/adapter/adapter-module.js +11 -34
  4. package/dist/adapter/authoring-seam-contract.d.ts +5 -0
  5. package/dist/adapter/authoring-seam-contract.d.ts.map +1 -1
  6. package/dist/adapter/authoring-seam-contract.js +1 -0
  7. package/dist/adapter/authoring.d.ts +16 -0
  8. package/dist/adapter/authoring.d.ts.map +1 -1
  9. package/dist/adapter/finders/finder-result.d.ts +2 -2
  10. package/dist/adapter/finders/finder-result.d.ts.map +1 -1
  11. package/dist/adapter/finders/index.d.ts +15 -2
  12. package/dist/adapter/finders/index.d.ts.map +1 -1
  13. package/dist/adapter/finders/index.js +38 -10
  14. package/dist/adapter/finders/prefabs-from-stories.d.ts.map +1 -1
  15. package/dist/adapter/finders/registry.d.ts +45 -0
  16. package/dist/adapter/finders/registry.d.ts.map +1 -0
  17. package/dist/adapter/finders/registry.js +56 -0
  18. package/dist/adapter/ingest/scene-capture.d.ts.map +1 -1
  19. package/dist/adapter/ingest/scene-capture.js +50 -20
  20. package/dist/adapter/system-adapter.d.ts +3 -1
  21. package/dist/adapter/system-adapter.d.ts.map +1 -1
  22. package/dist/canvas-react/pixi-react-root-factory.d.ts.map +1 -1
  23. package/dist/canvas-react/pixi-react-root-factory.js +21 -11
  24. package/dist/data/vite-plugin-data.d.ts +1 -1
  25. package/dist/data/vite-plugin-data.d.ts.map +1 -1
  26. package/dist/data/vite-plugin-data.js +2 -2
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/input/host-pointer.d.ts +18 -0
  31. package/dist/input/host-pointer.d.ts.map +1 -1
  32. package/dist/input/host-pointer.js +54 -5
  33. package/dist/input/input-manager.d.ts +83 -1
  34. package/dist/input/input-manager.d.ts.map +1 -1
  35. package/dist/input/input-manager.js +357 -8
  36. package/dist/manifest/configuration-kinds.d.ts +97 -0
  37. package/dist/manifest/configuration-kinds.d.ts.map +1 -0
  38. package/dist/manifest/configuration-kinds.js +148 -0
  39. package/dist/manifest/index.d.ts +2 -1
  40. package/dist/manifest/index.d.ts.map +1 -1
  41. package/dist/manifest/index.js +4 -3
  42. package/dist/manifest/kind-modules.d.ts +18 -0
  43. package/dist/manifest/kind-modules.d.ts.map +1 -0
  44. package/dist/manifest/kind-modules.js +58 -0
  45. package/dist/manifest/load-file.d.ts +3 -3
  46. package/dist/manifest/load-file.d.ts.map +1 -1
  47. package/dist/manifest/load-file.js +4 -4
  48. package/dist/manifest/load.d.ts +17 -12
  49. package/dist/manifest/load.d.ts.map +1 -1
  50. package/dist/manifest/load.js +29 -19
  51. package/dist/manifest/runtime-environment.d.ts +11 -0
  52. package/dist/manifest/runtime-environment.d.ts.map +1 -0
  53. package/dist/manifest/runtime-environment.js +44 -0
  54. package/dist/manifest/schema.d.ts +10 -9
  55. package/dist/manifest/schema.d.ts.map +1 -1
  56. package/dist/manifest/schema.js +32 -27
  57. package/dist/react/use-data.d.ts +1 -1
  58. package/dist/react/use-data.js +1 -1
  59. package/dist/render/matcap-texture.d.ts +5 -0
  60. package/dist/render/matcap-texture.d.ts.map +1 -0
  61. package/dist/render/matcap-texture.js +82 -0
  62. package/dist/render/soft-particle-depth.d.ts +14 -8
  63. package/dist/render/soft-particle-depth.d.ts.map +1 -1
  64. package/dist/render/soft-particle-depth.js +37 -14
  65. package/dist/render/viewport-shading.d.ts +11 -1
  66. package/dist/render/viewport-shading.d.ts.map +1 -1
  67. package/dist/render/viewport-shading.js +25 -0
  68. package/dist/runtime/create-runtime.js +6 -5
  69. package/dist/runtime/mount-manifest.d.ts.map +1 -1
  70. package/dist/runtime/mount-manifest.js +11 -2
  71. package/dist/settings/schema.d.ts +99 -0
  72. package/dist/settings/schema.d.ts.map +1 -0
  73. package/dist/settings/schema.js +110 -0
  74. package/dist/world3d-react/r3f-root-factory.d.ts.map +1 -1
  75. package/dist/world3d-react/r3f-root-factory.js +34 -36
  76. package/dist/world3d-react/rapier-physics-bridge.d.ts.map +1 -1
  77. package/dist/world3d-react/rapier-physics-bridge.js +21 -6
  78. package/dist-config/config.js +1 -1
  79. package/dist-config/config.js.map +2 -2
  80. package/package.json +2 -1
  81. package/schemas/engine-capabilities.json +4 -4
  82. package/schemas/vgai-project.schema.json +41 -36
  83. package/schemas/vgai-settings.schema.json +112 -0
  84. package/src/adapter/adapter-module.ts +33 -51
  85. package/src/adapter/authoring-seam-contract.ts +1 -0
  86. package/src/adapter/authoring.ts +16 -0
  87. package/src/adapter/finders/finder-result.ts +2 -2
  88. package/src/adapter/finders/index.ts +68 -12
  89. package/src/adapter/finders/prefabs-from-stories.ts +2 -2
  90. package/src/adapter/finders/registry.ts +95 -0
  91. package/src/adapter/finders/scenes-from-entrypoint-selection.ts +4 -4
  92. package/src/adapter/ingest/scene-capture.ts +48 -19
  93. package/src/adapter/system-adapter.ts +3 -1
  94. package/src/canvas-react/pixi-react-root-factory.tsx +21 -11
  95. package/src/data/vite-plugin-data.ts +4 -2
  96. package/src/index.ts +1 -1
  97. package/src/input/host-pointer.ts +84 -5
  98. package/src/input/input-manager.ts +404 -7
  99. package/src/manifest/configuration-kinds.ts +241 -0
  100. package/src/manifest/index.ts +4 -3
  101. package/src/manifest/kind-modules.ts +58 -0
  102. package/src/manifest/load-file.ts +11 -5
  103. package/src/manifest/load.ts +53 -22
  104. package/src/manifest/runtime-environment.ts +48 -0
  105. package/src/manifest/schema.ts +39 -33
  106. package/src/react/use-data.ts +1 -1
  107. package/src/render/matcap-texture.ts +92 -0
  108. package/src/render/soft-particle-depth.ts +43 -14
  109. package/src/render/viewport-shading.ts +33 -1
  110. package/src/runtime/create-runtime.ts +6 -5
  111. package/src/runtime/mount-manifest.ts +13 -2
  112. package/src/settings/schema.ts +127 -0
  113. package/src/world3d-react/r3f-root-factory.tsx +45 -39
  114. package/src/world3d-react/rapier-physics-bridge.tsx +22 -8
@@ -0,0 +1,148 @@
1
+ /**
2
+ * THE RUN-CONFIGURATION KIND REGISTRY — the open set of kinds a manifest's
3
+ * `configurations[]` may declare (ARCHITECTURE-CORE §The project model). A run
4
+ * configuration is one of the project's ENTRYPOINTS: something the editor,
5
+ * the CLI or a harness can start by id. The engine registers two kinds
6
+ * here; a capability registers more through the same door; the manifest
7
+ * validates each declaration against its kind's own schema at load, and an
8
+ * unregistered kind refuses loudly naming the registered ones.
9
+ *
10
+ * The implicit configuration every project with roots has is `play` — mount
11
+ * every root in the host — which is never declared and may be named by a
12
+ * `compound`.
13
+ */
14
+ import { z } from 'zod';
15
+ const CONFIGURATION_ROLES = ['run', 'build'];
16
+ /** Register a contribution's kind after checking its shape by name. */
17
+ export function registerContributedConfigurationKind(value, source) {
18
+ const record = (value ?? {});
19
+ const problems = [];
20
+ if (typeof record.kind !== 'string' || record.kind.length === 0)
21
+ problems.push('`kind` must be a non-empty string');
22
+ if (!CONFIGURATION_ROLES.includes(record.role))
23
+ problems.push("`role` must be 'run' or 'build'");
24
+ if (typeof record.describe !== 'string')
25
+ problems.push('`describe` must be a string');
26
+ const schema = record.schema;
27
+ if (!schema || typeof schema.safeParse !== 'function')
28
+ problems.push('`schema` must be a Zod schema');
29
+ const build = record.build;
30
+ if (build !== undefined &&
31
+ (typeof build.tool !== 'string' || typeof build.input !== 'function')) {
32
+ problems.push('`build` must be `{ tool: string; input(configuration) }`');
33
+ }
34
+ if (problems.length > 0) {
35
+ throw new Error(`${source}: not a configuration kind — ${problems.join('; ')}`);
36
+ }
37
+ return registerConfigurationKind(record);
38
+ }
39
+ const registry = new Map();
40
+ /** Register a kind. A second registration replaces the first (a module
41
+ * re-evaluated on save); never throws. */
42
+ export function registerConfigurationKind(registration) {
43
+ const entry = registration;
44
+ registry.set(registration.kind, entry);
45
+ return () => {
46
+ if (registry.get(registration.kind) === entry)
47
+ registry.delete(registration.kind);
48
+ };
49
+ }
50
+ export function registeredConfigurationKinds() {
51
+ return [...registry.keys()];
52
+ }
53
+ export function configurationKind(kind) {
54
+ return registry.get(kind);
55
+ }
56
+ /** The id of the implicit configuration: mount every root in the host. */
57
+ export const PLAY_CONFIGURATION_ID = 'play';
58
+ registerConfigurationKind({
59
+ kind: 'process',
60
+ role: 'run',
61
+ describe: 'A process beside the host: an entry module, a port, readiness',
62
+ schema: z
63
+ .object({
64
+ id: z.string().min(1).describe('Configuration id'),
65
+ kind: z.literal('process'),
66
+ entry: z.string().min(1).describe('Project-relative entry module'),
67
+ command: z
68
+ .string()
69
+ .min(1)
70
+ .optional()
71
+ .describe('Shell command that starts it; `npx tsx <entry>` when omitted'),
72
+ port: z.number().int().min(1).max(65535).optional().describe('Port it listens on'),
73
+ cwd: z.string().min(1).optional().describe('Project-relative working directory'),
74
+ env: z.record(z.string(), z.string()).optional().describe('Environment for the process'),
75
+ ready: z
76
+ .object({ http: z.string().min(1).optional().describe('HTTP path answering 2xx when up') })
77
+ .strict()
78
+ .optional()
79
+ .describe('Readiness beyond the port accepting connections'),
80
+ })
81
+ .strict(),
82
+ });
83
+ registerConfigurationKind({
84
+ kind: 'compound',
85
+ role: 'run',
86
+ describe: 'Several configurations started together; `play` names the host mount',
87
+ schema: z
88
+ .object({
89
+ id: z.string().min(1).describe('Configuration id'),
90
+ kind: z.literal('compound'),
91
+ run: z.array(z.string().min(1)).min(1).describe('Configuration ids, `play` included'),
92
+ instances: z
93
+ .number()
94
+ .int()
95
+ .min(1)
96
+ .optional()
97
+ .describe('Instances of the host mount to run against the rest'),
98
+ })
99
+ .strict(),
100
+ });
101
+ registerConfigurationKind({
102
+ kind: 'bundle',
103
+ role: 'build',
104
+ describe: "The project's web bundle: its build script, then dist/ packaged as the artifact",
105
+ schema: z
106
+ .object({
107
+ id: z.string().min(1).describe('Configuration id'),
108
+ kind: z.literal('bundle'),
109
+ script: z.string().min(1).optional().describe('package.json script that builds (`build`)'),
110
+ args: z.array(z.string()).optional().describe('Arguments passed after `--`'),
111
+ })
112
+ .strict(),
113
+ });
114
+ /** Validate `configurations[]` against the registry: every kind registered, every
115
+ * declaration its kind's shape, ids unique, compound members declared. */
116
+ export function configurationIssues(configurations) {
117
+ const issues = [];
118
+ const ids = new Set();
119
+ for (const declaration of configurations) {
120
+ if (ids.has(declaration.id))
121
+ issues.push(`configurations: duplicate id "${declaration.id}"`);
122
+ ids.add(declaration.id);
123
+ const registration = registry.get(declaration.kind);
124
+ if (!registration) {
125
+ issues.push(`configurations "${declaration.id}": unknown kind "${declaration.kind}" — registered: ${registeredConfigurationKinds()
126
+ .map((k) => `"${k}"`)
127
+ .join(', ')}`);
128
+ continue;
129
+ }
130
+ const parsed = registration.schema.safeParse(declaration);
131
+ if (!parsed.success) {
132
+ for (const issue of parsed.error.issues) {
133
+ issues.push(`configurations "${declaration.id}" (${declaration.kind}): ${issue.path.join('.') || '(declaration)'}: ${issue.message}`);
134
+ }
135
+ }
136
+ }
137
+ for (const declaration of configurations) {
138
+ if (declaration.kind !== 'compound')
139
+ continue;
140
+ const members = declaration.run ?? [];
141
+ for (const member of members) {
142
+ if (member !== PLAY_CONFIGURATION_ID && !ids.has(member)) {
143
+ issues.push(`configurations "${declaration.id}": member "${member}" is not a declared configuration (or "${PLAY_CONFIGURATION_ID}")`);
144
+ }
145
+ }
146
+ }
147
+ return issues;
148
+ }
@@ -1,6 +1,7 @@
1
+ export * from './configuration-kinds';
1
2
  export { isManifestFilename, MANIFEST_FILENAME, REMOVED_MANIFEST_FILENAME, removedManifestFilenameMessage, } from './filename';
2
3
  export type { ResolvedAdapter, ResolvedAdapterRoot, ResolvedGameManifest } from './load';
3
- export { DEFAULT_SERVER_MODULE, loadGameManifest } from './load';
4
+ export { loadGameManifest } from './load';
4
5
  export type { AdapterRoot, GameManifest, RootAdapter } from './schema';
5
6
  export { AdapterRootSchema, GameManifestSchema, RootAdapterSchema } from './schema';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/manifest/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AACzF,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/manifest/index.ts"],"names":[],"mappings":"AAGA,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,yBAAyB,EACzB,8BAA8B,GAC/B,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
@@ -1,9 +1,10 @@
1
1
  // Game manifest (vgai.project.json) — schema + loader (T3.1 slice
2
2
  // 1)..
3
+ export * from './configuration-kinds';
3
4
  export { isManifestFilename, MANIFEST_FILENAME, REMOVED_MANIFEST_FILENAME, removedManifestFilenameMessage, } from './filename';
4
- export { DEFAULT_SERVER_MODULE, loadGameManifest } from './load';
5
+ export { loadGameManifest } from './load';
5
6
  export { AdapterRootSchema, GameManifestSchema, RootAdapterSchema } from './schema';
6
- // `loadGameManifestFile` (Node-only, reads `path` via `node:fs`) is
7
+ // File loading and kind-module discovery read `node:fs` and are
7
8
  // deliberately NOT re-exported here — this barrel must stay import-safe for
8
9
  // browser bundles. Import it directly from `@engine/manifest/load-file` in
9
- // Node-only contexts (CLI, tests).
10
+ // Node-only contexts; kind discovery lives in `@engine/manifest/kind-modules`.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Where a project's CONFIGURATION-KIND CONTRIBUTIONS live and how a host
3
+ * takes them in (ARCHITECTURE-CORE §The project model). A module named
4
+ * `src/contributions/<name>.kind.ts` (or `.tsx`) exports `kind`, a plain
5
+ * `ConfigurationKindContribution`; the HOST that loads the manifest — the
6
+ * editor server through Vite's SSR loader, a project's own validate script
7
+ * through tsx — imports each and registers it in its own registry through
8
+ * {@link registerContributedConfigurationKind}. Node-only: it walks the
9
+ * project folder.
10
+ */
11
+ /** Whether one file name is a kind contribution by the convention. */
12
+ export declare function isConfigurationKindModule(fileName: string): boolean;
13
+ /** Absolute paths of the project's kind contributions, sorted. */
14
+ export declare function contributedKindModulePaths(projectDir: string): string[];
15
+ /** Register the `kind` export of an already-imported module; the source
16
+ * path names the module in a refusal. */
17
+ export declare function registerKindModule(module: unknown, source: string): () => void;
18
+ //# sourceMappingURL=kind-modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kind-modules.d.ts","sourceRoot":"","sources":["../../src/manifest/kind-modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,sEAAsE;AACtE,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,kEAAkE;AAClE,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAwBvE;AAED;0CAC0C;AAC1C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,CAM9E"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Where a project's CONFIGURATION-KIND CONTRIBUTIONS live and how a host
3
+ * takes them in (ARCHITECTURE-CORE §The project model). A module named
4
+ * `src/contributions/<name>.kind.ts` (or `.tsx`) exports `kind`, a plain
5
+ * `ConfigurationKindContribution`; the HOST that loads the manifest — the
6
+ * editor server through Vite's SSR loader, a project's own validate script
7
+ * through tsx — imports each and registers it in its own registry through
8
+ * {@link registerContributedConfigurationKind}. Node-only: it walks the
9
+ * project folder.
10
+ */
11
+ import { readdirSync, statSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ import { registerContributedConfigurationKind } from './configuration-kinds';
14
+ const KIND_SUFFIXES = ['.kind.ts', '.kind.tsx'];
15
+ /** Whether one file name is a kind contribution by the convention. */
16
+ export function isConfigurationKindModule(fileName) {
17
+ return KIND_SUFFIXES.some((suffix) => fileName.endsWith(suffix));
18
+ }
19
+ /** Absolute paths of the project's kind contributions, sorted. */
20
+ export function contributedKindModulePaths(projectDir) {
21
+ const found = [];
22
+ const walk = (directory) => {
23
+ let names;
24
+ try {
25
+ names = readdirSync(directory);
26
+ }
27
+ catch {
28
+ return;
29
+ }
30
+ for (const name of names) {
31
+ if (name.startsWith('.') || name === 'node_modules')
32
+ continue;
33
+ const absolute = join(directory, name);
34
+ let isDirectory = false;
35
+ try {
36
+ isDirectory = statSync(absolute).isDirectory();
37
+ }
38
+ catch {
39
+ continue;
40
+ }
41
+ if (isDirectory)
42
+ walk(absolute);
43
+ else if (isConfigurationKindModule(name))
44
+ found.push(absolute);
45
+ }
46
+ };
47
+ walk(join(projectDir, 'src', 'contributions'));
48
+ return found.sort();
49
+ }
50
+ /** Register the `kind` export of an already-imported module; the source
51
+ * path names the module in a refusal. */
52
+ export function registerKindModule(module, source) {
53
+ const exported = module?.kind;
54
+ if (exported === undefined) {
55
+ throw new Error(`${source}: a kind contribution must export \`kind\``);
56
+ }
57
+ return registerContributedConfigurationKind(exported, source);
58
+ }
@@ -1,7 +1,7 @@
1
- import { type ResolvedGameManifest } from './load';
1
+ import { type LoadGameManifestOptions, type ResolvedGameManifest } from './load';
2
2
  export { hasManifest, manifestWritePath, resolveManifestPath } from './locate';
3
3
  /** Read + JSON.parse `path`, then resolve it via `loadGameManifest`. Node-only. */
4
- export declare function loadGameManifestFile(path: string): ResolvedGameManifest;
4
+ export declare function loadGameManifestFile(path: string, options?: LoadGameManifestOptions): ResolvedGameManifest;
5
5
  /** {@link loadGameManifestFile} against `dir`'s `vgai.project.json`. */
6
- export declare function loadGameManifestDir(dir: string): ResolvedGameManifest;
6
+ export declare function loadGameManifestDir(dir: string, options?: LoadGameManifestOptions): ResolvedGameManifest;
7
7
  //# sourceMappingURL=load-file.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load-file.d.ts","sourceRoot":"","sources":["../../src/manifest/load-file.ts"],"names":[],"mappings":"AASA,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAMrE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/E,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAGvE;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAErE"}
1
+ {"version":3,"file":"load-file.d.ts","sourceRoot":"","sources":["../../src/manifest/load-file.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,uBAAuB,EAAoB,KAAK,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAMnG,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAE/E,mFAAmF;AACnF,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,uBAA4B,GACpC,oBAAoB,CAGtB;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,uBAA4B,GACpC,oBAAoB,CAEtB"}
@@ -13,11 +13,11 @@ import { resolveManifestPath } from './locate';
13
13
  // module.
14
14
  export { hasManifest, manifestWritePath, resolveManifestPath } from './locate';
15
15
  /** Read + JSON.parse `path`, then resolve it via `loadGameManifest`. Node-only. */
16
- export function loadGameManifestFile(path) {
16
+ export function loadGameManifestFile(path, options = {}) {
17
17
  const raw = JSON.parse(readFileSync(path, 'utf-8'));
18
- return loadGameManifest(raw);
18
+ return loadGameManifest(raw, options);
19
19
  }
20
20
  /** {@link loadGameManifestFile} against `dir`'s `vgai.project.json`. */
21
- export function loadGameManifestDir(dir) {
22
- return loadGameManifestFile(resolveManifestPath(dir));
21
+ export function loadGameManifestDir(dir, options = {}) {
22
+ return loadGameManifestFile(resolveManifestPath(dir), options);
23
23
  }
@@ -1,4 +1,5 @@
1
- import { type LearnMetadata } from './schema';
1
+ import { type DeclaredConfiguration } from './configuration-kinds';
2
+ import { type GameManifest, type LearnMetadata } from './schema';
2
3
  /** D6's resolved adapter identities. */
3
4
  export type ResolvedAdapter = {
4
5
  readonly type: 'builtin';
@@ -62,14 +63,15 @@ export interface ResolvedGameManifest {
62
63
  };
63
64
  /** Sorted by zOrder; ties broken by original array order (§3). */
64
65
  readonly roots: readonly ResolvedAdapterRoot[];
65
- readonly server: {
66
- readonly room: string;
67
- readonly module: string;
68
- /** The declared endpoint, or `undefined` = the scaffold default (see
69
- * the schema's own description; the editor resolves it against the
70
- * page host, which the loader has no business knowing). */
71
- readonly endpoint: string | undefined;
72
- } | undefined;
66
+ /** The declared run configurations, validated by kind (`run-kinds.ts`). */
67
+ readonly configurations: readonly DeclaredConfiguration[];
68
+ /** Ids whose kind no registry here knows — only ever non-empty when the
69
+ * caller loaded with `configurationKinds: 'defer'` (a bundled host that
70
+ * cannot evaluate a project's kind contributions); the editor session
71
+ * is the validator for those. */
72
+ readonly deferredConfigurationKinds: readonly string[];
73
+ /** Deploy-baked relay credentials, when the served manifest carries them. */
74
+ readonly relay: GameManifest['relay'];
73
75
  readonly resolution: {
74
76
  readonly width: number;
75
77
  readonly height: number;
@@ -117,13 +119,16 @@ export interface ResolvedGameManifest {
117
119
  * gallery/wizard/Learn-catalog registries. */
118
120
  readonly learn: LearnMetadata | undefined;
119
121
  }
120
- /** Default relative path for `server.module` when omitted (§3) — the scaffolded Colyseus bootstrap. */
121
- export declare const DEFAULT_SERVER_MODULE = "server/colyseus-setup.ts";
122
122
  /**
123
123
  * Parse + validate + resolve a raw manifest value into a `ResolvedGameManifest`.
124
124
  * Pure data-in/data-out (no `fs`) — see `load-file.ts` for the Node path-based
125
125
  * wrapper. Throws a descriptive `Error` (naming the offending root/field) on
126
126
  * any Zod validation failure or cross-field rule violation.
127
127
  */
128
- export declare function loadGameManifest(raw: unknown): ResolvedGameManifest;
128
+ export interface LoadGameManifestOptions {
129
+ /** `require` (default): a declaration of an unregistered kind refuses.
130
+ * `defer`: it is reported in `deferredConfigurationKinds` instead. */
131
+ readonly configurationKinds?: 'require' | 'defer';
132
+ }
133
+ export declare function loadGameManifest(raw: unknown, options?: LoadGameManifestOptions): ResolvedGameManifest;
129
134
  //# sourceMappingURL=load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/manifest/load.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/manifest/load.ts"],"names":[],"mappings":"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"}
@@ -12,9 +12,8 @@
12
12
  // No `fs` import here on purpose — `load-file.ts` is the thin Node-only
13
13
  // wrapper that reads a path and calls this function, so browser bundles that
14
14
  // only need `loadGameManifest` never pull in `node:fs`.
15
+ import { configurationIssues, configurationKind, } from './configuration-kinds';
15
16
  import { GameManifestSchema, } from './schema';
16
- /** Default relative path for `server.module` when omitted (§3) — the scaffolded Colyseus bootstrap. */
17
- export const DEFAULT_SERVER_MODULE = 'server/colyseus-setup.ts';
18
17
  const SEMVER_RE = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?$/;
19
18
  // ---------------------------------------------------------------------------
20
19
  // Adapter shape guards
@@ -119,16 +118,7 @@ function resolveRoot(root) {
119
118
  loop: root.loop,
120
119
  };
121
120
  }
122
- // ---------------------------------------------------------------------------
123
- // Entry point
124
- // ---------------------------------------------------------------------------
125
- /**
126
- * Parse + validate + resolve a raw manifest value into a `ResolvedGameManifest`.
127
- * Pure data-in/data-out (no `fs`) — see `load-file.ts` for the Node path-based
128
- * wrapper. Throws a descriptive `Error` (naming the offending root/field) on
129
- * any Zod validation failure or cross-field rule violation.
130
- */
131
- export function loadGameManifest(raw) {
121
+ export function loadGameManifest(raw, options = {}) {
132
122
  // Removed-format guard FIRST, on the raw value: a root declaring a removed
133
123
  // content field would otherwise fail Zod's `roots` discriminated union with
134
124
  // a confusing shape error instead of the named migration message.
@@ -156,13 +146,31 @@ export function loadGameManifest(raw) {
156
146
  }));
157
147
  resolvedWithIndex.sort((a, b) => a.root.zOrder - b.root.zOrder || a.index - b.index);
158
148
  const roots = resolvedWithIndex.map(({ root }) => root);
159
- const server = manifest.server
160
- ? {
161
- room: manifest.server.room,
162
- module: manifest.server.module ?? DEFAULT_SERVER_MODULE,
163
- endpoint: manifest.server.endpoint,
149
+ const configurations = (manifest.configurations ?? []);
150
+ // Kinds are OPEN (ARCHITECTURE-CORE §The project model): each declaration
151
+ // is checked against its registered kind's own schema HERE, where the
152
+ // host's registry is, not in the Zod schema. A host that cannot evaluate a
153
+ // project's kind contributions defers unknown kinds by name instead of
154
+ // refusing them.
155
+ const deferredConfigurationKinds = [];
156
+ const kindIssues = configurationIssues(configurations).filter((issue) => {
157
+ if (options.configurationKinds !== 'defer')
158
+ return true;
159
+ const unknown = /^configurations "([^"]+)": unknown kind/.exec(issue);
160
+ if (!unknown)
161
+ return true;
162
+ deferredConfigurationKinds.push(unknown[1]);
163
+ return false;
164
+ });
165
+ if (kindIssues.length > 0) {
166
+ throw new Error(`Game manifest: ${kindIssues.join('\n ')}`);
167
+ }
168
+ for (const configuration of configurations) {
169
+ if (!configurationKind(configuration.kind) &&
170
+ !deferredConfigurationKinds.includes(configuration.id)) {
171
+ deferredConfigurationKinds.push(configuration.id);
164
172
  }
165
- : undefined;
173
+ }
166
174
  return {
167
175
  manifestVersion: manifest.manifestVersion,
168
176
  name: manifest.name,
@@ -170,7 +178,9 @@ export function loadGameManifest(raw) {
170
178
  version: manifest.version,
171
179
  engine: { version: manifest.engine.version },
172
180
  roots,
173
- server,
181
+ configurations,
182
+ deferredConfigurationKinds,
183
+ relay: manifest.relay,
174
184
  resolution: manifest.resolution,
175
185
  rendering: manifest.rendering,
176
186
  authoring: manifest.authoring,
@@ -0,0 +1,11 @@
1
+ /** `engines.node` from the project's `package.json`, or `null` when the
2
+ * project declares none (or has no package.json). */
3
+ export declare function declaredNodeRange(projectDir: string): string | null;
4
+ /**
5
+ * Why a process of this project cannot start on the running Node, spelled
6
+ * for the person who will fix it — or `null` when it can. A range that is
7
+ * not valid semver is itself the issue: a declaration nobody can satisfy is
8
+ * named, never skipped.
9
+ */
10
+ export declare function nodeRuntimeIssue(projectDir: string, running?: string): string | null;
11
+ //# sourceMappingURL=runtime-environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-environment.d.ts","sourceRoot":"","sources":["../../src/manifest/runtime-environment.ts"],"names":[],"mappings":"AAeA;sDACsD;AACtD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQnE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,MAA8B,GACtC,MAAM,GAAG,IAAI,CAWf"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * THE RUNTIME HALF OF A PROJECT'S ENVIRONMENT (ARCHITECTURE-CORE §The
3
+ * project model, "environment"): the Node version a project's processes need
4
+ * is declared ONCE, where the ecosystem already declares it —
5
+ * `package.json` `engines.node` — and read here by whatever starts a
6
+ * `process` configuration (the editor server's configurations route, the
7
+ * CLI's autoboot). The manifest carries no `environment` key: a second
8
+ * declaration of the same fact is the drift a single home prevents.
9
+ *
10
+ * Node-only (reads the project folder), like `locate.ts`.
11
+ */
12
+ import { readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+ import semver from 'semver';
15
+ /** `engines.node` from the project's `package.json`, or `null` when the
16
+ * project declares none (or has no package.json). */
17
+ export function declaredNodeRange(projectDir) {
18
+ try {
19
+ const raw = JSON.parse(readFileSync(join(projectDir, 'package.json'), 'utf-8'));
20
+ const engines = raw?.engines;
21
+ return typeof engines?.node === 'string' && engines.node.trim() ? engines.node.trim() : null;
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ /**
28
+ * Why a process of this project cannot start on the running Node, spelled
29
+ * for the person who will fix it — or `null` when it can. A range that is
30
+ * not valid semver is itself the issue: a declaration nobody can satisfy is
31
+ * named, never skipped.
32
+ */
33
+ export function nodeRuntimeIssue(projectDir, running = process.versions.node) {
34
+ const range = declaredNodeRange(projectDir);
35
+ if (range === null)
36
+ return null;
37
+ if (semver.validRange(range) === null) {
38
+ return `package.json declares engines.node "${range}", which is not a semver range`;
39
+ }
40
+ if (semver.satisfies(running, range, { includePrerelease: true }))
41
+ return null;
42
+ return (`package.json declares engines.node "${range}" and this host runs Node ${running} — ` +
43
+ `run the editor and \`vgai\` on a Node that satisfies it, or change engines.node`);
44
+ }
@@ -168,15 +168,16 @@ export declare const GameManifestSchema: z.ZodObject<{
168
168
  }, z.core.$strict>>>;
169
169
  }, z.core.$strict>>;
170
170
  }, z.core.$strict>>;
171
- server: z.ZodOptional<z.ZodObject<{
172
- room: z.ZodString;
173
- endpoint: z.ZodOptional<z.ZodString>;
174
- module: z.ZodOptional<z.ZodString>;
175
- relay: z.ZodOptional<z.ZodObject<{
176
- signalingUrl: z.ZodOptional<z.ZodString>;
177
- accessToken: z.ZodString;
178
- expiresAt: z.ZodNumber;
179
- }, z.core.$strict>>;
171
+ configurations: z.ZodOptional<z.ZodArray<z.ZodObject<{
172
+ id: z.ZodString;
173
+ kind: z.ZodString;
174
+ }, z.core.$loose>>>;
175
+ relay: z.ZodOptional<z.ZodObject<{
176
+ signalingUrl: z.ZodOptional<z.ZodString>;
177
+ grant: z.ZodOptional<z.ZodString>;
178
+ sessionUrl: z.ZodOptional<z.ZodString>;
179
+ accessToken: z.ZodOptional<z.ZodString>;
180
+ expiresAt: z.ZodOptional<z.ZodNumber>;
180
181
  }, z.core.$strict>>;
181
182
  resolution: z.ZodOptional<z.ZodObject<{
182
183
  width: z.ZodNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/manifest/schema.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAsFhD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;qBA0H3B,CAAC;AACJ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqFnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAkB5D,eAAO,MAAM,eAAe;;;;;EAMzB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;EAEa,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;kBAqC7B,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAMhE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA8TyD,CAAC;AAEzF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/manifest/schema.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAsFhD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;qBA0H3B,CAAC;AACJ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAqFnB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAkB5D,eAAO,MAAM,eAAe;;;;;EAMzB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,qBAAqB;;;;EAEa,CAAC;AAChD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;kBAqC7B,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAchE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA4TyD,CAAC;AAEzF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -328,6 +328,13 @@ export const LearnMetadataSchema = z
328
328
  // ---------------------------------------------------------------------------
329
329
  // Game manifest (vgai.project.json)
330
330
  // ---------------------------------------------------------------------------
331
+ /** The envelope of one run configuration; the kind's schema takes the rest. */
332
+ const ConfigurationEnvelopeSchema = z
333
+ .object({
334
+ id: z.string().min(1).describe('Configuration id, unique in the manifest'),
335
+ kind: z.string().min(1).describe('A registered run kind'),
336
+ })
337
+ .passthrough();
331
338
  export const GameManifestSchema = z
332
339
  .object({
333
340
  $schema: z
@@ -354,7 +361,6 @@ export const GameManifestSchema = z
354
361
  .describe('Engine version pin'),
355
362
  roots: z
356
363
  .array(AdapterRootSchema)
357
- .min(1)
358
364
  .superRefine((roots, ctx) => {
359
365
  // D-V6 (debt): root ids are described as unique above but that was
360
366
  // describe-only at the SCHEMA level — only load.ts's loader-level
@@ -410,7 +416,7 @@ export const GameManifestSchema = z
410
416
  });
411
417
  }
412
418
  })
413
- .describe("The Game's explicit, non-empty adapter-root composition. There is no implicit root. " +
419
+ .describe("The project's explicit adapter-root composition ZERO OR MORE roots, and no implicit root: a project with no roots mounts nothing (a library of models, a folder of documents) and the editor derives its chrome from what IS declared. " +
414
420
  'Root ids are unique, and a project declares at most ONE world root per medium — ' +
415
421
  'one `three`, one `dom`, one canvas-surface root (first-party canvas, canvas ingest ' +
416
422
  'and canvas module are the same medium).'),
@@ -443,40 +449,39 @@ export const GameManifestSchema = z
443
449
  .strict()
444
450
  .optional()
445
451
  .describe('Editor-only authoring metadata; never runtime ownership'),
446
- server: z
452
+ configurations: z
453
+ .array(ConfigurationEnvelopeSchema)
454
+ .optional()
455
+ .describe("The project's run configurations — its ENTRYPOINTS beyond the host mount (`play`): each an " +
456
+ 'id and a registered kind (`process`, `compound`, and whatever a capability registers) with ' +
457
+ "that kind's own fields. The editor's transport, `vgai run <id>` and a harness start the same declaration."),
458
+ relay: z
447
459
  .object({
448
- room: z.string().describe('Colyseus room name'),
449
- endpoint: z
460
+ signalingUrl: z
450
461
  .string()
451
462
  .optional()
452
- .describe('WebSocket endpoint the editor reports for this room, e.g. "wss://rooms.example.com". ' +
453
- 'Omit to declare the scaffold default, `ws://<the page host>:2567` — the port ' +
454
- "`server/colyseus-setup.ts` listens on. Stated here because the endpoint is the game's " +
455
- 'own deployment fact, not something the editor may guess'),
456
- module: z
463
+ .describe('Managed relay signaling URL to prefer over the client default; omitted when the deploy did not pin one'),
464
+ grant: z
457
465
  .string()
458
466
  .optional()
459
- .describe('Module path for the Colyseus room bootstrap; defaults to the scaffolded server bootstrap'),
460
- relay: z
461
- .object({
462
- signalingUrl: z
463
- .string()
464
- .optional()
465
- .describe('Managed relay signaling URL to prefer over the client default; omitted when the deploy did not pin one'),
466
- accessToken: z
467
- .string()
468
- .describe('Room-scoped managed-relay access token minted at `vgai deploy` and read by the standalone client (main.ts)'),
469
- expiresAt: z
470
- .number()
471
- .describe('Token expiry as epoch milliseconds; the client falls back to a tokenless join once elapsed'),
472
- })
473
- .strict()
467
+ .describe('Room-scoped managed-relay GRANT minted at `vgai deploy`; players exchange it for a fresh token at `sessionUrl`'),
468
+ sessionUrl: z
469
+ .string()
470
+ .optional()
471
+ .describe('Public session endpoint where a deployed client exchanges the grant for a short-lived relay token'),
472
+ accessToken: z
473
+ .string()
474
+ .optional()
475
+ .describe('A baked relay token (older deploys); used directly while unexpired'),
476
+ expiresAt: z
477
+ .number()
474
478
  .optional()
475
- .describe('Deploy-baked managed-relay credentials. NEVER hand-authored in source — written only into the staged manifest by `vgai deploy` and fetched at runtime by the standalone client'),
479
+ .describe('Token expiry as epoch milliseconds; the client falls back to a tokenless join once elapsed'),
476
480
  })
477
481
  .strict()
478
482
  .optional()
479
- .describe('Multiplayer server config (Colyseus), if this game registers a room'),
483
+ .describe('Deploy-baked managed-relay credentials a DEPLOYMENT fact. NEVER hand-authored in source: written only into ' +
484
+ 'the staged manifest by `vgai deploy` and read by the deployed client at connect time.'),
480
485
  resolution: z
481
486
  .object({
482
487
  width: z.number().describe('Canvas width in pixels'),