@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
@@ -1109,19 +1109,20 @@
1109
1109
  "plane",
1110
1110
  "cylinder",
1111
1111
  "capsule",
1112
- "gltf"
1112
+ "gltf",
1113
+ "splat"
1113
1114
  ],
1114
- "description": "Mesh primitive type, or \"gltf\" for an external 3D model"
1115
+ "description": "Renderable type: a built-in mesh primitive, \"gltf\" for an external 3D model, or \"splat\" for a native Gaussian-splat asset"
1115
1116
  },
1116
1117
  "args": {
1117
- "description": "Geometry constructor args — box: [w,h,d], sphere: [radius], cylinder: [rTop,rBot,h], capsule: [radius,length], plane: [w,h]",
1118
+ "description": "Geometry constructor args — box: [w,h,d], sphere: [radius], cylinder: [rTop,rBot,h], capsule: [radius,length], plane: [w,h,widthSegments,heightSegments]",
1118
1119
  "type": "array",
1119
1120
  "items": {
1120
1121
  "type": "number"
1121
1122
  }
1122
1123
  },
1123
1124
  "src": {
1124
- "description": "Path to GLTF/GLB model file. Required when type is \"gltf\"",
1125
+ "description": "Path to the external render asset. Required for \"gltf\" (GLTF/GLB) and \"splat\" (SPZ)",
1125
1126
  "type": "string"
1126
1127
  },
1127
1128
  "node": {
@@ -1132,56 +1133,8 @@
1132
1133
  "description": "Path to an instance-transform asset (.instances.json: an array of [posX,posY,posZ, quatX,quatY,quatZ,quatW, scaleX,scaleY,scaleZ] tuples). Renders one THREE.InstancedMesh (one draw call). Bulk transform data is referenced as an asset, never inlined — keeps vscn thin.",
1133
1134
  "type": "string"
1134
1135
  },
1135
- "instancer": {
1136
- "description": "Registered instancer name. When set, the mesh renders as a single THREE.InstancedMesh (one draw call) with code-generated per-instance transforms instead of one THREE.Mesh",
1137
- "type": "string"
1138
- },
1139
- "instancerParams": {
1140
- "description": "Params for the instancer (e.g. count, spacing), keyed by name",
1141
- "type": "object",
1142
- "propertyNames": {
1143
- "type": "string"
1144
- },
1145
- "additionalProperties": {
1146
- "anyOf": [
1147
- {
1148
- "type": "number"
1149
- },
1150
- {
1151
- "type": "string"
1152
- },
1153
- {
1154
- "type": "boolean"
1155
- }
1156
- ]
1157
- }
1158
- },
1159
- "generator": {
1160
- "description": "Registered geometry-generator name (e.g. \"Terrain\"). When set, the mesh geometry is produced procedurally in code instead of from `type`/`args`. Pairs with a \"trimesh\" collider for matching physics.",
1161
- "type": "string"
1162
- },
1163
- "generatorParams": {
1164
- "description": "Params for the geometry generator (e.g. width, segments, amplitude)",
1165
- "type": "object",
1166
- "propertyNames": {
1167
- "type": "string"
1168
- },
1169
- "additionalProperties": {
1170
- "anyOf": [
1171
- {
1172
- "type": "number"
1173
- },
1174
- {
1175
- "type": "string"
1176
- },
1177
- {
1178
- "type": "boolean"
1179
- }
1180
- ]
1181
- }
1182
- },
1183
1136
  "lod": {
1184
- "description": "Per-entity Level-of-Detail: distance-keyed glTF sub-nodes swapped by camera distance (THREE.LOD). gltf-only. Gated by the environment.rendering.lod master toggle — when off, only the closest level renders. Cannot combine with node/instances/instancer.",
1137
+ "description": "Per-entity Level-of-Detail: distance-keyed glTF sub-nodes swapped by camera distance (THREE.LOD). gltf-only. Gated by the environment.rendering.lod master toggle — when off, only the closest level renders. Cannot combine with node/instances.",
1185
1138
  "type": "array",
1186
1139
  "items": {
1187
1140
  "type": "object",
@@ -1218,40 +1171,9 @@
1218
1171
  "standard",
1219
1172
  "physical",
1220
1173
  "basic",
1221
- "toon",
1222
- "custom"
1174
+ "toon"
1223
1175
  ],
1224
- "description": "Material shading model. \"custom\" resolves `def` against the material registry"
1225
- },
1226
- "def": {
1227
- "description": "Registered custom-material name (required when type is \"custom\")",
1228
- "type": "string"
1229
- },
1230
- "uniforms": {
1231
- "description": "Authored uniform values for a custom material, keyed by uniform name",
1232
- "type": "object",
1233
- "propertyNames": {
1234
- "type": "string"
1235
- },
1236
- "additionalProperties": {
1237
- "anyOf": [
1238
- {
1239
- "type": "number"
1240
- },
1241
- {
1242
- "type": "string"
1243
- },
1244
- {
1245
- "type": "boolean"
1246
- },
1247
- {
1248
- "type": "array",
1249
- "items": {
1250
- "type": "number"
1251
- }
1252
- }
1253
- ]
1254
- }
1176
+ "description": "Material shading model"
1255
1177
  },
1256
1178
  "color": {
1257
1179
  "description": "Base color as CSS hex string (e.g. \"#ff0000\")",
@@ -6181,19 +6103,20 @@
6181
6103
  "plane",
6182
6104
  "cylinder",
6183
6105
  "capsule",
6184
- "gltf"
6106
+ "gltf",
6107
+ "splat"
6185
6108
  ],
6186
- "description": "Mesh primitive type, or \"gltf\" for an external 3D model"
6109
+ "description": "Renderable type: a built-in mesh primitive, \"gltf\" for an external 3D model, or \"splat\" for a native Gaussian-splat asset"
6187
6110
  },
6188
6111
  "args": {
6189
- "description": "Geometry constructor args — box: [w,h,d], sphere: [radius], cylinder: [rTop,rBot,h], capsule: [radius,length], plane: [w,h]",
6112
+ "description": "Geometry constructor args — box: [w,h,d], sphere: [radius], cylinder: [rTop,rBot,h], capsule: [radius,length], plane: [w,h,widthSegments,heightSegments]",
6190
6113
  "type": "array",
6191
6114
  "items": {
6192
6115
  "type": "number"
6193
6116
  }
6194
6117
  },
6195
6118
  "src": {
6196
- "description": "Path to GLTF/GLB model file. Required when type is \"gltf\"",
6119
+ "description": "Path to the external render asset. Required for \"gltf\" (GLTF/GLB) and \"splat\" (SPZ)",
6197
6120
  "type": "string"
6198
6121
  },
6199
6122
  "node": {
@@ -6204,56 +6127,8 @@
6204
6127
  "description": "Path to an instance-transform asset (.instances.json: an array of [posX,posY,posZ, quatX,quatY,quatZ,quatW, scaleX,scaleY,scaleZ] tuples). Renders one THREE.InstancedMesh (one draw call). Bulk transform data is referenced as an asset, never inlined — keeps vscn thin.",
6205
6128
  "type": "string"
6206
6129
  },
6207
- "instancer": {
6208
- "description": "Registered instancer name. When set, the mesh renders as a single THREE.InstancedMesh (one draw call) with code-generated per-instance transforms instead of one THREE.Mesh",
6209
- "type": "string"
6210
- },
6211
- "instancerParams": {
6212
- "description": "Params for the instancer (e.g. count, spacing), keyed by name",
6213
- "type": "object",
6214
- "propertyNames": {
6215
- "type": "string"
6216
- },
6217
- "additionalProperties": {
6218
- "anyOf": [
6219
- {
6220
- "type": "number"
6221
- },
6222
- {
6223
- "type": "string"
6224
- },
6225
- {
6226
- "type": "boolean"
6227
- }
6228
- ]
6229
- }
6230
- },
6231
- "generator": {
6232
- "description": "Registered geometry-generator name (e.g. \"Terrain\"). When set, the mesh geometry is produced procedurally in code instead of from `type`/`args`. Pairs with a \"trimesh\" collider for matching physics.",
6233
- "type": "string"
6234
- },
6235
- "generatorParams": {
6236
- "description": "Params for the geometry generator (e.g. width, segments, amplitude)",
6237
- "type": "object",
6238
- "propertyNames": {
6239
- "type": "string"
6240
- },
6241
- "additionalProperties": {
6242
- "anyOf": [
6243
- {
6244
- "type": "number"
6245
- },
6246
- {
6247
- "type": "string"
6248
- },
6249
- {
6250
- "type": "boolean"
6251
- }
6252
- ]
6253
- }
6254
- },
6255
6130
  "lod": {
6256
- "description": "Per-entity Level-of-Detail: distance-keyed glTF sub-nodes swapped by camera distance (THREE.LOD). gltf-only. Gated by the environment.rendering.lod master toggle — when off, only the closest level renders. Cannot combine with node/instances/instancer.",
6131
+ "description": "Per-entity Level-of-Detail: distance-keyed glTF sub-nodes swapped by camera distance (THREE.LOD). gltf-only. Gated by the environment.rendering.lod master toggle — when off, only the closest level renders. Cannot combine with node/instances.",
6257
6132
  "type": "array",
6258
6133
  "items": {
6259
6134
  "type": "object",
@@ -6287,40 +6162,9 @@
6287
6162
  "standard",
6288
6163
  "physical",
6289
6164
  "basic",
6290
- "toon",
6291
- "custom"
6165
+ "toon"
6292
6166
  ],
6293
- "description": "Material shading model. \"custom\" resolves `def` against the material registry"
6294
- },
6295
- "def": {
6296
- "description": "Registered custom-material name (required when type is \"custom\")",
6297
- "type": "string"
6298
- },
6299
- "uniforms": {
6300
- "description": "Authored uniform values for a custom material, keyed by uniform name",
6301
- "type": "object",
6302
- "propertyNames": {
6303
- "type": "string"
6304
- },
6305
- "additionalProperties": {
6306
- "anyOf": [
6307
- {
6308
- "type": "number"
6309
- },
6310
- {
6311
- "type": "string"
6312
- },
6313
- {
6314
- "type": "boolean"
6315
- },
6316
- {
6317
- "type": "array",
6318
- "items": {
6319
- "type": "number"
6320
- }
6321
- }
6322
- ]
6323
- }
6167
+ "description": "Material shading model"
6324
6168
  },
6325
6169
  "color": {
6326
6170
  "description": "Base color as CSS hex string (e.g. \"#ff0000\")",
@@ -156,6 +156,8 @@ export interface SelectionProvider {
156
156
  }
157
157
 
158
158
  export interface TransformProvider {
159
+ /** Honest inspector presentation for the substrate's transform vocabulary. */
160
+ dimensions?(id: string): '2d' | '3d' | null;
159
161
  get(id: string): Transform;
160
162
  owner(id: string): TransformOwner;
161
163
  /** Pause whatever controller fights the gizmo (physics/script) for editing. */
@@ -355,7 +357,22 @@ export interface ComponentsProvider {
355
357
  /** Asset drop (hierarchy + viewport). */
356
358
  export interface AssetDropProvider {
357
359
  accepts(nodeId: string, assetPath: string): boolean;
358
- drop(nodeId: string, assetPath: string): void;
360
+ drop(nodeId: string, assetPath: string): void | Promise<void>;
361
+ }
362
+
363
+ /** One adapter-owned reusable-entity format the shared hierarchy can save.
364
+ * The adapter owns the bytes and semantics; the shell owns only the filename
365
+ * dialog. This keeps native 2D entity assets out of Three prefab code while
366
+ * preserving one editor language for the operation. */
367
+ export interface EntityAssetSaveDescriptor {
368
+ defaultFolder: string;
369
+ extension: string;
370
+ label: string;
371
+ }
372
+
373
+ export interface EntityAssetProvider {
374
+ describeSave(nodeId: string): EntityAssetSaveDescriptor | null;
375
+ save(nodeId: string, path: string): Promise<boolean>;
359
376
  }
360
377
 
361
378
  /** Plain-object rect shape shared by {@link RectProvider} — the same fields a real
@@ -395,13 +412,138 @@ export interface RectProvider {
395
412
  emptyContainers?(): { id: string; rect: DOMRectLike; displayName: string }[];
396
413
  }
397
414
 
415
+ /** One adapter-owned reference point rendered by the shared world overlay.
416
+ * Coordinates are host-relative px, the same frame as {@link RectProvider}.
417
+ * A provider deliberately exposes at most one point for a node so coincident
418
+ * native concepts (for example an anchor and pivot) never become ambiguous. */
419
+ export interface BoxEditReferencePoint {
420
+ /** True when the native source constrains this point (for example a
421
+ * normalized 0..1 Sprite anchor). The overlay then uses only exact native
422
+ * snap points, never an unreachable axis-aligned bounding-box target. */
423
+ bounded?: boolean;
424
+ id: string;
425
+ kind: 'anchor' | 'pivot';
426
+ label: string;
427
+ /** Exact host-space points the native reference can reach and should snap
428
+ * to. Useful for transformed corner/edge/center grids on rotated content. */
429
+ snapPoints?: ReadonlyArray<{ x: number; y: number }>;
430
+ x: number;
431
+ y: number;
432
+ }
433
+
398
434
  /** Spatial gesture → source/data write, for non-Object3D (DOM) nodes. Distinct from the
399
435
  * 3D TransformProvider. begin/apply/end bracket a single undo step; apply is live-preview. */
400
436
  export interface BoxEditProvider {
401
437
  begin(id: string): void;
402
- /** patch: any of x,y,width,height,marginTop… paddingLeft… — px deltas or absolutes */
438
+ /** patch: any of x,y,width,height,marginTop… paddingLeft… — px deltas or absolutes.
439
+ * `referenceX`/`referenceY` are the absolute host-relative coordinates of
440
+ * the active {@link referencePoint}; only providers exposing that optional
441
+ * capability receive those keys. The provider owns conversion to native
442
+ * source units and any placement-preserving compensation. */
403
443
  apply(id: string, patch: Record<string, number>): void;
404
444
  end(id: string): void;
445
+ /** Optional single native anchor/pivot affordance for this node. */
446
+ referencePoint?(id: string): BoxEditReferencePoint | null;
447
+ }
448
+
449
+ export interface TilemapCell {
450
+ column: number;
451
+ row: number;
452
+ }
453
+
454
+ /** One bounded native tile grid projected into the shared world overlay.
455
+ * Geometry is affine and host-relative: `origin` is local cell corner [0,0],
456
+ * while `columnStep`/`rowStep` are the transformed one-cell basis vectors.
457
+ * This compact shape represents nested rotation, non-uniform scale, reflection,
458
+ * and zoom without fabricating axis-aligned cell polygons. */
459
+ export interface TilemapEditGrid {
460
+ columns: number;
461
+ columnStep: { x: number; y: number };
462
+ origin: { x: number; y: number };
463
+ palette: ReadonlyArray<{ frame: string; index: number }>;
464
+ rows: number;
465
+ rowStep: { x: number; y: number };
466
+ }
467
+
468
+ /** Native tile-cell authoring. Palette selection is editor-session state;
469
+ * source truth receives only atlas-frame indices, with -1 meaning an empty cell.
470
+ * begin/apply/end bracket one exact project-history transaction. */
471
+ export interface TilemapEditProvider {
472
+ apply(id: string, cell: TilemapCell): void;
473
+ begin(id: string, tileIndex: number): void;
474
+ /** Resolve a host-relative pointer through the adapter's native transform. */
475
+ cellAt(id: string, point: { x: number; y: number }): TilemapCell | null;
476
+ end(id: string): void;
477
+ grid(id: string): TilemapEditGrid | null;
478
+ /** Load the native Pixi atlas used to render palette thumbnails. */
479
+ loadTileset(id: string): Promise<SpriteAtlas2D>;
480
+ }
481
+
482
+ export type PhysicsShape2DHandle = 'half-height' | 'half-width' | 'radius';
483
+
484
+ /** One native 2D physics shape projected into host-relative viewport pixels.
485
+ * `origin` is collider-local [0,0]; `xAxis`/`yAxis` are the transformed
486
+ * one-pixel basis vectors. Keeping the complete affine basis preserves nested
487
+ * rotation, non-uniform scale, reflection, centered canvas placement, and
488
+ * viewport zoom without teaching the shared shell about Pixi or Rapier. */
489
+ export interface PhysicsShape2DProjection {
490
+ collider:
491
+ | { shape: 'cuboid'; halfExtents: readonly [number, number] }
492
+ | { shape: 'ball'; radius: number }
493
+ | { shape: 'capsule'; halfHeight: number; radius: number };
494
+ editable: boolean;
495
+ id: string;
496
+ origin: { x: number; y: number };
497
+ sensor: boolean;
498
+ xAxis: { x: number; y: number };
499
+ yAxis: { x: number; y: number };
500
+ }
501
+
502
+ /** Adapter-owned native collider inspection and spatial editing. Shapes are
503
+ * readable independently of editability so locked/read-only source remains
504
+ * inspectable. begin/apply/end bracket one exact project-history transaction. */
505
+ export interface PhysicsShape2DProvider {
506
+ apply(id: string, handle: PhysicsShape2DHandle, point: { x: number; y: number }): void;
507
+ begin(id: string, handle: PhysicsShape2DHandle): void;
508
+ end(id: string): void;
509
+ shapes(): readonly PhysicsShape2DProjection[];
510
+ }
511
+
512
+ /** One named sub-texture in a Pixi-compatible spritesheet atlas. `x`/`y` are
513
+ * source-image pixels; width/height are the runtime-facing dimensions Pixi
514
+ * swaps when `rotated` reports packed 90-degree storage. */
515
+ export interface SpriteAtlasFrame2D {
516
+ height: number;
517
+ name: string;
518
+ rotated: boolean;
519
+ width: number;
520
+ x: number;
521
+ y: number;
522
+ }
523
+
524
+ export interface SpriteAtlas2D {
525
+ atlasPath: string;
526
+ frames: readonly SpriteAtlasFrame2D[];
527
+ /** Project-relative image source named by the atlas. */
528
+ imagePath: string;
529
+ /** Image bytes loaded through the owning adapter's storage backend. */
530
+ imageBytes: Uint8Array;
531
+ imageMediaType: string;
532
+ }
533
+
534
+ export interface SpriteFrames2DDescriptor {
535
+ atlasPath: string;
536
+ editable: boolean;
537
+ selectedFrame: string | null;
538
+ }
539
+
540
+ /** Source-backed Pixi spritesheet discovery and frame selection. Atlas parsing
541
+ * remains adapter-owned; the universal Inspector only renders this projection.
542
+ * `select` writes source truth and creates one project-history transaction. */
543
+ export interface SpriteFrames2DProvider {
544
+ describe(id: string): SpriteFrames2DDescriptor | null;
545
+ load(id: string): Promise<SpriteAtlas2D>;
546
+ select(id: string, frame: string | null): void;
405
547
  }
406
548
 
407
549
  /** Text-content editing — currently OFF-contract (the react adapter has an `editText(id)`
@@ -458,6 +600,12 @@ export interface AuthoringAdapter {
458
600
  /** T0 (spec 27 §2) — spatial drag-resize/move → source/data write for non-Object3D
459
601
  * (DOM) nodes. Absent ⇒ no box-edit gesture for this adapter. */
460
602
  readonly boxEdit?: BoxEditProvider;
603
+ /** Native 2D physics debug geometry and shape handles. */
604
+ readonly physicsShapes2D?: PhysicsShape2DProvider;
605
+ /** Native Pixi spritesheet frame discovery/selection. */
606
+ readonly spriteFrames2D?: SpriteFrames2DProvider;
607
+ /** Native bounded tile-cell painting. Absent means no viewport tile editor. */
608
+ readonly tilemapEdit?: TilemapEditProvider;
461
609
  /** T0 (spec 27 §2) — double-click-to-edit-text on the contract (wires the react
462
610
  * adapter's existing off-contract `editText`). Absent ⇒ no in-place text edit. */
463
611
  readonly text?: TextProvider;
@@ -470,6 +618,8 @@ export interface AuthoringAdapter {
470
618
  readonly components?: ComponentsProvider;
471
619
  /** Asset drop (hierarchy + viewport). Absent ⇒ this adapter accepts no drops. */
472
620
  readonly assetDrop?: AssetDropProvider;
621
+ /** Save a native entity subtree as an adapter-owned reusable asset. */
622
+ readonly entityAssets?: EntityAssetProvider;
473
623
  /** Undo/redo for this adapter's edits (first-party delegates to the store; an
474
624
  * ingest adapter keeps its own overlay-backed stack). Absent ⇒ host falls back. */
475
625
  undo?(): void;
@@ -16,7 +16,10 @@
16
16
  import type * as THREE from 'three';
17
17
  import type {
18
18
  ConnectionState,
19
+ NetConditioning,
20
+ NetMessageEvent,
19
21
  NetPeer,
22
+ NetRates,
20
23
  NetworkingAdapter,
21
24
  ReplicationStats,
22
25
  RoomInfo,
@@ -47,10 +50,25 @@ export interface ColyseusNetworkingConfig {
47
50
  /** Subscribe to changes in connection state / room / replication stats.
48
51
  * Optional — defaults to a no-op subscription. */
49
52
  subscribe?(cb: () => void): Unsubscribe;
53
+ /** Optional CAPABILITY: plain-data replicated-state snapshot (Colyseus
54
+ * `state.toJSON()`), for the inspector's state tree (W3b). Unlike the
55
+ * defaulted accessors above, this and the remaining optional accessors
56
+ * propagate their ABSENCE to the built adapter — a config that omits one
57
+ * yields an adapter without that method, so the inspector marks the
58
+ * section absent instead of rendering fabricated empties. */
59
+ stateSnapshot?(): unknown;
60
+ /** Optional capability: message-log events with `seq > sinceSeq`. */
61
+ messageEvents?(sinceSeq?: number): NetMessageEvent[];
62
+ /** Optional capability: msg + byte rates for the inspector sparklines. */
63
+ rates?(): NetRates;
64
+ /** Optional capability pair: link conditioning at the adapter seam. Both
65
+ * must be supplied together for the inspector to show the controls. */
66
+ getConditioning?(): NetConditioning;
67
+ setConditioning?(c: NetConditioning): void;
50
68
  }
51
69
 
52
70
  export function createColyseusNetworkingAdapter(cfg: ColyseusNetworkingConfig): NetworkingAdapter {
53
- return {
71
+ const adapter: NetworkingAdapter = {
54
72
  peers: () => cfg.peers(),
55
73
  networkId: (o) => cfg.networkId(o),
56
74
  authority: (o) => {
@@ -69,4 +87,20 @@ export function createColyseusNetworkingAdapter(cfg: ColyseusNetworkingConfig):
69
87
  cfg.replicationStats?.() ?? { entities: 0, msgsInPerSec: 0, msgsOutPerSec: 0 },
70
88
  subscribe: (cb) => cfg.subscribe?.(cb) ?? (() => {}),
71
89
  };
90
+ // The W3b inspector capabilities attach ONLY when supplied: their absence
91
+ // is the editor's degradation signal (`getStateSnapshot` in adapter ⇒ tree,
92
+ // missing ⇒ "not provided by this adapter" — never a fabricated empty).
93
+ const stateSnapshot = cfg.stateSnapshot?.bind(cfg);
94
+ if (stateSnapshot) adapter.getStateSnapshot = () => stateSnapshot();
95
+ const messageEvents = cfg.messageEvents?.bind(cfg);
96
+ if (messageEvents) adapter.messageEvents = (sinceSeq) => messageEvents(sinceSeq);
97
+ const rates = cfg.rates?.bind(cfg);
98
+ if (rates) adapter.getRates = () => rates();
99
+ const getConditioning = cfg.getConditioning?.bind(cfg);
100
+ const setConditioning = cfg.setConditioning?.bind(cfg);
101
+ if (getConditioning && setConditioning) {
102
+ adapter.getConditioning = () => getConditioning();
103
+ adapter.setConditioning = (c) => setConditioning(c);
104
+ }
105
+ return adapter;
72
106
  }
@@ -68,6 +68,7 @@ export function createAudioSystemAdapter(audio: GameAudio): AudioAdapter {
68
68
  let muted = false;
69
69
  let priorGain = audio.masterGain.gain.value;
70
70
  return {
71
+ resume: () => audio.resume(),
71
72
  setMuted(next: boolean) {
72
73
  if (next === muted) return;
73
74
  muted = next;
@@ -82,11 +83,16 @@ export function createAudioSystemAdapter(audio: GameAudio): AudioAdapter {
82
83
  };
83
84
  }
84
85
 
85
- /** First-party `NavigationAdapter` over the engine `NavMeshManager`. */
86
+ /** First-party `NavigationAdapter` over the engine `NavMeshManager` — the
87
+ * blessed recast implementation, including the optional bake/export/crowd
88
+ * capabilities the editor's Navigation panel binds through. */
86
89
  export function createNavigationAdapter(nav: NavMeshManager): NavigationAdapter {
87
90
  return {
88
91
  hasNavMesh: () => nav.hasNavMesh(),
89
92
  findPath: (start: NavPoint, end: NavPoint) => nav.findPath(start, end) as NavPoint[],
90
93
  debugMesh: (scene: THREE.Scene) => nav.getDebugMesh(scene) as unknown as THREE.Object3D | null,
94
+ bake: (meshes, params) => nav.buildFromMeshes(meshes, params),
95
+ exportData: () => nav.exportData(),
96
+ crowdAgents: () => nav.getCrowdAgents(),
91
97
  };
92
98
  }
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { Container } from 'pixi.js';
12
12
  import type * as THREE from 'three';
13
+ import type { ComponentManager } from '../ecs/component-manager';
13
14
  import type { AdapterSurface } from './adapter-surface';
14
15
  import type { AuthoringAdapter } from './authoring';
15
16
  import type { HostContext } from './host-context';
@@ -80,6 +81,18 @@ export interface MountedWorldBase {
80
81
  /** Optional capability providers — absence = "not supported", host degrades. */
81
82
  readonly authoring?: AuthoringAdapter;
82
83
  readonly systems?: SystemAdapters;
84
+ /**
85
+ * Optional component-query capability: an adapter that runs the engine's
86
+ * REAL `ComponentManager` without being the classic first-party mount
87
+ * (e.g. `@engine/world3d-react`'s R3F adapter — `<Behavior>` attaches
88
+ * through a real manager) exposes it here so `Game.queryByComponent`
89
+ * (`runtime/game.ts`) aggregates this world's instances and
90
+ * `registerThreeWorld` (`runtime/create-runtime.ts`) backfills
91
+ * `instance.world` at registration, exactly like a first-party world.
92
+ * Absent for a genuinely foreign mount that hosts no GameComponents —
93
+ * such a world legitimately answers "no components".
94
+ */
95
+ readonly components?: ComponentManager;
83
96
  /** Optional state-observation capability (T7.4 slice 2, §4) — absent means
84
97
  * "no state bridge"; `Game.registerWorld` reports this loudly, once, for
85
98
  * any non-first-party mount. First-party mounts are exempt — their state
@@ -17,26 +17,39 @@ export type {
17
17
  AuthoringCapabilities,
18
18
  AuthoringProvenance,
19
19
  BoxEditProvider,
20
+ BoxEditReferencePoint,
20
21
  ColorSampleProvider,
21
22
  ComponentsProvider,
22
23
  DOMRectLike,
23
24
  EditorNode,
24
25
  EditorNodeRole,
26
+ EntityAssetProvider,
27
+ EntityAssetSaveDescriptor,
25
28
  FileMapProvider,
26
29
  HierarchyProvider,
27
30
  InspectorProvider,
28
31
  LayoutProvider,
29
32
  PersistenceProvider,
33
+ PhysicsShape2DHandle,
34
+ PhysicsShape2DProjection,
35
+ PhysicsShape2DProvider,
30
36
  PickProvider,
31
37
  PropertyDescriptor,
32
38
  RectProvider,
33
39
  RootGroup,
34
40
  RootGroupsProvider,
35
41
  SelectionProvider,
42
+ SpriteAtlas2D,
43
+ SpriteAtlasFrame2D,
44
+ SpriteFrames2DDescriptor,
45
+ SpriteFrames2DProvider,
36
46
  StoriesProvider,
37
47
  StoryRef,
38
48
  StructureProvider,
39
49
  TextProvider,
50
+ TilemapCell,
51
+ TilemapEditGrid,
52
+ TilemapEditProvider,
40
53
  TransformProvider,
41
54
  } from './authoring';
42
55
  export {
@@ -64,13 +77,25 @@ export { createRapierPhysicsAdapter } from './rapier-physics-adapter';
64
77
  export type {
65
78
  ActionValueSnapshot,
66
79
  AssetAdapter,
80
+ AudioAdapter,
81
+ AudioDebugEvent,
82
+ AudioGraphNode,
83
+ AudioMeterFrame,
84
+ AudioMeterHandle,
85
+ AudioTransportState,
67
86
  ConnectionState,
68
87
  InputAdapter,
88
+ NavBakeParams,
89
+ NavCrowdAgentState,
69
90
  NavigationAdapter,
70
91
  NavPoint,
92
+ NetConditioning,
93
+ NetMessageEvent,
71
94
  NetPeer,
95
+ NetRates,
72
96
  NetworkingAdapter,
73
97
  PhysicsAdapter,
98
+ RenderDebugAdapter,
74
99
  ReplicationStats,
75
100
  RoomInfo,
76
101
  SystemAdapters,