Runtime
Runtime creates the renderer, world, and game loop for one canvas, then drives them. How the parts fit together is in ARCHITECTURE.md.
const runtime = await Runtime.create("canvas", {
assets: {
catalog: new URL("assets.json", document.baseURI)
}
});
await runtime.load({
scene: new GameScene()
});Runtime.create(target, options?)
target is an HTMLCanvasElement or a CSS selector. The promise rejects when the selector matches nothing or a non-canvas element, when the asset catalog cannot be resolved, or when the renderer fails to initialize.
Options
| Option | Default | Description |
|---|---|---|
context | undefined | Typed application context of the world. |
assets | empty catalog | Catalog and extra loaders. See asset options. |
audio | engine default | Global audio service of the world. |
renderer | engine defaults | Forwarded to ThreeRenderer.create(). An explicit output.pixelRatio or output.maxPixelRatio survives load(). |
loop | scheduler defaults | FrameSchedulerOptions of runtime.loop, plus its idleDelay, 2000 by default. |
logger | every namespace disabled | Receives the startup steps and a lost GPU device. |
overlay.container | tracks the canvas | Element or selector hosting runtime.overlay. |
includePerformanceStats | false | true or an object mounts the corner HUD. |
includePerformanceStats.mount | true | false leaves the HUD unmounted. |
includePerformanceStats.position | "top-left" | OverlayPosition of the HUD. |
includePerformanceStats.inset | 8 | Distance in pixels from the canvas edges. |
includePerformanceStats.panel | false | true or MetricsPanelOptions also mounts the readout panel. |
focusCanvas | true | Refocuses the canvas after any click in the page. |
focusHint | false | true or an object shows a hint while the canvas has no focus. Pair it with focusCanvas: false, or the hint only flashes. |
focusHint.position | "top-center" | OverlayPosition of the hint. |
focusHint.inset | 12 | Distance in pixels from the canvas edges. |
focusHint.text | "Click to focus" | Label of the hint. |
viewHelper | false | true or an object draws a 128 px axis gizmo for the camera with the lowest depth. Display only. |
viewHelper.position | "bottom-right" | "top-left", "top-right", "bottom-left" or "bottom-right". |
viewHelper.inset | 0 | Distance in pixels from the canvas edges. |
renderOnDemand | false | Stops rendering while nothing changes. See rendering on demand. |
suspendWhenHidden | false | Stops the loop while the canvas is off screen or inside a hidden frame. See suspendWhenHidden. |
Properties
| Property | Type | Description |
|---|---|---|
world | World<WebGPURenderer, TContext> | Scene manager, input, audio, context, and asset coordinator. |
renderer | ThreeRenderer | Same object as world.renderer, with its concrete type. |
loop | GameLoop | Configure its scheduler before start() or load(). |
canvas | HTMLCanvasElement | The resolved target. |
overlay | OverlayLayer | HTML layer above the canvas. |
manager | THREE.LoadingManager | Shared by every asset loader. |
stats | StatsRecorder | Times every frame, with or without a HUD. |
metrics | RuntimeMetrics | Metric registry and readout panel. |
statsHud | PerformanceStatsHud | null | The corner HUD, or null when includePerformanceStats mounts none. Set its hidden to hide it without unmounting. |
viewHelper | ViewHelperSettings | null | The axis gizmo's resolved position and inset, or null without the viewHelper option. Setting its hidden requests a frame and lasts across stop() and start(). |
running | boolean | true between start() and stop(). |
renderOnDemand | boolean | The option's value. |
idle | boolean | true while on-demand rendering sleeps. |
Methods
| Method | Description |
|---|---|
load(options?) | Runs startup, then start(). See loading and startup. |
start() | Attaches the focus listener, focus hint, and view helper, connects the world, and starts the loop. Idempotent. |
stop() | Reverses start(). Idempotent, and called when input requests an exit. |
dispose() | Stops, then removes the HUD, readout panel, and overlay layer and disposes the world. Do not reuse the runtime. |
nextFrame() | Requests a frame and resolves once a frame has rendered and emitted afterUpdate. Never resolves while stopped. |
frames(count) | Awaits nextFrame() count times. |
compiledFrame() | Awaits nextFrame(), then, while the renderer has pipelines compiling, waits for them and awaits another frame. Resolves once a frame has drawn every object. Never resolves while stopped. |
mountMetricsPanel(options?) | metrics.mountPanel() with the world keyboard as keyboard. |
Loading and startup
load() configures the device, loads startup assets and the initial scene behind a loading screen, then calls start(). The step order is in ARCHITECTURE.md and the screen is covered by the loading screen guide.
| Option | Default | Description |
|---|---|---|
scene | undefined | Initial scene, loaded before the runtime starts. It awakes on the first frame, after load() resolves. |
assets | none | Extra asset references, loaded before the scene. |
maxFps | GPU estimate | Render cap. Skips GPU benchmarking; Infinity removes the cap. |
skipLoadingScreen | false | Shows the canvas at once and ignores the two options below. |
loadingDelay | 850 | Minimum milliseconds the screen shows before assets load. |
loadingContainer | document.body | Parent of the loading screen. |
A failing step rejects with its Error, which the loading screen also displays. The runtime stays stopped.
Rendering on demand
With renderOnDemand: true, the loop sleeps once no frame is owed and two seconds (loop.idleDelay) have passed since the last frame request. The GameLoop page explains the trailing frames, idle delay, and wake-up delta. While started, the runtime requests frames on:
- keyboard, pointer, wheel, and drag-and-drop events in the page;
- window
resize,focus, andblur; - a resize of the canvas container or a device pixel ratio change;
- the renderer's
compiledevent, so objects skipped while their pipelines compiled get drawn; - a
gamepadconnectedevent, or a held button or stick on a connected gamepad, sampled once per animation frame while idle without rendering; - every frame after which a key, button, or touch is still held, or a
world.keepAlive()predicate returnstrue.
Any other change to what is drawn must call world.invalidate(). The HUD shows an IDLE badge while idle is true. The runtime calls stats.skipGap() whenever the loop starts or wakes, so the idle time never shows up as an FPS drop.
Startup tracing
logger records each step as a Logger.step: <step> started, then <step> done with ms or <step> failed with error, on the logger's own namespace.
| Step | Logged by |
|---|---|
catalog | create() |
renderer | create() |
stats | create(), with includePerformanceStats |
device | load() |
assets | load() |
scene | load(), with scene; meta scene holds its name |
Once started, an enabled logger writes waiting for first frame with visibility (document.visibilityState), then first frame. A missing first frame next to visibility: "hidden" explains a scene that never woke.
When the renderer emits deviceLost, the logger writes an error with api, message and reason. The canvas stays blank until the page reloads.