Custom adapters & the conformance kit
A game that isn’t built on vgai’s first-party scene format can still run —
and be edited — inside the editor by shipping its own adapter: a module
in the game folder implementing the small GameAdapter contract (the same
seam described in the adapter seam). The editor
mounts, renders, and authors the game through it; your game keeps its own
architecture.
The one-page version
Section titled “The one-page version”- Your
vgai.game.jsondeclares a world with"adapter": { "module": "src/adapter.ts" }(game-folder-relative path; no.., no absolute paths) and explicit"capabilities": { "local": …, "hosted": … }— module worlds have no derivable tier ceiling, so you self-certify one. - The module default-exports
{ id, mount(host) }. Your manifest’skind—"threejs","pixijs", or"react"— picks the hostmount()receives and the mounted shape it returns (a realTHREE.Scene+THREE.Camerafor threejs, a real pixiContainerstagefor pixijs, the samecontainerelement it was handed for react), plus adispose()and (what makes you editable) an optionalauthoringsurface:hierarchy(required),transforms,inspector,persistence— a react adapter has notransformssurface by design (no 3D object to bind). - Your self-certified tier is checked against reality after mount
(
packages/editor/src/achieved-tier.ts): noauthoring→opaque-embed; partial →shared; hierarchy **+ transforms + inspector- persistence** →
first-party. At runtime a shortfall mounts anyway at the achieved tier with a structuredtier-shortfallwarning; in the conformance kit it’s a hard failure.
- persistence** →
- Prove it — the quick way, from a monorepo checkout:
vgai conformance /abs/path/to/your/game-folder(add--jsonfor a machine-readable report). Or call the kit directly from a vitest test in this repo:
import { runAdapterConformanceKit } from './adapter-conformance-kit';
const report = await runAdapterConformanceKit('/abs/path/to/your/game-folder');// throws a named `adapter-conformance: …` error on the first violationThe full contract — provider-by-provider assertions, the inspector probe
table, the three.js identity/dedupe rules, worked examples — lives in
docs/ADAPTER-AUTHORING-GUIDE.md
in the repo. That guide is the canonical reference; this page is the map.
What the kit checks
Section titled “What the kit checks”runAdapterConformanceKit(projectRoot) runs headless (Node, no GPU/DOM) and
walks the whole contract in order: manifest loads → module path-guarded and
imported → default export shape-checked → mount() against a headless host
matching your world’s kind (HostContext for threejs, World2DHost
for pixijs, { container, game } for react) → the mount-contract check for
that kind (threejs: scene/camera real instances; pixijs: stage a real
pixi Container; react: container is the same element handed to
mount(), plus drivesOwnLoop: false) → hierarchy roots non-empty, ids
unique, id↔object3D bridge bidirectional (threejs/pixijs — explicitly
skipped, with a logged note, for react) → transforms get/apply
round-trip, rotation is a quaternion (threejs/pixijs only, react has no
transform surface) → every non-readonly inspector field survives a
set→get round-trip (every kind) → persistence is honest (destination
named, save() resolves; every kind) → achieved tier ≥ declared →
dispose() doesn’t throw.
Trust boundary, honestly stated
Section titled “Trust boundary, honestly stated”There is no sandbox: a custom adapter module runs with full editor-realm privileges, exactly like game entry code (single-realm is a recorded decision — D5). The boundary is declaration honesty: the module path can’t escape the game folder, capabilities must be declared, and declared-vs-achieved is verified and logged. Don’t run game folders you don’t trust.