@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
tracker
Returns
TrackMeasureScope
Overrides
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
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?
Italic / oblique variant. Defaults to normal.
Returns
number
Advance width in pixels.