MotionScript

@motion-script/core


@motion-script/core / Precomp

Class: Precomp

Defined in: runtime/precompisition.ts:367

Runs offline build passes over a project's scenes before/while it plays.

Each scene is driven through its generator (without rendering) to learn its frame count, asset usage, audio, and per-node lifespans — all scene-local. ensureScene is the unit of work and memoizes, so every entry point below is a different scheduling policy over the same passes:

  • run — every scene, synchronously. Blocks until the whole project is measured; used by callers that have nothing to show until then.
  • runAsync — every scene, time-sliced, publishing a growing result as each one lands. This is the interactive path: the player renders frame 0 after scene 0 rather than after scene n.
  • runUntil — stops as soon as a caller has what it needs (a screenshot at frame f only needs the scenes up to the one owning f).
  • replaceScene — re-runs one scene and reuses every other scene's cached pass, which is what makes scene-level hot reloading cheap.

The sequential invariant

Scenes must be measured in order, starting from 0, and a scene must be fully measured before anything else drives its generator. Precomp and StateEvaluator share the same Scene instances and precompSceneSteps calls scene.reset(), which would tear down a tree the evaluator is live on. Ordering is what keeps them apart: a frame inside scene k is not addressable until scenes 0..k-1 have durations, so the evaluator cannot reach a scene the background pass has not already finished with.

run/runAsync/replaceScene each return a fresh immutable PrecompResult the PlaybackController swaps in; the per-scene passes behind them are cached on the instance.

Constructors

Constructor

new Precomp(scenes, viewport, fps, assets, measureScope, options?): Precomp

Defined in: runtime/precompisition.ts:385

Parameters

scenes

Scene[]

viewport

Size2D

fps

number

assets

AssetCatalog

measureScope

MeasureScope

options?

PrecompOptions = {}

Returns

Precomp

Accessors

globals

Get Signature

get globals(): ProjectGlobals | undefined

Defined in: runtime/precompisition.ts:415

The project's global audio + layers, or undefined when none were supplied. Hand this to the StateEvaluator so playback draws the same layer instances this pass measured.

Returns

ProjectGlobals | undefined


measuredCount

Get Signature

get measuredCount(): number

Defined in: runtime/precompisition.ts:420

How many scenes have been measured so far.

Returns

number


sceneList

Get Signature

get sceneList(): readonly Scene[]

Defined in: runtime/precompisition.ts:406

The scene list this precomp drives (kept in sync by replaceScene).

Returns

readonly Scene[]

Methods

ensureScene()

ensureScene(index): ScenePrecomp

Defined in: runtime/precompisition.ts:433

Measure scene index if it hasn't been already, and return its pass.

The one place a scene's generator is actually driven, and idempotent: a second call is a cache read. Every other entry point is a policy for choosing when to call this.

Parameters

index

number

Returns

ScenePrecomp


replaceScene()

replaceScene(prev, index, newScene): PrecompResult

Defined in: runtime/precompisition.ts:578

Re-run a single scene and produce a fresh result that reuses every other scene's cached pass. The replaced scene's new frame count shifts all downstream startFrames and re-merges the global asset map; nothing about the untouched scenes is recomputed.

Parameters

prev

PrecompResult

The current result whose other scenes are reused.

index

number

Index of the scene to re-run.

newScene

Scene

The edited scene instance to swap in at index.

Returns

PrecompResult


run()

run(): PrecompResult

Defined in: runtime/precompisition.ts:484

Execute a build pass over every scene and assemble the complete result.

Synchronous and unbounded — for a long project this occupies the thread until the last scene finishes. Prefer runAsync anywhere a UI is waiting. A scene that throws is recorded in buildErrors rather than aborting the whole pass, so other scenes still precomp.

Returns

PrecompResult


runAsync()

runAsync(options?): Promise<PrecompResult>

Defined in: runtime/precompisition.ts:517

Measure every scene in order, yielding to the event loop so the page stays responsive, and publishing a fresh result each time a scene lands.

The yield points are complete frame boundaries only — the frame loop mutates the scene tree, so suspending mid-frame would expose a torn state to whatever runs next. isCancelled is re-checked as the first thing after every resume, before touching anything, so an abandoned pass can never mutate state a newer one has moved past.

Parameters

options?

RunAsyncOptions = {}

Returns

Promise<PrecompResult>

the final result, or the last partial one if cancelled.


runUntil()

runUntil(done): PrecompResult

Defined in: runtime/precompisition.ts:498

Measure scenes in order until done is satisfied, then assemble what is known. Scenes past the stopping point appear as unmeasured placeholders, so the result's totalFrames covers only what was actually measured.

Parameters

done

(index, precomp) => boolean

Called with the index just measured and its pass; return true to stop. Not called for scenes served from cache misses only — it sees every scene the loop touches, cached or not.

Returns

PrecompResult