Skip to content

React adapter roots

A React root is an entry in vgai.game.json.roots whose adapter is react. It mounts as a DOM layer in the same z-ordered host stack as gameplay canvases:

A React adapter root flows from its JSX entry through the automatic GameProvider into the z-ordered host stack
A React root uses the same declared composition and lifecycle as canvas roots; JSX remains its authored document.
vgai.game.json (excerpt)
{
"manifestVersion": 2,
"roots": [
{ "id": "main", "adapter": "threejs", "scene": "scenes/level.vscn.json" },
{ "id": "menu", "adapter": "react", "entry": "src/menu.tsx", "zOrder": 10 }
]
}

The entry module default-exports a component. The host wraps it in the engine GameProvider, so it can subscribe to live state without a local provider shim:

src/menu.tsx
import { useGameState } from '@engine/react/game-state';
import { Health } from './scripts/components/health';
export default function Menu() {
const hp = useGameState((game) => game.queryByComponent(Health)[0]?.hp ?? 0);
return <button style={{ pointerEvents: 'auto' }}>HP: {hp}</button>;
}

A React root has no scene file. The editor derives its hierarchy from stable OID instrumentation in the served TSX, and inspector edits write back to JSX. React nodes do not host GameComponents; behavior lives in gameplay roots and the React tree renders from shared game state.

The manifest composer mounts and disposes React with every other root. Layers are click-through by default; interactive elements opt in with pointer-events: auto.