Skip to content

Add a React root β€” JSX as truth, live game state, source write-back

tutorial lesson Intermediate ⏱ 12 min vgai 0.1.0

Prerequisites: Build a multi-world game

What you'll learn

  • Declare React roots (entry .tsx modules) in the manifest root list
  • Read live game state in a react world with useGameState β€” zero polling
  • Edit a JSX style from the inspector and watch it write back to the .tsx source
  • Opt interactive elements into clicks with pointer-events auto

What you'll build: A threejs world with a live-score React HUD world and an interactive React menu world stacked above it.

Walkthrough β€” Add a React root β€” JSX as truth, live game state, source write-back Β· generated by site/media/lessons/learn-reactworld.lesson.ts (5 steps)

React is a first-class adapter root: an entry with "adapter": "react" mounts as its own DOM layer in the host stack, z-ordered beside 3D and 2D canvases. A React root has no scene file β€” JSX source is the authoritative document, and the editor works directly against it. In this lesson you add two React roots to a 3D game: a HUD that displays a live score, and a menu with a clickable button. (Concept reference: React worlds.)

  1. Press Play. The threejs world renders on its canvas; both react worlds mount as transparent DOM layers above it. The HUD’s Score: counter ticks live β€” driven by useGameState reading the Ticker component in the 3D world.

    Score HUD and menu button rendered as DOM layers over the 3D world
    React worlds are DOM layers in the same host stack β€” no canvas, no scene file.
  2. Read the hierarchy. The native React group contains Hud and Menu, and beneath them the JSX elements as OID-derived nodes β€” span and button β€” named Component:tag from instrumentation of the served .tsx.

    Hierarchy showing world:hud (react) and world:menu (react) with JSX element nodes
    The hierarchy is derived from the JSX β€” component:tag nodes, no scene tree.
  3. Select the HUD’s span. The inspector shows its JSX style props (color, font size, spacing…). There is no scene document behind this panel β€” you are inspecting the .tsx source.

  4. Edit the color. Change the span’s color and the edit writes back into hud.tsx on disk β€” a real source edit (you’ll see it in git), not an overlay or scene change. Reload and press Play again: the rewritten source now drives the HUD to the new color β€” no in-memory illusion, the .tsx file is what changed.

    After reload and replay the HUD renders in the new color persisted to hud.tsx
    Style edits land in the JSX source β€” reload, and the source drives the new color.
  5. Click the menu button. React world layers have pointer-events: none by default; interactive elements opt back in with pointer-events: auto. The button takes clicks, while clicks on empty layer space fall through to the worlds below.

Recap

New functionality

  • Mounted two react worlds (HUD + menu) as DOM layers over a 3D world
  • Read live game state in the HUD via useGameState β€” no polling
  • Edited a JSX style in the inspector and saw it write back to hud.tsx
  • Clicked a pointer-events: auto button while empty space fell through

New concepts & skills

  • adapter: react makes React a root-list peer of threejs/pixijs
  • JSX is truth β€” no scene file; the editor derives hierarchy from OID instrumentation
  • the host auto-wraps React roots in GameProvider
  • layers default to pointer-events: none; interactive elements opt in

Next lesson β†’ React worlds (manual)

On Your Own!

Extend what you built:

  • Add a second stat to the HUD read from another component via useGameState
  • Edit the button's className in the inspector and diff hud.tsx/menu.tsx in git
  • Give the menu a Resume button that calls game.play.resume() β€” pair it with the play-control lesson