@vgai/engine 0.4.1 → 0.5.0-canary.20260719.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.
Files changed (103) hide show
  1. package/README.md +48 -15
  2. package/package.json +11 -25
  3. package/schemas/engine-capabilities.json +10 -10
  4. package/schemas/entity2d.schema.json +468 -0
  5. package/schemas/mat.schema.json +2 -33
  6. package/schemas/prefab.schema.json +16 -172
  7. package/schemas/scn2d.schema.json +42 -23
  8. package/schemas/vgai-game.schema.json +34 -0
  9. package/schemas/vscn.schema.json +16 -172
  10. package/src/adapter/authoring.ts +152 -2
  11. package/src/adapter/colyseus-networking-adapter.ts +35 -1
  12. package/src/adapter/first-party-systems.ts +7 -1
  13. package/src/adapter/game-adapter.ts +13 -0
  14. package/src/adapter/index.ts +25 -0
  15. package/src/adapter/rapier-physics-adapter.ts +55 -2
  16. package/src/adapter/system-adapter.ts +249 -2
  17. package/src/adapter/vgai-scene-game-adapter.ts +149 -25
  18. package/src/ai/navigation.ts +28 -0
  19. package/src/animation/clip-map.ts +1 -8
  20. package/src/animation/theatre-director.ts +50 -0
  21. package/src/animation/xstate-animation-binding.ts +6 -0
  22. package/src/audio/audio-introspection.ts +290 -0
  23. package/src/audio/tone-context.ts +46 -0
  24. package/src/dev/chrome-trace.ts +153 -0
  25. package/src/dev/performance-profiler.ts +93 -6
  26. package/src/dev/render-debug-adapter.ts +199 -0
  27. package/src/dev/render-memory.ts +243 -0
  28. package/src/dev/webgl-frame-capture.ts +424 -0
  29. package/src/ecs/component-manager.ts +43 -10
  30. package/src/ecs/game-component.ts +39 -10
  31. package/src/input/input-manager.ts +24 -19
  32. package/src/input/input-types.ts +1 -1
  33. package/src/loader.ts +7 -0
  34. package/src/manifest/load.ts +14 -0
  35. package/src/manifest/schema.ts +65 -0
  36. package/src/react/game-state.tsx +1 -1
  37. package/src/render/render-batch-system.ts +26 -12
  38. package/src/render/spark-renderer-lifecycle.ts +64 -0
  39. package/src/runtime/create-runtime.ts +33 -5
  40. package/src/runtime/debug-bridge.ts +5 -5
  41. package/src/runtime/game.ts +102 -20
  42. package/src/runtime/mount-manifest.ts +1 -1
  43. package/src/runtime/render-control.ts +121 -0
  44. package/src/runtime/types.ts +1 -1
  45. package/src/scene/asset-loaders.ts +77 -3
  46. package/src/scene/instance-mesh.ts +25 -0
  47. package/src/scene/material-factory.ts +4 -15
  48. package/src/scene/mesh-shadow.ts +18 -0
  49. package/src/scene/particles-factory.ts +59 -0
  50. package/src/scene/scene-loader.ts +41 -16
  51. package/src/scene/schema/instances.ts +1 -2
  52. package/src/scene/schema/material.ts +83 -94
  53. package/src/scene/schema/mesh.ts +76 -90
  54. package/src/scene/schema/scene-file.ts +1 -2
  55. package/src/scene/user-data.ts +30 -14
  56. package/src/setup/setup-renderer.ts +6 -1
  57. package/src/world2d/asset-paths2d.ts +44 -0
  58. package/src/world2d/collision-2d.ts +7 -14
  59. package/src/world2d/entity2d-asset.ts +22 -0
  60. package/src/world2d/index.ts +27 -2
  61. package/src/world2d/physics2d-transform.ts +173 -0
  62. package/src/world2d/physics2d-units.ts +10 -0
  63. package/src/world2d/pixi-game-adapter.ts +148 -36
  64. package/src/world2d/scene2d-identity.ts +49 -0
  65. package/src/world2d/scene2d-loader.ts +243 -119
  66. package/src/world2d/schema/entity2d.ts +51 -33
  67. package/src/world2d/schema/physics2d.ts +14 -3
  68. package/src/world2d/schema/sprite.ts +32 -4
  69. package/src/world2d/schema/tilemap.ts +26 -9
  70. package/src/world2d/transform-writer-2d.ts +29 -11
  71. package/src/world2d/types.ts +21 -8
  72. package/src/world3d-react/behavior.tsx +138 -0
  73. package/src/world3d-react/engine-bridge.ts +48 -0
  74. package/src/world3d-react/index.ts +44 -0
  75. package/src/world3d-react/r3f-adapter.tsx +303 -0
  76. package/src/world3d-react/world-context.ts +294 -0
  77. package/vendor/realism-effects/LICENSE.md +21 -0
  78. package/vendor/realism-effects/UPSTREAM.md +19 -0
  79. package/vendor/realism-effects/dist/index.cjs +3447 -0
  80. package/vendor/realism-effects/dist/index.d.ts +59 -0
  81. package/vendor/realism-effects/dist/index.js +3434 -0
  82. package/vendor/realism-effects/package.json +23 -0
  83. package/src/character/cloth-sim.ts +0 -533
  84. package/src/character/spring-chain.ts +0 -307
  85. package/src/humanoid/body.ts +0 -663
  86. package/src/humanoid/clips.ts +0 -149
  87. package/src/humanoid/compose.ts +0 -209
  88. package/src/humanoid/generate.ts +0 -189
  89. package/src/humanoid/index.ts +0 -36
  90. package/src/humanoid/schema.ts +0 -108
  91. package/src/humanoid/skeleton.ts +0 -345
  92. package/src/react/humanoid-bake.document.tsx +0 -337
  93. package/src/scene/geometries/index.ts +0 -7
  94. package/src/scene/geometries/terrain.ts +0 -42
  95. package/src/scene/geometry-registry.ts +0 -42
  96. package/src/scene/instance-registry.ts +0 -84
  97. package/src/scene/instancers/grid.ts +0 -38
  98. package/src/scene/instancers/index.ts +0 -7
  99. package/src/scene/material-registry.ts +0 -73
  100. package/src/scene/materials/index.ts +0 -7
  101. package/src/scene/materials/water.ts +0 -56
  102. package/src/world2d/components-2d.ts +0 -86
  103. package/tools/humanoid-bake.tool.ts +0 -274
@@ -1,274 +0,0 @@
1
- /**
2
- * Package-contributed project tool for baking the procedural humanoid into
3
- * ordinary project assets. The editor discovers this module through
4
- * @vgai/engine's package.json; the editor itself contains no humanoid branch.
5
- */
6
-
7
- import { readFile, realpath } from 'node:fs/promises';
8
- import { dirname, resolve, sep } from 'node:path';
9
- import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js';
10
- import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
11
- import { z } from 'zod';
12
- import { createHumanoidClipLibrary, retargetClipToHumanoid } from '../src/humanoid/clips';
13
- import { generateHumanoid } from '../src/humanoid/generate';
14
- import { HumanoidParamsSchema } from '../src/humanoid/schema';
15
-
16
- export const HumanoidBakeInputSchema = z.object({
17
- name: z
18
- .string()
19
- .regex(/^[a-z0-9][a-z0-9-_]{0,63}$/)
20
- .default('humanoid')
21
- .describe('Stable lowercase asset name used for the generated GLB and prefab files.'),
22
- params: HumanoidParamsSchema.default(HumanoidParamsSchema.parse({})).describe(
23
- 'Procedural body proportions.',
24
- ),
25
- clipSource: z
26
- .string()
27
- .optional()
28
- .describe(
29
- 'Optional project-public GLB path containing Mixamo-named clips. When supplied, Idle, Walk, and Run are retargeted and baked into the generated humanoid GLB.',
30
- ),
31
- clipNames: z
32
- .array(z.string())
33
- .min(1)
34
- .default(['Idle', 'Walk', 'Run'])
35
- .describe('Exact standard clip names to retarget from clipSource.'),
36
- dryRun: z
37
- .boolean()
38
- .default(false)
39
- .describe('Generate and validate the complete output batch without writing project files.'),
40
- });
41
-
42
- const OutputFileSchema = z.object({
43
- path: z.string(),
44
- bytes: z.number(),
45
- mediaType: z.string().optional(),
46
- role: z.enum(['asset', 'prefab', 'provenance', 'other']).optional(),
47
- });
48
-
49
- export const HumanoidBakeResultSchema = z.object({
50
- model: z.string(),
51
- prefab: z.string(),
52
- provenanceOperationId: z.string().optional(),
53
- vertexCount: z.number(),
54
- clips: z.array(z.string()),
55
- files: z.array(OutputFileSchema),
56
- totalBytes: z.number(),
57
- dryRun: z.boolean(),
58
- });
59
-
60
- interface OutputWriter {
61
- write(
62
- files: ReadonlyArray<{
63
- path: string;
64
- content: string | Uint8Array;
65
- mediaType?: string;
66
- role?: 'asset' | 'prefab' | 'provenance' | 'other';
67
- }>,
68
- options?: { dryRun?: boolean },
69
- ): Promise<{
70
- files: z.infer<typeof OutputFileSchema>[];
71
- totalBytes: number;
72
- dryRun: boolean;
73
- provenanceOperationId?: string;
74
- }>;
75
- }
76
-
77
- interface ProjectToolContext {
78
- projectRoot?: string;
79
- projectOutputs?: OutputWriter;
80
- signal?: AbortSignal;
81
- }
82
-
83
- const nodeThreePolyfillKeys = ['self', 'ProgressEvent', 'createImageBitmap', 'FileReader'] as const;
84
-
85
- function installNodeThreePolyfills(): () => void {
86
- const target = globalThis as unknown as Record<string, unknown>;
87
- const previous = new Map(
88
- nodeThreePolyfillKeys.map((key) => [key, Object.getOwnPropertyDescriptor(globalThis, key)]),
89
- );
90
- if (!target['self']) target['self'] = globalThis;
91
- if (!target['ProgressEvent']) {
92
- target['ProgressEvent'] = class {
93
- readonly type: string;
94
- constructor(type: string, init: Record<string, unknown> = {}) {
95
- this.type = type;
96
- Object.assign(this, init);
97
- }
98
- };
99
- }
100
- if (!target['createImageBitmap']) {
101
- target['createImageBitmap'] = async () => ({ close() {} });
102
- }
103
- if (!target['FileReader']) {
104
- target['FileReader'] = class {
105
- result: string | ArrayBuffer | null = null;
106
- onloadend: (() => void) | null = null;
107
- readAsArrayBuffer(blob: Blob): void {
108
- void blob.arrayBuffer().then((value) => {
109
- this.result = value;
110
- this.onloadend?.();
111
- });
112
- }
113
- readAsDataURL(blob: Blob): void {
114
- void blob.arrayBuffer().then((value) => {
115
- this.result = `data:${blob.type || 'application/octet-stream'};base64,${Buffer.from(value).toString('base64')}`;
116
- this.onloadend?.();
117
- });
118
- }
119
- };
120
- }
121
- return () => {
122
- for (const key of nodeThreePolyfillKeys) {
123
- const descriptor = previous.get(key);
124
- if (descriptor) Object.defineProperty(globalThis, key, descriptor);
125
- else Reflect.deleteProperty(globalThis, key);
126
- }
127
- };
128
- }
129
-
130
- async function resolvePublicFile(projectRoot: string, path: string): Promise<string> {
131
- const relativePath = path.replace(/^\//, '');
132
- const publicRoot = await realpath(resolve(projectRoot, 'public'));
133
- const candidate = await realpath(resolve(publicRoot, relativePath));
134
- if (candidate !== publicRoot && !candidate.startsWith(`${publicRoot}${sep}`)) {
135
- throw new Error(`clipSource must resolve inside the project's public/ directory: ${path}`);
136
- }
137
- return candidate;
138
- }
139
-
140
- async function loadRetargetedClips(
141
- projectRoot: string,
142
- sourcePath: string,
143
- names: string[],
144
- rig: ReturnType<typeof generateHumanoid>,
145
- ) {
146
- const absolute = await resolvePublicFile(projectRoot, sourcePath);
147
- const bytes = await readFile(absolute);
148
- const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
149
- const gltf = await new GLTFLoader().parseAsync(arrayBuffer, `${dirname(absolute)}${sep}`);
150
- const library = createHumanoidClipLibrary(gltf.animations);
151
- const clips = names.map((name) => {
152
- const clip = retargetClipToHumanoid(library.get(name), rig);
153
- clip.name = name;
154
- return clip;
155
- });
156
- gltf.scene.traverse((object) => {
157
- const mesh = object as typeof object & {
158
- geometry?: { dispose(): void };
159
- material?: { dispose(): void } | Array<{ dispose(): void }>;
160
- };
161
- mesh.geometry?.dispose();
162
- for (const material of Array.isArray(mesh.material)
163
- ? mesh.material
164
- : mesh.material
165
- ? [mesh.material]
166
- : []) {
167
- material.dispose();
168
- }
169
- });
170
- return { clips };
171
- }
172
-
173
- async function exportGlb(
174
- root: ReturnType<typeof generateHumanoid>['root'],
175
- animations: Awaited<ReturnType<typeof loadRetargetedClips>>['clips'],
176
- ): Promise<Uint8Array> {
177
- const result = await new Promise<ArrayBuffer>((resolveResult, reject) => {
178
- new GLTFExporter().parse(
179
- root,
180
- (value) => {
181
- if (value instanceof ArrayBuffer) resolveResult(value);
182
- else reject(new Error('GLTFExporter returned JSON while binary output was requested.'));
183
- },
184
- reject,
185
- {
186
- binary: true,
187
- animations,
188
- onlyVisible: false,
189
- },
190
- );
191
- });
192
- return new Uint8Array(result);
193
- }
194
-
195
- export const tool = {
196
- name: 'project.humanoid.bake',
197
- summary: 'Bake a procedural humanoid into an ordinary GLB asset and prefab.',
198
- description:
199
- 'Generates VGAI’s skinned procedural humanoid from body parameters. Optionally retargets ' +
200
- 'Mixamo-named clips from a project-public GLB, then atomically writes the generated GLB, ' +
201
- 'a normal .prefab.json referencing it, with automatic project provenance. Use the prefab as ' +
202
- 'the authored scene object; do not regenerate the visible body every gameplay run. The ' +
203
- 'baked body keeps the multicolored engineering-reference material: it is not a styled ' +
204
- 'production character. A prominent player character should receive an intentional, ' +
205
- 'project-owned material/composition treatment unless that reference look is deliberate.',
206
- input: HumanoidBakeInputSchema,
207
- result: HumanoidBakeResultSchema,
208
- errors: [],
209
- requires: { project: true },
210
- host: 'node' as const,
211
- mutates: true,
212
- supportsDryRun: true,
213
- longRunning: true,
214
- permission: {
215
- risk: 'write' as const,
216
- summary: 'Writes or replaces a generated model and prefab under public/.',
217
- },
218
- async impl(input: z.infer<typeof HumanoidBakeInputSchema>, ctx: ProjectToolContext) {
219
- if (!ctx.projectRoot || !ctx.projectOutputs) {
220
- throw new Error('project.humanoid.bake requires a project root and generated-output writer.');
221
- }
222
- if (ctx.signal?.aborted) throw new Error('project.humanoid.bake was cancelled.');
223
-
224
- const rig = generateHumanoid(input.params);
225
- const restoreNodeGlobals = installNodeThreePolyfills();
226
- try {
227
- const loaded = input.clipSource
228
- ? await loadRetargetedClips(ctx.projectRoot, input.clipSource, input.clipNames, rig)
229
- : { clips: [] };
230
- const glb = await exportGlb(rig.root, loaded.clips);
231
- const base = input.name;
232
- const model = `public/models/generated/${base}.glb`;
233
- const prefab = `public/prefabs/generated/${base}.prefab.json`;
234
- const modelUrl = `/models/generated/${base}.glb`;
235
- const prefabDocument = {
236
- version: 1,
237
- name: base,
238
- root: {
239
- name: base,
240
- mesh: { type: 'gltf', src: modelUrl },
241
- ...(loaded.clips.length > 0 ? { animation: {} } : {}),
242
- shadow: { enabled: true },
243
- },
244
- };
245
- const output = await ctx.projectOutputs.write(
246
- [
247
- {
248
- path: model,
249
- content: glb,
250
- mediaType: 'model/gltf-binary',
251
- role: 'asset',
252
- },
253
- {
254
- path: prefab,
255
- content: `${JSON.stringify(prefabDocument, null, 2)}\n`,
256
- mediaType: 'application/json',
257
- role: 'prefab',
258
- },
259
- ],
260
- { dryRun: input.dryRun },
261
- );
262
- return {
263
- model,
264
- prefab,
265
- vertexCount: rig.vertexCount,
266
- clips: loaded.clips.map((clip) => clip.name),
267
- ...output,
268
- };
269
- } finally {
270
- rig.dispose();
271
- restoreNodeGlobals();
272
- }
273
- },
274
- };