Example: Product description and code¶
Manifest row 17 · built today as betta-product-description
A white brand mark (invisible on the reference's white ground) over a two-line uppercase product description in navy, over the SKU in a lighter weight, all left aligned and hugging their own content. Each of the three slides in from the left while fading, staggered by four frames.
flowchart TB
subgraph scene["scene-product-description (one motion graph per ratio)"]
ROOT["pd-root<br/>flowBox column · absolute · content-sized · alignAcross left"]
LOGO["pd-logo<br/>image · flow · w 380, h content · slideFade"]
DESC["pd-description<br/>text · flow · slideFade"]
CODE["pd-code<br/>text · flow · slideFade"]
LOGO -- flowIn --> ROOT
DESC -- flowIn --> ROOT
CODE -- flowIn --> ROOT
end
The document¶
{
"id": "scene-product-description",
"durationInFrames": 75,
"layers": [
// ── Content-sized column: exactly as wide as its widest member, no fixed length here.
{
"id": "pd-root",
"type": "flowBox",
"zIndex": 1,
"layout": {
"mode": "absolute",
"16:9": { "x": 120, "y": 120, "w": "content", "h": "content", "anchor": "top-left" },
"9:16": { /* … */ }, "1:1": { /* … */ }
},
// The preset wants 23px above the description and 21px above the code. One `gap`.
"props": { "direction": "column", "alignAcross": "left", "alignAlong": "top", "gap": 22 }
},
// ── The logo: fixed width, height follows the file's aspect ratio.
{
"id": "pd-logo",
"type": "image",
"zIndex": 2,
"layout": { "mode": "flow", "16:9": { "flowIn": "pd-root", "w": 380, "h": "content" },
"9:16": { /* … */ }, "1:1": { /* … */ } },
"props": { "src": { "kind": "bundled", "path": "effects/betta-product-description/logo.png" } },
"animations": [
{ "animation": "slideFade",
"params": { "from": "left", "distance": 76, "durationInFrames": 12 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 0 } }
]
},
// ── Description: content-sized on both axes, so it never wraps by measure; the hard `\n`
// is the only break, and the box is as wide as the longer of the two lines.
{
"id": "pd-description",
"type": "text",
"zIndex": 2,
"layout": { "mode": "flow", "16:9": { "flowIn": "pd-root", "w": "content", "h": "content" },
"9:16": { /* … */ }, "1:1": { /* … */ } },
"typography": { "16:9": { "family": "GT Eesti Display", "weight": 700, "size": 56.5,
"color": "#054F8E", "tracking": 0.6, "lineHeight": 0.93,
"case": "uppercase", "horizontalAlign": "left" } },
"props": { "content": [ { "value": "509L French\nDoor Fridge" } ] },
"animations": [
{ "animation": "slideFade",
"params": { "from": "left", "distance": 60, "durationInFrames": 12 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 4 } }
]
},
// ── The SKU.
{
"id": "pd-code",
"type": "text",
"zIndex": 2,
"layout": { "mode": "flow", "16:9": { "flowIn": "pd-root", "w": "content", "h": "content" },
"9:16": { /* … */ }, "1:1": { /* … */ } },
"typography": { "16:9": { "family": "GT Eesti Display", "weight": 400, "size": 35,
"color": "#054F8E", "tracking": 0.4 } },
"props": { "content": [ { "value": "836332" } ] },
"animations": [
{ "animation": "slideFade",
"params": { "from": "left", "distance": 22, "durationInFrames": 12 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 8 } }
]
}
]
}
What a campaign would bind:
| Path | Control |
|---|---|
pd-logo.props.src |
image (the brand mark) |
pd-logo.layout.16:9.w (and per ratio) |
number |
pd-description.props.content[0].value |
multiline text, from product data |
pd-code.props.content[0].value |
text, from product data |
each typography.*.color |
colour |
What the engine does with it¶
Resolve. No prices, no relative sizes. Three at references resolve to frames 0, 4 and 8.
Each slideFade expands into an x track and an opacity track.
Solve. The logo's intrinsic size is the PNG's pixel size, scaled to 380 wide with height following. The description is measured with no width constraint: two lines, hard-broken, the box as wide as "DOOR FRIDGE". The code likewise. The column packs the three left-aligned with 22px between; its own box is the widest member by the sum of heights.
Animate. Three independent slide-fades on three nodes with no edges between them beyond flow membership, which composes nothing extra here since the column itself is still.
Place. Three elements, one an <img> sized by layout.
What this shows¶
- A content-sized column with mixed primitives — image and text — each supplying its own intrinsic size (Coordinate System → Intrinsic size).
w: 380, h: "content"on an image is the aspect-preserving auto-height that page promised.- Product data flows straight into runs: description and SKU are plain text bindings.
Stress points¶
- No per-member spacing in a
flowBox. The design wants 23px then 21px;gapis one number, there is no membermargin, and the built component uses per-partmarginTopfor exactly this. Encoded here asgap: 22, a 1px lie each way. Every component in the catalogue with more than two rows has this (Positioning → flowBox vocabulary). - Named-animation distances relative to the layer's own size have no unit. The built entrance
is
distancePercent: 20— a fifth of the part's own width.targetFractionis relative to a target or container box, never to self, so the px values above (76, 60, 22) are 20% of each layer's expected width worked out by hand and go stale the moment a binding changes the copy (Coordinate System → targetFraction, Keyframe Animation → named animations). AselfFractionunit, or letting a named animation's expansion read its layer's solved box, would close this — the second is already implied by "a named animation can read the layer's resolved box" on that page, so it may only need stating as the wayslideFadegets its distance. - Hard line breaks in content-sized text are unstated. Point text "never wraps"; this layer is
content/content and carries a
\n. It obviously should break, and the width should be the widest line, but the three-shape table doesn't say so (Text Foundation → point/box consolidation). - Bindable
won a flow member is a numeric leaf inlayout, notprops. Fine under the rule as written, worth one example in the brief since every other binding shown targetsprops.