Skip to content

Engine capabilities format

VGAI Reference 0.3

Planned versioned generated-schema truth covering Current engine and schema reference generation.

planned · generated · immutable Reference 0.3

Lifecycle and constraints

Detailed constraints will publish with the generated or reviewed entry.

Runnable Learn material

Generated format inventory

Inventory only — AC-REF-002 is not passed. Valid parser-verified examples, narrative guidance, complete cross-field/runtime constraints, and version history remain deferred. This page must not be treated as a complete format contract.

Source: packages/engine/schemas/engine-capabilities.json · 18 branch-sensitive field records · 0 source-described. This source intentionally supersedes the frozen study boundary.

EngineCapabilities · capability-catalog · 18 fields
Field / branchTypeRequiredDefaultConstraintsDescription
# $ object yes none {"additionalProperties":false} Missing source description
# $.$comment string yes none none Missing source description
# $._readme string yes none none Missing source description
# $.schemaDirPath string yes none none Missing source description
# $.schemaDirHash string yes none none Missing source description
# $.reviewedAt string yes none none Missing source description
# $.entries array yes none none Missing source description
# $.entries[] object yes none {"additionalProperties":false} Missing source description
# $.entries[].id string yes none none Missing source description
# $.entries[].area string yes none none Missing source description
# $.entries[].status string yes none none Missing source description
# $.entries[].claim string yes none none Missing source description
# $.entries[].evidence array yes none none Missing source description
# $.entries[].evidence[] string yes none none Missing source description
# $.entries[].notes string yes none none Missing source description
# $.entries[].evidenceHashes object yes none {"additionalProperties":false} Missing source description
# $.entries[].evidenceHashes.packages/engine/src/scene/scene-loader.ts string yes none none Missing source description
# $.entries[].evidenceHashes.packages/engine/src/world2d/scene2d-loader.ts string yes none none Missing source description

Generated records

#
{
  "id": "schema-record:984de5cc0426c87305a8",
  "area": "physics",
  "status": "unsupported",
  "claim": "No Continuous Collision Detection (CCD). Fast/small dynamic bodies can tunnel through thin colliders in one step.",
  "evidence": [
    "packages/engine/src/scene/scene-loader.ts (the `bodyDesc` switch: fixed/kinematicPositionBased/dynamic only; file under concurrent edit elsewhere this wave, so no line numbers — grep 'RigidBodyDesc')",
    "packages/engine/src/world2d/scene2d-loader.ts:168-179 (2D bodyDesc: same four stock constructors)"
  ],
  "notes": "Grepped packages/engine/src for ccd/CCD/setCcdEnabled: zero matches, 2D and 3D. No call ever sets a ccd flag. Workaround: keep dynamic-body per-step travel small relative to the thinnest collider, or add intermediate colliders.",
  "evidenceHashes": {
    "packages/engine/src/scene/scene-loader.ts": "53c8f6d756363c0638c576b7e5a3d425fe0e77ce929dac9d462b8999b7000db8",
    "packages/engine/src/world2d/scene2d-loader.ts": "f0f74eefd9cce16bbe7826225a52f2b0407ab141641dcdd370bcff1d091bce69"
  },
  "anchor": "record-984de5cc0426c873",
  "version": "0.3"
}
#
{
  "id": "schema-record:d1baf9e0832a498c2d01",
  "area": "physics",
  "status": "unsupported",
  "claim": "No enforced limit on entity or physics-body count; practical envelope is untested.",
  "evidence": [
    "packages/engine/src/setup/setup-physics.ts (RAPIER.World construction: no capacity/count config)",
    "packages/engine/src/scene/scene-loader.ts (entity/body creation: no count guard)"
  ],
  "notes": "Grepped for maxBodies/MAX_ENTITIES/entity limit/body limit/entityCount: no matches. No invented numbers — nothing caps entity/body count and no perf test here establishes a safe ceiling. Treat large counts (hundreds+ dynamic bodies) as unvalidated, not 'supported at scale'.",
  "evidenceHashes": {
    "packages/engine/src/setup/setup-physics.ts": "0540c502f420018b24dac8b77c486f30f905f0a05b02ead7ed3899e5aa612ee5",
    "packages/engine/src/scene/scene-loader.ts": "53c8f6d756363c0638c576b7e5a3d425fe0e77ce929dac9d462b8999b7000db8"
  },
  "anchor": "record-d1baf9e0832a498c",
  "version": "0.3"
}
#
{
  "id": "schema-record:1adf1881ad3795e67f11",
  "area": "input",
  "status": "supported-with-caveats",
  "claim": "F1 (spec §12) added a typed action-value model (digital/scalar/vector2/pointerDelta/pointerPosition, default digital) with real deadzone/combine rules and a valueType-mismatch throw. F2 ('Complete Device Backends') un-rejects mouse_move/gamepad_axis_pair, giving both real readers (mouse_move -> pointerDelta/vector2 off the real mouse-delta accumulator; gamepad_axis_pair -> vector2 off a coupled xAxis/yAxis stick, deadzone-rescaled like gamepad_axis), and adds touch_button/touch_stick (digital/vector2) via setTouchButton/setTouchStick. Real window focus (blur/focus) and pointer-lock state are tracked and flush held REAL-device input on loss (#144: virtual/scheduled machine input gates on enabled only and survives blur); gamepad device identity (id/mapping) is exposed via getGamepadInfo/ActionValueSource.gamepadId. F4 adds getLastActiveDevice() + an optional getPrompt device param. Caveat: pointerPosition still has no real-device backend (test_pointer_position injection only); scalar isn't fed by mouse_move (no axis-select field).",
  "evidence": [
    "packages/engine/src/input/input-types.ts:2-40 (InputBinding union incl. mouse_move/gamepad_axis_pair/touch_button/touch_stick/test_*)",
    "packages/engine/src/input/input-manager.ts:609-1905 (digital/gating/typed getters/inject*/setTouch*/getGamepadInfo/F4 getLastActiveDevice+getPrompt)"
  ],
  "notes": "gamepad disconnect/reconnect needs no special-cased code: poll() re-reads navigator.getGamepads() and every read skips a null slot, so a disconnected gamepad's actions go neutral with a correct isJustReleased edge for free — see input-device-backends-f2.test.ts.",
  "evidenceHashes": {
    "packages/engine/src/input/input-types.ts": "d6c7a6d1eda6b71665407fd5ac35d414dccf4156d4f79c56671b07e0a60b7f7c",
    "packages/engine/src/input/input-manager.ts": "f3c2683397ed36eeb34ffd54861d14e4c0675bc7fbaef5530e7552a1edd129d4"
  },
  "anchor": "record-1adf1881ad3795e6",
  "version": "0.3"
}
#
{
  "id": "schema-record:d338b97542230f4e0760",
  "area": "animation",
  "status": "supported",
  "claim": "A native XState machine can drive multiple simultaneous named AnimationMixer layers through parallel regions. Layers support 0..1 weights, normal or additive Three.js blending, and include/exclude masks over named bone/Object3D subtrees.",
  "evidence": [
    "packages/engine/src/animation/xstate-animation-meta.ts (strict layer, weight, blendMode, and boneMask metadata schemas)",
    "packages/engine/src/animation/xstate-animation-binding.ts (parallel-region reconciliation, subtree track filtering, and native additive composition)"
  ],
  "notes": "XState remains the only transition language. Parallel regions use distinct layer names. The binding filters native clip tracks, uses AnimationUtils.makeClipAdditive, can register with ctx.systems, and exposes live owner inspection data until disposal.",
  "evidenceHashes": {
    "packages/engine/src/animation/xstate-animation-meta.ts": "80376ac74819803616c4b396244a971cb9a6b2859c33409d032363bfeb3db44f",
    "packages/engine/src/animation/xstate-animation-binding.ts": "34e94a7db674ea3d8a98cf98359a9ba8cdd2af9266d1e857a6ad5df02d5a5f73"
  },
  "anchor": "record-d338b97542230f4e",
  "version": "0.3"
}
#
{
  "id": "schema-record:28f32a90132180e2cdad",
  "area": "scene-schema",
  "status": "unsupported",
  "claim": "Authored `components.<Name>` values in .vscn.json/.prefab.json must be a scalar or homogeneous scalar array — nested objects/arrays-of-objects are rejected before a component's own static schema sees them.",
  "evidence": [
    "packages/engine/src/scene/schema/entity.ts:46-54 (ComponentScalarSchema/ComponentValueSchema/ComponentDataSchema/ComponentsSchema)",
    "packages/engine/src/scene/schema/entity.ts:89 (`components: ComponentsSchema.optional()` on SceneEntitySchema, validated at scene-parse time)",
    "packages/engine/src/scene/component-registry.ts:21-37 (applyComponents' `Klass.schema.parse(data)` runs on data that already passed ComponentDataSchema)"
  ],
  "notes": "The ceiling: `z.union([number, string, boolean, number[], string[], boolean[]])`. A GameComponent's own static `schema` CAN declare z.object() fields, but the scene-file parse rejects a nested value first, so authored JSON never carries one that far. Workaround: flatten (`targetX`/`targetY`/`targetZ` instead of `target:{x,y,z}`).",
  "evidenceHashes": {
    "packages/engine/src/scene/schema/entity.ts": "2b73fec245362168b1824ee06b820c801e7590de95ab1f11176fadad54991f21",
    "packages/engine/src/scene/component-registry.ts": "7ea93439c56fdcd1db915893ebb0f3cabfc08112dbf24c15c76df64a063713e4"
  },
  "anchor": "record-28f32a90132180e2",
  "version": "0.3"
}
#
{
  "id": "schema-record:1fd8682662ace0a62ff1",
  "area": "ingestion",
  "status": "supported-with-tiers",
  "claim": "Unmodified OSS PixiJS games run via the world2d seam: manifest 'iframe-reachable' + bundleUrl — in-realm capture, editor edits, overlay persistence. extraDeps must be registry-known (unknown throws); capture failure degrades loudly.",
  "evidence": [
    "docs/BACKBONE-TASKS.md:389-414"
  ],
  "notes": "Track P shipped 2026-07-03; proven: bubbo-bubbo/puzzling-potions/flappy-pixi. Tiers/limits: docs/CAPABILITY-TIERS.md, docs/PIXI-INGEST-LANDING-DESIGN.md.",
  "evidenceHashes": {
    "docs/BACKBONE-TASKS.md": "206ce2818efcf2b12876160d7366d41a6afec6b545b025a98a3fcf2915cdf824"
  },
  "anchor": "record-1fd8682662ace0a6",
  "version": "0.3"
}
#
{
  "id": "schema-record:d3aa6e5a0eecdfe44048",
  "area": "ingestion",
  "status": "supported-with-caveats",
  "claim": "Unmodified native-React DOM games run via the manifest `ingest-react` identity: vendored byte-for-byte (vendor/react-games/, zero-diff CI), mounted through the react world stack under the host React 19 (deduped). Embed-only in v1 — hosted, sized, disposed; NO authoring (the editor never writes JSX back into an unmodified game, D-N4).",
  "evidence": [
    "docs/BACKBONE-TASKS.md:415-435 (Track N, N0-N4 all done)"
  ],
  "notes": "Scope is native-DOM React ONLY (D-N1): R3F/@pixi/react games are canvas games and ride the three.js/pixi seams instead. Generality limit: ONE proven game (react-rpg — menu-to-dungeon e2e under React 19; both game-2 candidates rejected on evidence, R-N7). Game deps must be host-installed root deps (D-N6). Open R-N6: vendored react games' raw window listeners bypass the play-mode input gate. Design: docs/REACT-INGEST-LANDING-DESIGN.md.",
  "evidenceHashes": {
    "docs/BACKBONE-TASKS.md": "206ce2818efcf2b12876160d7366d41a6afec6b545b025a98a3fcf2915cdf824"
  },
  "anchor": "record-d3aa6e5a0eecdfe4",
  "version": "0.3"
}
#
{
  "id": "schema-record:2ba10ebaae2b8e95b615",
  "area": "summary",
  "status": "supported",
  "claim": "For contrast, the engine DOES support: discrete Rapier bodies (fixed/kinematic/dynamic) with triggers; phase-ordered GameComponents; Zod-validated scene/prefab JSON; masked layered animation state machines with blend trees; boolean+thresholded-analog input actions; direct (unwrapped) Colyseus multiplayer.",
  "evidence": [
    "packages/engine/schemas/engine-api.json (auto-generated positive/imperative-surface manifest beside this file)"
  ],
  "notes": "This file exists for negatives engine-api.json can't express (e.g. 'parses but does nothing'). For the full positive surface, read engine-api.json/.md — regenerated by `npm run generate-engine-manifest`, can't drift.",
  "evidenceHashes": {
    "packages/engine/schemas/engine-api.json": "9cdf401821aaa4065a32eb0c042c3962e27a9bb76b017ee6ab5a282ab4c7c004"
  },
  "anchor": "record-2ba10ebaae2b8e95",
  "version": "0.3"
}