Compiled scenes

Resolving frames, reading typed exports, looking up actors, memoizing, and reflecting for editors.

CompiledScene is what createScene returns. It holds the authored record and turns frame numbers into state.

compiled.fps; // 30
compiled.totalDuration; // authored length, in frames

Resolving a frame

const state = compiled.at(90);

// Scene exports — typed
state.scene.title;

// Camera
state.camera.zoom;
state.camera.centerX;

Typed lookup

For actors that were not exported, look them up by blueprint rather than by string type. The blueprint carries the type, so no cast is needed.

state.findActor(TextBlock); // first instance
state.findActors(TextBlock); // all instances
state.getActor("title", TextBlock); // by id, typed

Prefer exports

A lookup is a search; an export is a name. Return the actors that matter from the scene generator and the call sites stay refactor-safe.

Resolution options

Pass host values at resolution time rather than baking them into the scene.

const state = compiled.at(frame, {
  channelValues: new Map([[createCellKey(actorId, "measuredBox"), box]]),
  viewport: { width: 1920, height: 1080 },
});

channelValues overrides are per-resolution only — they never write through to the channel publication store, which is what makes them safe to compute inside a React render.

Memoization

memoizedScene(compiled) wraps at() with an LRU keyed on (frame, viewport) and invalidated per channel key: publishing to channel A does not bust a cached frame that only read channel B.

const memo = memoizedScene(compiled, { lru: 4 });
const state = memo.at(frame);

SceneRenderer uses it by default.

Reflection

compiled.reflect(frame?) returns editor-facing data — ids, types, tree structure and signal values — without needing a typed blueprint. This is the surface an editor or an inspector reads.

const reflection = compiled.reflect(90);
reflection.getActor("title"); // by id, untyped

ResolvedActor

What every lookup and export resolves to:

interface ResolvedActor {
  id: string;
  type: string;
  scopeId: string;
  parentId: string | null;
  slotName: string | null;
  slotChildren: Record<string, string[]>;
  signals: Record<string, unknown>;
  channels: Record<string, ResolvedChannelHandle<unknown>>;
  localLayout: ResolvedLayoutBox;
  worldLayout: ResolvedLayoutBox;
  effects: ActiveEffect[];
  spawnFrame: number;
  despawnFrame?: number;
}

Do not read signals by string key

signals and channels exist for reflection and tooling. In application and renderer code the blueprint is known, so use scene exports or findActor(Blueprint) — reaching into signals["opacity"] throws away the types the runtime went to trouble to give you.

On this page