@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
fps
number
assets
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
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
The current result whose other scenes are reused.
index
number
Index of the scene to re-run.
newScene
The edited scene instance to swap in at index.
Returns
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
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.