API reference

Every public class, method, and event in @codexo/exojs. Generated from source.

C

classScene

@codexo/exojs / core / stable

A scene's lifecycle host. Subclass to define scene behavior: class GameScene extends Scene { override init(): void { ... } override update(delta: Seconds): void { ... } override draw(context: RenderingContext): void { ... } } `Data` is this scene's activation-data type - the value passed to Scene.load and Scene.init. Scenes that need no activation data use the default: class TitleScene extends Scene { ... } A scene that needs typed data declares it through the generic: interface GameData { readonly level: number; } class GameScene extends Scene<GameData> { ... } `AppLike` (second generic, default Application) types Scene.app as the concrete Application subclass the scene runs under, so a project's own `Application` members are visible inside scene code, not just at the call site that constructs it: class AppScene<Data = void> extends Scene<Data, GameApplication> {} class TitleScene extends AppScene { ... } // this.app: GameApplication For a project whose own base scene needs `typeof app` (an already- constructed `Application` instance) rather than a named subclass, see ApplicationOf's doc for the explicit-fixed-point pattern required to avoid an unresolvable inference cycle. Scene-bound facilities (Scene.systems, Scene.loader, Scene.inputs, Scene.interaction, Scene.tweens, Scene.coroutines, Scene.audio, Scene.animations) are unavailable during construction and class-field initialization - they become available once the scene is attached and remain available through Scene.load, Scene.init, the frame hooks, Scene.unload, and Scene.destroy.

15
props
12
methods
4
events
Import
import { Scene } from '@codexo/exojs'

A scene's lifecycle host. Subclass to define scene behavior:

class GameScene extends Scene { override init(): void { ... } override update(delta: Seconds): void { ... } override draw(context: RenderingContext): void { ... } }

`Data` is this scene's activation-data type - the value passed to Scene.load and Scene.init. Scenes that need no activation data use the default:

class TitleScene extends Scene { ... }

A scene that needs typed data declares it through the generic:

interface GameData { readonly level: number; } class GameScene extends Scene<GameData> { ... }

`AppLike` (second generic, default Application) types Scene.app as the concrete Application subclass the scene runs under, so a project's own `Application` members are visible inside scene code, not just at the call site that constructs it:

class AppScene<Data = void> extends Scene<Data, GameApplication> {} class TitleScene extends AppScene { ... } // this.app: GameApplication

For a project whose own base scene needs `typeof app` (an already- constructed `Application` instance) rather than a named subclass, see ApplicationOf's doc for the explicit-fixed-point pattern required to avoid an unresolvable inference cycle.

Scene-bound facilities (Scene.systems, Scene.loader, Scene.inputs, Scene.interaction, Scene.tweens, Scene.coroutines, Scene.audio, Scene.animations) are unavailable during construction and class-field initialization - they become available once the scene is attached and remain available through Scene.load, Scene.init, the frame hooks, Scene.unload, and Scene.destroy.

Constructors1
new(): Scene<Data, AppLike>
Methods12
Rebuild this scene's root subtree from a SerializedScene produced by Scene.serialize. Existing root children are removed first, then the descriptor's children are reconstructed under Scene.root. Assets referenced by the data must already be loaded into the application's Loader (pre-load contract). Older documents are migrated to the current format; documents newer than the running engine throw. Returns this.
destroy(): void
Optional synchronous cleanup hook for ordinary objects created directly by the scene and not managed by a scene facility (facility-tracked work - systems, loader claims, input bindings, interaction observations, tweens, audio playback - is cleaned up automatically). Engine-owned scene internals are torn down separately; subclasses never need super.destroy(). Override in subclass.
Explicit per-frame rendering entry point. Override to choose what gets rendered. The default body is intentionally empty: Scene does not automatically traverse Scene.root. Auto-rendering the full hierarchy would conflict with ExoJS's "explicit instead of implicit" identity. Users decide which subtree(s) render each frame - context.render(this.root) is the recommended high-level path, but selective rendering (e.g. context.render(world) while skipping ui for a given frame) is equally valid and intentionally supported. Must be synchronous - see Scene.update. An async draw() would present incomplete frames.
Fixed-timestep logic hook. Called zero or more times per frame with a constant delta (Application.fixedTimeStep) before Scene.update, so physics and deterministic gameplay advance at a frame-rate-independent rate. Put physicsWorld.step(delta) and movement here; leave camera, UI and purely visual work in Scene.update. Default is a no-op. Override in subclass. Must be synchronous - see Scene.update.
Optional synchronous setup hook. Runs once per activation, after the Promise returned by Scene.load has fulfilled and before the scene becomes active: register scene systems, connect stable scene objects, bind input, register interaction roots, start scene audio. Override in subclass. Must be synchronous: async init() is a compile error (see Synchronous) and, for callers the type system cannot reach, a thrown lifecycle error that fails activation in **every** build. Put asynchronous setup in Scene.load, which the engine awaits before init() runs.
load(_data: Readonly<Data>): Promise<void> | void
Optional asynchronous loading hook. Runs once per activation, before Scene.init: initial asset loading, activation-data-dependent asset selection, remote/storage reads, or any other work that must complete before synchronous setup. Reach the loader via this.loader (scene lifetime) or this.app.loader (app lifetime). Override in subclass.
Serialize this scene's structural root subtree to a plain, JSON-able SerializedScene descriptor. Captures **data, not behaviour**: structure, transforms, visuals and asset references - never update logic, signal handlers, tweens or systems. When the scene is attached to an Application, texture/asset references resolve to their Loader source keys. Reattach behaviour in code after Scene.deserialize.
track(item: T): T
Register a Destroyable to be destroyed automatically when this scene ends permanently (reverse registration order). Returns its argument for fluent capture: const world = this.track(new PhysicsWorld()).
unload(): Promise<void> | void
Optional asynchronous teardown hook for a scene that completed activation successfully and is ending permanently. Use the loader to release assets that are scene-private and not shared with a scene that remains active. Not called for a scene that never completed activation (see the definition spec's failed-activation cleanup). Override in subclass.
Per-frame logic hook. Receives the time elapsed since the previous frame. The scene-graph transforms are still authoritative - mutate positions, advance timers, drive AI here. Override in subclass. Must be synchronous - see Scene.init for the contract and Synchronous for why. The frame path never awaits a hook result, so an async override would drop its timing and swallow its errors.
Properties15
animations: SceneAnimations
Scene-bound animation facade. An AnimatedSprite handed to this.animations.add(...) follows this scene's pause, retention and teardown instead of running for as long as it is attached to the tree. Throws if accessed before the scene is attached to an Application.
The Application this scene is attached to. The framework attaches a scene before any lifecycle hook (load/init/update/draw) runs, so scene code can read this.app inside those hooks without a null guard - consistent with Scene.inputs/Scene.tweens/Scene.loader. Throws if accessed before the scene is attached (e.g. in a constructor). Use Scene.attached for the rare "is it attached yet?" check that must not throw.
attached: boolean
true once the scene is attached to an Application - a non-throwing lifecycle probe (see Scene.app).
audio: SceneAudio
Scene-bound audio facade. Playback started via this.audio.play(...) is automatically stopped when the scene ends permanently - no manual cleanup required. Throws if accessed before the scene is attached to an Application.
coroutines: SceneCoroutines
Scene-bound coroutine facade over app.coroutines. Work queued via this.coroutines.queue(...) stops advancing while the scene is paused or suspended, resumes exactly where it left off, and is cancelled when the scene ends permanently - no manual cleanup required. Throws if accessed before the scene is attached to an Application.
inputs: SceneInputs
Scene-bound input facade. Bindings created via this.inputs.onTrigger(...) etc. are automatically unbound when the scene ends permanently - no manual cleanup required. Throws if accessed before the scene is attached to an Application.
interaction: SceneInteraction
Scene-bound interaction facade. this.root and a materialized this.ui are attached automatically; use this.interaction.observe(root) for any additional root that needs pointer/focus routing. Observations are detached automatically when the scene ends permanently. Throws if accessed before the scene is attached to an Application.
lifecycleSignal: AbortSignal
Aborted the moment this scene's permanent teardown begins - before Scene.unload is called, and also on the paths where unload() never runs at all (a failed activation, a preload cancelled before it was ever consumed, Application.destroy). Pass it to anything that takes an AbortSignal - fetch() above all - so work started in Scene.load stops when the scene goes away instead of resolving into a torn-down scene. The abort reason is the standard AbortError DOMException, so a fetch() given this signal rejects exactly as it would for any other abort. This is what keeps teardown bounded: Application.destroy() waits a fixed grace period for scene teardown and then proceeds without it. A scene whose asynchronous work watches this signal settles well inside that window; one that ignores it can be abandoned mid-teardown.
loader: SceneLoader
Scene-scoped claim view over the application Loader. Assets claimed via this.loader.get/load(...) are held under this scene's own claim scope and released automatically when the scene ends permanently - scene-private assets are evicted on unload with zero manual bookkeeping. App-lifetime assets stay on app.loader. Throws if accessed before the scene is attached to an Application.
paused: boolean
true while this scene is paused - only meaningful while Scene.state is Active; freezes fixedUpdate/update but not draw. Read-only - see SceneDirector.pause/SceneDirector.resume. Throws if accessed before the scene is attached to an Application.
Structural root container for this scene's hierarchy. Scene.root is an **ownership and traversal anchor**, not an automatic render-authoritative root. The framework never calls root.render(backend) for you. Scene.draw(context) is the explicit orchestration point - see Scene.draw. The root exists eagerly so addChild / removeChild can proxy to a known container, and so transform/bounds traversal has a stable parent. Selecting what to render each frame remains the scene's responsibility.
This scene's current lifecycle state. Read-only - state changes only in response to director-driven lifecycle events, never by direct assignment. Throws if accessed before the scene is attached to an Application.
Scene-bound system registry. Add tickable Systems (e.g. a physics world) via this.systems.add(world); each participates in the scheduler phases it implements (fixedUpdate/update/draw, ascending order) and is destroyed with the scene - no manual step() / destroy() wiring. Throws if accessed before the scene is attached to an Application.
tweens: SceneTweens
Scene-bound tween facade. Tweens created via this.tweens.create(...) are automatically stopped when the scene ends permanently - no manual cleanup required. Throws if accessed before the scene is attached to an Application.
Scene-bound UI layer, rendered screen-fixed on top of the scene content (after Scene.draw). Lazily created and destroyed with the scene; add widgets via this.ui.addChild(...). Unlike Scene.root, the UI layer **is** auto-rendered each frame - a first-class overlay that always sits above the world. Its children live in screen space (origin top-left, 0..width × 0..height); pointer and keyboard input route to them ahead of the world layer.
Events4
Dispatched after this scene becomes Active - a fresh activation (Ready → Active) or a retention restore (Suspended → Active). Exceptions thrown by a listener are isolated: reported through Application.onError, never propagated back to whatever triggered the activation, and never able to block the remaining listeners or the activation itself.
Dispatched after this scene's Scene.paused flag is set. Same event as SceneDirector.onPause, exposed directly on the scene for convenience, and the same exception-isolation contract as Scene.onActivate.
Dispatched after this scene's Scene.paused flag is cleared. Same event as SceneDirector.onResume, exposed directly on the scene for convenience, and the same exception-isolation contract as Scene.onActivate.
Dispatched after this scene is suspended for retention (Active → Suspended). Same exception-isolation contract as Scene.onActivate.
Source