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 iframe tiers and overlay 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. Edits are stored separately as an overlay, so the game’s source stays untouched.

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

    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)
  • iframe tiers degrade gracefully; edits persist as a separate overlay (.vgai/overlays)

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.game.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": "threejs",
"ingest": { "strategy": "iframe-reachable", "entryHtml": "index.html" }
}
}
]
}

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; edits land in .vgai/overlays/ in your folder, and your game source is never touched. The strategy field is the capability declaration — iframe-reachable needs your three to be reachable in-realm (import-map builds qualify; an opaque prebuilt bundle falls back to embed-only). 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.game.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.