Skip to content

Runtime ​

Runtime creates the renderer, world, and game loop for one canvas, then drives them. How the parts fit together is in ARCHITECTURE.md.

ts
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 ​

OptionDefaultDescription
contextundefinedTyped application context of the world.
assetsempty catalogCatalog and extra loaders. See asset options.
audioengine defaultGlobal audio service of the world.
rendererengine defaultsForwarded to ThreeRenderer.create(). An explicit output.pixelRatio or output.maxPixelRatio survives load().
loopscheduler defaultsFrameSchedulerOptions of runtime.loop, plus its idleDelay, 2000 by default.
loggerevery namespace disabledReceives the startup steps and a lost GPU device.
overlay.containertracks the canvasElement or selector hosting runtime.overlay.
includePerformanceStatsfalsetrue or an object mounts the corner HUD.
includePerformanceStats.mounttruefalse leaves the HUD unmounted.
includePerformanceStats.position"top-left"OverlayPosition of the HUD.
includePerformanceStats.inset8Distance in pixels from the canvas edges.
includePerformanceStats.panelfalsetrue or MetricsPanelOptions also mounts the readout panel.
focusCanvastrueRefocuses the canvas after any click in the page.
focusHintfalsetrue 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.inset12Distance in pixels from the canvas edges.
focusHint.text"Click to focus"Label of the hint.
viewHelperfalsetrue 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.inset0Distance in pixels from the canvas edges.
renderOnDemandfalseStops rendering while nothing changes. See rendering on demand.
suspendWhenHiddenfalseStops the loop while the canvas is off screen or inside a hidden frame. See suspendWhenHidden.

Properties ​

PropertyTypeDescription
worldWorld<WebGPURenderer, TContext>Scene manager, input, audio, context, and asset coordinator.
rendererThreeRendererSame object as world.renderer, with its concrete type.
loopGameLoopConfigure its scheduler before start() or load().
canvasHTMLCanvasElementThe resolved target.
overlayOverlayLayerHTML layer above the canvas.
managerTHREE.LoadingManagerShared by every asset loader.
statsStatsRecorderTimes every frame, with or without a HUD.
metricsRuntimeMetricsMetric registry and readout panel.
statsHudPerformanceStatsHud | nullThe corner HUD, or null when includePerformanceStats mounts none. Set its hidden to hide it without unmounting.
viewHelperViewHelperSettings | nullThe 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().
runningbooleantrue between start() and stop().
renderOnDemandbooleanThe option's value.
idlebooleantrue while on-demand rendering sleeps.

Methods ​

MethodDescription
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.

OptionDefaultDescription
sceneundefinedInitial scene, loaded before the runtime starts. It awakes on the first frame, after load() resolves.
assetsnoneExtra asset references, loaded before the scene.
maxFpsGPU estimateRender cap. Skips GPU benchmarking; Infinity removes the cap.
skipLoadingScreenfalseShows the canvas at once and ignores the two options below.
loadingDelay850Minimum milliseconds the screen shows before assets load.
loadingContainerdocument.bodyParent 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, and blur;
  • a resize of the canvas container or a device pixel ratio change;
  • the renderer's compiled event, so objects skipped while their pipelines compiled get drawn;
  • a gamepadconnected event, 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 returns true.

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.

StepLogged by
catalogcreate()
renderercreate()
statscreate(), with includePerformanceStats
deviceload()
assetsload()
sceneload(), 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.