ReadonlyctxReadonlysceneReadonlycacheActive camera. Defaults to the first Camera found on a root GameObject when the first frame runs; can be set explicitly.
When false, the per-frame loop skips scene.update(dt) — the engine
renders the scene but never advances its simulation. Use this for a
secondary view that shares another engine's Scene (e.g. an editor
Game view): the primary engine owns simulation, and the secondary engine
renders the same GameObjects render-only, so the scene is stepped exactly
once per frame instead of once per engine. scene.updateRender still runs
so this engine's camera sees up-to-date world matrices.
Asset resolver supplying things the runtime can't build itself — glTF meshes, material/assembly references — for instantiateAssembly and friends. A game sets this once (e.g. a manifest/fetch resolver). Left null, only assemblies of primitive meshes + inline materials build fully.
When true (default), _bucketScene frustum-culls the opaque and
transparent draw lists against the active camera so off-screen meshes are
never submitted to the lit/geometry passes. Shadow casters are kept
complete here and culled per-cascade inside the shadow pass instead.
Number of mesh renderers culled from the visible lists on the most recent frame (diagnostic; resets each frame).
Active WebXR session, or null for ordinary single-view rendering. Set via
enterXR; cleared when the session ends. While set, the engine's
frame loop is driven by the headset compositor, not window.
The XRFrame currently being rendered, valid only during a WebXR frame
(set at the top of frameXR, cleared after). Read it from a
beforeFrame hook to drive XrControllers.update or query poses.
ReadonlyframeEmitted at the top of each frame, before features update — see beforeFrame.
ReadonlyframeEmitted at the bottom of each frame, after graph execute — see afterFrame.
ReadonlygraphEmitted while a fresh render graph is being built — see beforeRender.
Host-provided handler that swaps the running scene for another project scene (by file name or asset guid). The engine itself can't resolve a project's scene files / assets — that's the editor's or standalone player's job — so each host registers this when it boots. Game code calls loadProjectScene; it stays null (a no-op with a warning) outside a hosted run.
Simulation clock, advanced each frame before scene.update. Set
engine.time.scale to pause (0) or slow/speed up gameplay. Shorthand for
Scene.time.
The most recently built RenderGraph. Useful for the graph-viz overlay; do not mutate.
The most recently compiled graph. Useful for the graph-viz overlay.
The shared audio engine for this engine instance, created on first access (so a project that never plays sound never spins up a Web Audio context). AudioSource/AudioListener components resolve their engine through here, and the scene-runtime component factory builds them against it.
All registered render features, in execution order (read-only). For tooling — e.g. a dev HUD that enumerates and toggles active effects.
Instantiate an AssemblyDoc into the scene (synchronously) and return
the live instance root. Adds the root to scene unless opts.parent
is given (then it's parented there instead). Use
instantiateAssemblyAsync for assemblies that reference other
assemblies — those links need the async path to resolve.
Async instantiateAssembly that resolves nested / referenced assemblies through assetResolver (and any asset-backed components).
Async loadScene that resolves scene-node / nested assembly links.
Switch the running game to another project scene at runtime, by scene file
name (e.g. 'level') or asset guid. Works in editor Play and standalone
builds via the host-registered sceneSwitcher; a no-op (logged) when
no host is present. The current scene's components are torn down (their
onDetach fires) and the target scene is loaded + started in its place.
StaticcreateCreate and bootstrap an engine. Awaits the RenderContext, the
render preset (which typically registers built-in features), and setup() on
every registered feature.
Add a RenderFeature. Runs its setup immediately (sync features
complete here; async ones are awaited before the next frame builds). The
cached graph is invalidated since the feature roster changed.
Returns the result of feature.setup: a Promise when the feature's setup
is async, otherwise undefined. Callers that need the feature's owned passes
before the next frame (e.g. to configure them synchronously) should
await engine.addFeature(...); otherwise the return value can be ignored.
Like addFeature, but inserts the feature immediately before the
already-registered feature named beforeName (instead of appending). Use
this to splice a feature into a preset-built pipeline at the right slot —
e.g. adding an anti-aliasing resolve just before TonemapFeature. Falls
back to appending when beforeName isn't registered.
Remove a feature by name (no-op if not present). Disposes the feature.
Lookup a feature by name. Returns null if not registered.
Lookup a feature by name and throw if not found.
Iterate the registered features in registration order.
Toggle whether a feature contributes to the frame. Invalidates the cached graph so the next frame rebuilds without the disabled feature.
Find a registered pass by its Function.name. Walks features and returns the first matching pass found. Convenience for the common case of tweaking pass parameters without reaching into a feature explicitly.
Run a callback at the top of each frame, before features update.
Shorthand for frameStarted.connect(cb).
Run a callback at the bottom of each frame, after graph execute.
Shorthand for frameEnded.connect(cb).
Defer a GPU-resource teardown (e.g. buffer.destroy() / model.destroy())
until the current frame's command buffer has been submitted. Frame rendering
is async (build → await execute → submit), so destroying a resource
synchronously — e.g. from a scene teardown / hot-reload that runs while a
frame is mid-flight — can free a buffer that the just-built command buffer
still references, tripping a "used in submit while destroyed" validation
error. Routing the destroy through here runs it after the submit instead.
Run a callback while a fresh graph is being built — between feature
addPasses and the final compile. Use this for one-off inline passes
that don't warrant a full feature class. Callback runs only on graph
(re)builds; when the cached graph is reused, the callback does NOT run,
so any inline pass must follow the same "execute closure reads mutable
state" pattern as a regular pass.
To make an inline pass appear/disappear per frame, wrap it in a feature
and toggle enabled via setFeatureEnabled instead.
Shorthand for graphBuilding.connect(cb).
Kept for API compatibility; the graph is rebuilt every frame, so explicit invalidation is unnecessary. No-op.
Begin the requestAnimationFrame loop. No-op if already running. Frames
after the first wait for any in-flight feature setup before kicking off
the next tick, so an async preset applied just before run() finishes
setting up before any frame work runs.
Stop whichever frame loop is running (window or XR).
Switch the engine into stereo WebXR rendering driven by xr. The frame
loop is handed off from window.requestAnimationFrame to the headset
compositor (xrSession.requestAnimationFrame), and each frame renders the
scene once per eye into the projection-layer texture. Temporal AA / motion
blur are disabled (no per-eye jitter+history yet — see
TODO/webxr-integration.md). Call inside the same user gesture that created
the XrSession. When the session ends (user exit / headset removed),
the engine automatically reverts to the window loop if still running.
Request the active XR session to end (no-op if not in XR). Cleanup runs
via the session's end event → _onXrEnded.
Stereo WebXR frame. Simulates the scene once, buckets it against the combined two-eye frustum, then renders the full pipeline per eye into that eye's viewport of the shared projection-layer texture. The camera GameObject's world transform acts as the player rig: XR eye poses are relative to it, so moving/turning the camera object is locomotion.
Tear down every feature and release the physical resource cache.
Top-level orchestration object: owns the RenderContext, Scene, the active Camera, the PhysicalResourceCache, the registered RenderFeatures, and the per-frame loop.
Per frame the engine:
ctx.update()(canvas resize detection, frame timing).scene.update(dt)) and refreshes the camera matrices.beforeFramecallbacks.feature.update(frame)on every enabled feature.feature.addPassesand then anybeforeRendercallbacks.afterFramecallbacks.The compiled graph is cached and reused as long as:
invalidate().Because passes follow the "execute closure reads mutable pass state" pattern (e.g.
pass._drawItems,pass._cameraScratch), the cached graph picks up fresh per-frame uniforms via theupdatehook without any rewiring.