MotionScript

@motion-script/core


@motion-script/core / TrackMeasureScope

Class: TrackMeasureScope

Defined in: render/track-measure-scope.ts:33

A MeasureScope that registers every font it's asked to measure into an AssetTracker, then delegates the actual measurement to the real scope.

This is what lets font discovery be inferred from layout()'s own measureText() calls instead of a hand-written prepareLayout declaration: Precomp.precompScene swaps this in for its dry-run layout() pass only — real playback (StateEvaluator) keeps using the real scope directly.

Precomp's dry-run measurements were never accurate to begin with: the font manager the real scope reads from starts empty and is only populated by AssetManager, strictly after the whole precomp pass completes, so a requestFont declared one line ahead of layout() never actually changed what that pass measured against — it only fed the asset timeline. This wrapper feeds the same timeline as a side effect of the measurement that was already happening, at the same (already-approximate) accuracy.

A node retains whatever MeasureScope it was last laid out with (see _lastScope in node-lifecycle.ts) so an animated add/remove can measure a detached child's natural "hug" size later, from inside the scene's own generator body — outside precomp's per-frame registry.start()/end() bracket. That's always been safe against the real scope (a stateless pure function) but isn't against this one, since requestFont requires an open frame. Self-bracket at frame 0 when called with none already open, rather than throwing — frame 0 is inert for fonts specifically (they're pinned at cacheAt: 0, discardAt: null regardless of the frame they're requested at, see buildAssetMap), so only registering at all matters, not which frame.

Extends

Constructors

Constructor

new TrackMeasureScope(real, tracker): TrackMeasureScope

Defined in: render/track-measure-scope.ts:34

Parameters

real

MeasureScope

tracker

AssetTracker

Returns

TrackMeasureScope

Overrides

MeasureScope.constructor

Methods

layoutTextBlock()

layoutTextBlock(state): TextBlockLayout | null

Defined in: render/measure-scope.ts:59

Lay state out the way it would be drawn and report where every character landed — see TextBlockLayout for the space and the caret model.

This is what makes on-canvas text editing possible: glyph positions live in the backend's shaper, so a host drawing its own caret and selection has no way to compute them, and anything it approximates in the DOM disagrees with the render as soon as the font, the line height or the wrapping does.

Takes the whole TextState rather than a handful of font fields because the resolution a caret has to agree with lives in the backend: 'autofit' picks a size from the box, wrap turns the width into a wrap limit, and textAlign places the lines within it. Handing over the same descriptor that gets drawn is what keeps the two from drifting apart.

Returns null when the backend can't measure this — the default, so a backend that never needed glyph positions keeps working, and for cases no caret model fits: text-on-path (glyphs follow a curve, not a line box) and a block with active selection segments.

Parameters

state

Partial<TextState>

Returns

TextBlockLayout | null

Inherited from

MeasureScope.layoutTextBlock


measureText()

measureText(text, fontSize, fontFamily, fontWeight?, letterSpacing?, fontStyle?): number

Defined in: render/track-measure-scope.ts:41

Returns the advance width (in pixels) of text rendered at the given fontSize with the specified font properties.

Parameters

text

string

The string to measure.

fontSize

number

Size in pixels.

fontFamily

string

CSS-style family name (e.g. "Inter").

fontWeight?

number

Numeric weight (100–900). Defaults to 400 when omitted.

letterSpacing?

number

Extra inter-glyph spacing in pixels. Defaults to 0.

fontStyle?

FontStyle

Italic / oblique variant. Defaults to normal.

Returns

number

Advance width in pixels.

Overrides

MeasureScope.measureText