Example: Footy Finals banner¶
Manifest row 04 · built today as betta-footy-finals-banner
A small yellow label panel, FOOTY FINALS in navy, over a large red hero panel tilted 5°
anticlockwise reading BONUS TV* with the asterisk small and raised. Both panels drop a soft shadow,
wipe on from the left four frames apart, and breathe on one beat. The label is centred over the hero.
flowchart TB
subgraph scene["scene-footy-finals"]
ROOT["ff-lockup<br/>flowBox column · absolute (120,120)"]
LABEL["ff-label<br/>text · flow · pulse"]
HERO["ff-hero<br/>text · flow · rotation −5 · pulse"]
LABEL -- flowIn --> ROOT
HERO -- flowIn --> ROOT
end
The document¶
{
"id": "scene-footy-finals",
"durationInFrames": 75,
"layers": [
{
"id": "ff-lockup",
"type": "flowBox",
"zIndex": 0,
"layout": {
"mode": "absolute",
"16:9": { "x": 120, "y": 120, "w": "content", "h": "content", "anchor": "top-left" },
"9:16": { /* own x/y */ }, "1:1": { /* own x/y */ }
},
"props": { "direction": "column", "alignAcross": "centre", "gap": 14 }
},
{
"id": "ff-label",
"type": "text",
"zIndex": 1,
"layout": {
"mode": "flow",
"16:9": { "flowIn": "ff-lockup", "w": "content", "h": "content" },
"9:16": { /* … */ }, "1:1": { /* … */ }
},
"typography": {
"16:9": { "family": "GT Eesti Display", "weight": 700, "size": 80, "color": "#054f8e",
"case": "uppercase", "tracking": 2, "horizontalAlign": "center" }
},
"props": {
"content": [ { "value": "Footy Finals" } ],
"background": { "fill": "#fed109", "radius": 7,
"padding": { "top": 24, "right": 40, "bottom": 25, "left": 46 } }
},
"effects": [ { "type": "dropShadow", "color": "#000000", "opacity": 0.3, "blurPx": 6, "offsetX": 4, "offsetY": 3 } ],
"animations": [
{ "animation": "wipe", "params": { "direction": "from-left", "durationInFrames": 12 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 0 } },
{ "animation": "pulse", "params": { "scale": 1.05, "periodInFrames": 40, "delay": 30 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 0 } }
]
},
{
"id": "ff-hero",
"type": "text",
"zIndex": 2,
"layout": {
"mode": "flow",
"16:9": { "flowIn": "ff-lockup", "w": "content", "h": "content", "rotation": -5 },
"9:16": { /* … */ }, "1:1": { /* … */ }
},
"typography": {
"16:9": { "family": "GT Eesti Display", "weight": 700, "size": 181, "color": "#ffffff",
"case": "uppercase", "tracking": 4.5, "horizontalAlign": "center" }
},
"props": {
"content": [ { "value": "Bonus TV*" } ],
"patterns": [
{ "expression": "\\*$", "typography": { "size": { "ofRoot": 0.43 }, "baseline": 0.75 } }
],
"background": { "fill": "#ed1c24", "radius": 10,
"padding": { "top": 56, "right": 41, "bottom": 52, "left": 41 } }
},
"animations": [
{ "animation": "wipe", "params": { "direction": "from-left", "durationInFrames": 12 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 4 } },
{ "animation": "pulse", "params": { "scale": 1.05, "periodInFrames": 40, "delay": 30 },
"at": { "mode": "cueOffset", "cue": "start", "offsetFrames": 0 } }
]
}
]
}
| Note | Field path | Control |
|---|---|---|
| Editable text | ff-label.props.content[0].value, ff-hero.props.content[0].value |
text |
| Change colours | ff-*.props.background.fill, ff-*.typography[ratio].color |
colour |
| Pulse toggle per panel | ff-*.animations[1] on/off |
no bindable leaf — see Stress points |
| Tilt | ff-hero.layout[ratio].rotation |
degrees |
Panel shadows are layer effects
Each panel above carries a drop shadow in the source artwork. A shadow is a per-layer
effect, applied to the whole layer (glyphs and pill together), not a field on
background — see Coordinate System & Sizing.
Where text and its panel need different shadows, they become two layers: a text layer
and a background layer spanning it, each with its own
effects.
What the engine does with it¶
Resolve. Two wipes at 0 and 4, two continuous scale tracks, 0.43 × 181 for the asterisk.
Solve. Both texts measure unconstrained; the column stacks them 14px apart and centres them on the wider hero. The hero's 5° tilt doesn't touch the packing — the label sits over the hero's resting, untransformed box.
Animate. Each panel pulses about its own content centre and wipes on its own clip. The label inherits nothing from the hero: they're siblings, not parent and child.
Place. Three elements.
What this shows¶
- The minimum lockup. Two text layers and a column — everything a "panel with a word on it"
needs is
props.background, and everything "stacked and centred" needs is oneflowBox. - Uppercase is typography, not copy.
case: "uppercase"keeps the bound valueFooty Finalshuman-readable while rendering the reference's caps.
Stress points¶
background.shadow— same as 03.- Wipe is a clip animation — same as 01.
- Pulse pivot and toggle binding — same as 01. With only two panels the shared-centre difference is small but visible: in the built component the label drifts down toward the hero as both grow; here it grows in place.
rotationon a flow member assumed — same as 01.
Nothing else in this component strained the schema.