DevTools
@g2w/devtools is a read-only runtime inspector: a small overlay panel that lives in the corner of your page while you develop, showing what your game is actually doing right now — its scenes, objects, transforms, frame performance, watched input, and a bounded runtime log.
It is development-only by design. The overlay is opt-in, dynamically imported, and never ships in a production build — the demo boots it behindimport.meta.env.DEV, so the chunk is not even fetched in a production bundle.

The hello-world demo with the overlay open in the bottom-right corner.
What it shows
The panel is split into six read-only sections, each built from the public g2w APIs you hand it at construction time:

- Scene Explorer — every registered scene name and which one is currently active, from
SceneManager's public surface. - Objects — the game objects currently in the collection you passed in, each with a positional label (
#0,#1, …) derived from insertion order. Click a row to inspect it. - Transform Inspector — the five public fields of the selected object's
Transform2D:x,y,rotation,scaleX,scaleY. - Performance — average FPS and frame time over a 120-frame window, computed from the overlay's own frame loop. It never adds a second game loop.
- Input monitor — pointer position and which watched keys and pointer buttons are currently held, polled from your
InputState. - Runtime log — a bounded log (200 entries by default, 50 rendered) you can write to with
devtools.log(level, message).
Enabling it
DevTools observes whatever you give it and nothing more — wire it up in your composition root, guarded so production builds exclude it entirely:
// Dev-only runtime inspector, opt-in and dynamically imported so production
// builds exclude it entirely.
if (import.meta.env.DEV) {
const { createDevTools } = await import("@g2w/devtools");
const devtools = createDevTools({ scenes, objects: sparks, input });
devtools.open();
}Every source is optional; DevTools reports a section as empty or"unsupported" when you don't provide it, rather than inventing data. The object list and input monitor only work if you passobjects and input.
Options
| Option | Type | Default | Description |
|---|---|---|---|
scenes | SceneManager | — | Scene explorer source: scene names and the active scene key. |
objects | GameObjectCollection | () => GameObject[] | — | Object list source, read through the collection's snapshot accessor. |
input | InputState | — | Input monitor source, polled on the watched keys and buttons. |
watchKeys | string[] | WASD, arrows, Escape | Key codes the input monitor polls. InputState has no key enumeration, so polling is explicit. |
watchButtons | number[] | [0, 1, 2] | Pointer button indexes the input monitor polls. |
title | string | "g2w DevTools" | Header title of the overlay panel. |
logLimit | number | 200 | Runtime-log capacity; the oldest entries are dropped first. |
refreshHz | number | 10 | Panel refresh rate in hertz. The frame loop itself runs every frame. |
document | Document | global document | Injectable for deterministic tests. |
scheduler | DevToolsScheduler | rafScheduler() | Frame source for the overlay loop, injectable for deterministic tests. |
API
createDevTools(options) returns a DevTools instance with three lifecycle methods and a small read-write surface:
open()/close()— show and hide the overlay. The frame loop only runs while open.dispose()— terminal and idempotent: removes the overlay, cancels the overlay frame loop, and clears the log buffer. It never disposes the game, the renderer, scenes, input, or any shared resource — the runtime outlives DevTools.select(index | null)— pick which object row the Transform Inspector shows.log(level, message)— append a runtime-log entry ("info","warn", or"error").
What DevTools will never do
The package is built around one rule, enforced by its tests: nothing mutates the game. DevTools holds references and reads them through immutable snapshots of the public API — it never reads private fields, never writes state, never disposes your runtime, and its frame loop only ever refreshes the overlay. Information the model does not expose is reported as null or"unsupported".
#0, #1, … reflect the collection's current insertion order and shift when objects are added or removed. g2w has no stable object IDs, so DevTools does not invent them.