Ingest an unmodified three.js game
site/media/lessons/ingest-game.lesson.ts (4 steps) vgai can load a real, unmodified three.js game and edit it in-place. It doesn’t ask the game
to use a vgai API — it traps the game’s render call, reads the Scene the game hands its
WebGLRenderer, and exposes that live Object3D tree to the editor through a neutral
AuthoringAdapter. An edit is then written back to the game’s own source — a surgical literal
edit anchored by the serve-time creation-site index — because a persistence artifact that is not the
game’s own code or data is exactly what this lane refuses to invent. Where a property cannot yet be
honestly anchored, that single edit refuses with its reason rather than being stashed somewhere else.
-
Open the editor. A normal editor session. Use the
?project=three-interactive-cubeslink above to launch it in your browser (the same flow runs headlessly via the ingest dev hook).
An ordinary editor session. -
Ingest an unmodified three.js game. The link loads the upstream Interactive Cubes example — no vgai changes to its code.
Loading an unmodified three.js game. -
The foreign game runs live — via the render-accessor trap.
adapter/ingest/scene-capture.tswraps the hostWebGLRenderer.renderso the first(scene, camera)the game renders is captured. The game runs exactly as written; vgai just observes its scene.
An unmodified three.js game, running inside the editor. -
The editor panels drive the ingested tree. The captured
Object3Dtree is presented through the same neutralAuthoringAdapterthe 3D and 2D surfaces use, so the hierarchy/inspector work on a foreign game with no special-casing.
One authoring contract drives a foreign game's tree.
Recap
New functionality
- Ingested an unmodified three.js game into the editor
- Saw its live Object3D tree in the editor panels
New concepts & skills
- The render-accessor trap captures the Scene the game renders — no game-side API
- A neutral AuthoringAdapter drives the foreign tree (same contract as 3D/2D)
- An unreached capability is a standing warning, never a silent degrade; persistence follows ownership — live-only on a vendored copy, your own source edits in a folder you own
Next lesson → Loading existing games (manual)
Ingest your own folder
Section titled “Ingest your own folder”The mechanism is not vendored-games-only: the same { ingest } manifest works for a
three.js game folder that has never seen this repo. Put a vgai.project.json next to your
game:
{ "manifestVersion": 2, "name": "My Existing Game", "version": "0.1.0", "engine": { "version": "0.1.0" }, "roots": [ { "id": "main", "adapter": { "surface": "three", "ingest": { "entry": "src/main.js" } } } ]}then open the folder in the editor (npx @vgai/cli@latest edit <folder>, or the
editor’s open-project flow). The resolver mounts it through the same ingest machinery you
just used. The ingest block declares mounting FACTS only — entry names your game’s own
module entry point, and the host serves it in-realm with three deduped to the editor’s
instance; there is no route menu to pick from, and a game the capture trap cannot see fails
to mount, loudly. Persistence is ownership-based: edits to a game you own are ordinary
source edits in your files. The JSON-Schema for the manifest (autocomplete + field docs)
ships in the engine package.
Scope honesty: this bring-your-own path works for three.js, PixiJS, and React games —
declare an { ingest, surface } adapter root in your own vgai.project.json and
open the folder (React’s manifest/external-folder route is the newest
of the three). The vendored games shown in this section exist to prove the mechanism in CI,
not because any of the three kinds is vendored-only — see docs/BRINGING-AN-EXISTING-GAME.md
in the checkout for the full per-kind capability map and the adapt-vs-port decision guide.