Skip to content

Ingest an unmodified three.js game

tutorial lesson Advanced ⏱ 9 min vgai 0.1.0

Prerequisites: Loading existing games — overview

What you'll learn

  • Ingest an unmodified three.js game into the editor
  • Understand the render-accessor trap that captures its scene
  • Know how in-realm capture and ownership-based persistence work

What you'll build: An unmodified three.js game running inside the editor, captured live.

Walkthrough — Ingest an unmodified three.js game · generated by 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.

  1. Open the editor. A normal editor session. Use the ?project=three-interactive-cubes link above to launch it in your browser (the same flow runs headlessly via the ingest dev hook).

    The editor open
    An ordinary editor session.
  2. Ingest an unmodified three.js game. The link loads the upstream Interactive Cubes example — no vgai changes to its code.

    Starting the ingest
    Loading an unmodified three.js game.
  3. The foreign game runs live — via the render-accessor trap. adapter/ingest/scene-capture.ts wraps the host WebGLRenderer.render so the first (scene, camera) the game renders is captured. The game runs exactly as written; vgai just observes its scene.

    The ingested cubes game running in the editor
    An unmodified three.js game, running inside the editor.
  4. The editor panels drive the ingested tree. The captured Object3D tree is presented through the same neutral AuthoringAdapter the 3D and 2D surfaces use, so the hierarchy/inspector work on a foreign game with no special-casing.

    The ingested-game hierarchy panel
    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)

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.