Financial Frontiers
# Lockup Sample — Financial Frontiers A seven-beat finance reel in all three ratios: a centred all-caps headline in broadcast yellow over full-bleed footage, with an italic cream subline. There is no plate and no scrim — both halves sit straight on the picture under an offset shadow, and every word of both climbs into its own line from below. Three scenes are recreated from an 18.85s screen recording of a looping ~13.3s reel. That reel carries ONE text mechanism — a per-word masked rise — applied to a two-part lockup, so the headline and the subline animate identically and only the delay between them changes. Four more scenes work the same mechanism at four stations the reel leaves empty, so the set walks the copy through seven compositions without ever changing the device. ## Scenes | scene | station | headline | subline | dur | source | | --- | --- | --- | --- | --- | --- | | `series` | top | 3 lines, big | 1 line under | 3.9s | measured | | `anticipate` | top | 3 lines | 3-line credit, accent name | 4.8s | measured | | `outlook` | centred mid-frame | 2 lines, big | 1 line under | 4.2s | added | | `quarter` | mid-frame, kicker ABOVE | 3 lines | 1-line kicker over it | 4.6s | added | | `numbers` | top + footer | 4 lines | 1 line at the foot | 5.2s | added | | `analysis` | top | 3 lines | 1 line, accent code | 4.6s | measured | | `subscribe` | docked to the lower third | 2 lines, big | 1 line under | 4.0s | added | The four added beats are the four things the reel never does: put the lockup in the MIDDLE of the frame, run the italic line ABOVE the headline as an eyebrow, carry FOUR headline lines with the subline pushed to the foot as a source credit, and hang the whole lockup off the lower third as an end card. They are interleaved rather than appended (title, hook, turn, chapter, detail, offer, end card) so the two measured CTA beats still close the film. The reel cuts hard between beats, so no scene carries a `transition` — which is also the elastic form, since nothing is then keyed to a length the narration will change. Each scene holds its last frame until its script finishes. `series` and `subscribe` are title beats and their pictures are held; the other five narrate over one full-bleed frame, so those are the slots marked `broll`. ## The motion One mechanism, every number fitted to the recording, and the four added scenes reuse the fit unchanged. | beat | how | fitted | | --- | --- | --- | | every headline word | `yPercent` 100 → 0 inside a per-LINE mask | starts 0.24s, `power2.out` over 0.25s, 0.1515s stagger | | every subline word | the same, quicker | starts 0.95–2.12s per scene, `power2.out` over 0.14s, 0.1515s stagger | **The clock had to be recovered before anything could be fitted.** The container reports `r_frame_rate 60/1` and is not 60fps: 587 frames over 18.83s is 31.1fps, and the interval histogram is 499 frames at 1/30 with 81 at 1/60. Every measurement here is therefore read off PTS-resampled frames rather than stored frame indices, and one source frame is 33.3ms — which is the real resolution of every time below. The stagger is the strong result. Twenty-one word onsets across five runs (two headlines, three sublines) were read by tracking each word's own column range frame by frame and taking its 50%-ink crossing, then fitted as ONE shared step with a free offset per run: **0.1515s at a 10.4ms rms residual**, a third of a source frame. Per-run steps land at 0.156 / 0.158 / 0.150 / 0.150 / 0.144, and the first headline word crosses 50% at 0.314s and 0.310s in the two scenes that have four and five words — which is what lets one pair of numbers serve the whole pack. Reading the deltas one at a time instead gives an alternating 0.133/0.167 because each is quantised to that 33.3ms grid; the pooled fit is what separates 0.1515 from the 0.1667 a single pair of frames suggests. The rise duration comes out of the shape of the ink curve rather than its start. For a masked rise the visible ink fraction IS the eased progress, so the gap between the 5%, 50% and 90% crossings pins the ease: `power2.out` puts them at 2.5%, 29.3% and 68.4% of the tween, and only `power2.out` makes the two measured gaps agree on one duration (0.250s and 0.256s from scene 2's second word). `expo.out` disagrees with itself by 1.7×, `power3.out` by 1.2×. At a 33.3ms sampling grid the duration itself is only good to about ±0.08s; the ease is the part that grid still separates, because it is read from a RATIO of gaps. The subline is measurably faster — its 5%→90% span is 0.067–0.100s against the headline's 0.134–0.167s — so it runs at 0.14s against the headline's 0.25s. Its per-scene delay is authored rather than fitted in the four added scenes, set so the second half lands after the headline has finished rising. It is a MASK, not a fade: `yPercent: 100` is exactly one line box, and the words are at full opacity on the first frame any of them shows. That is why every line break is an explicit `<br>` — the player emits one `[data-part="line"]` per AUTHORED break, so a width-wrapped block would be a single line element and the mask would clip the whole stack instead of each line. The mask is the scene css, with 0.04em of padding and a matching negative margin so the descenders in "Rodriguez," and "insights monthly" clear the clip without moving the next line. ## The type The face is `poppins` — 900 for the headline, 700 italic for the subline — and the weight was settled by the one measurement that separates weights rather than sizes. Ink widths alone could not: least-squares fitting nine measured widths against every heavy grotesque in the catalogue put Arvo, Open Sans, Biryani, Poppins and Roboto within one error unit of each other, which at a 314px capture is noise. Stem width does separate them — the recording's `I` stems run a consistent 8px against a 25px cap, so 0.32, against 0.243 for Poppins 700 and 0.311 for Poppins 900. Two sizes of each half, both measured off the reel: | | headline | subline | | --- | --- | --- | | big — `series`, `outlook`, `subscribe` | 115.2px (`size: 47`) | 57.9px (`size: 17`) | | standard — the other four | 80.3px (`size: 29`) | 48.6px (`size: 12`) | `series` is genuinely larger than the other two measured scenes — 25px of cap against 17.5px in the capture — because its headline is 26 characters where theirs are 34 and 35, and the reference sized each to the same three lines. The two added scenes that carry two-word headlines take the same big size for the same reason. Leading is `0.96em` on the headline (`lineHeight: -20`) and `1.308em` on the subline (`9`), both read as line pitch over type size: 32.5/33.7 and 22.5/23.7 for the two headline sizes, 18.5/14.1 for the subline. The headline also carries `-0.02em` of tracking (`-2`), which is what closes the residual on the width fit. **Every box top is derived, not calibrated.** `alignY: "top"` puts the first line box on `style.top`, so the ink top is `top` plus a pure face-metrics offset — half-leading plus the distance from the ascender to the tallest glyph in the line. Feeding the stored numbers back through that identity reproduces every measured ink top, at every ratio, to within **0.09px at 1920** — which is the check that the anchors were read rather than guessed. ## Docking, and why the added scenes need a different rule The three measured scenes dock by the ink top the recording puts them at. That works because all three hang from the TOP of the frame, and a top-docked block stays put when the canvas gets shorter. The added scenes do not all hang from the top, and there the same rule breaks: a block is roughly twice the height FRACTION on a 1080-tall canvas as on a 1920-tall one, so a mid-frame block held by its top edge slides low and a bottom-docked one walks off the bottom. Each added layer therefore declares the anchor it actually hangs from — `centre` for `outlook`, `bottom` for `subscribe`, `inktop` for the rest — and `style.top` is solved per ratio from that anchor and the block's own height. `subscribe`'s two-line headline sits at 60.5% at 9:16, 51.4% at 1:1 and 47.4% at 16:9, all three putting its bottom edge on the same 72% of the frame. Line counts are 3/1, 3/3, 2/1, 3/1, 4/1, 3/1 and 2/1 at every ratio, checked by measuring each row's advance width against its own box rather than by looking, with the widest at 78% of its box — inside the 96% the player needs before it re-wraps. No two blocks in a scene overlap at any ratio; both are asserted in `_generate.py`'s companion check. ## The shadow Measured, then deliberately overdriven. Around the headline the glyph edges carry a dark band of a few px on both axes with a slight downward bias — but the reference footage is dark enough that the band never has to work hard, and at this capture scale it could not be separated from a busy bookshelf background with any confidence. So the shipped shadow keeps the direction and the proportions and carries 65% black: `3px 5px 14px #000000A6` on the headline at 9:16 and `2px 3px 8px` on the smaller subline. `textShadow` is one of the two field groups stored in raw pixels, so it does not scale with the canvas — 16:9 restates it scaled with its own type size, and 1:1 needs no override because its type is the same absolute size as the base's. ## The palette Four roles — `ground`, `accent`, `paper`, `shade` — and eight variants, the format's maximum. `accent` and `paper` are the two halves of the lockup, and they are separate roles rather than one ink because the design depends on the contrast between them: the headline shouts and the subline does not. `shade` is the glyph shadow, given a role of its own so a warm scheme can carry a warm shadow. `accent` is also the colour of the one highlighted run inside each subline — the name in `anticipate`, the code in `analysis`, the day, the period, the figure and the price in the four added scenes — written as `<span data-text-color>`, which the palette swap rewrites along with everything else. Seven of the eight keep a light `paper` and a saturated `accent`, because there is no plate anywhere in this design: a dark ink on unscrimmed footage has nothing to sit on. `mono` is the deliberate exception — a white accent over a grey paper, for a wire-service look that does not read as a brand colour at all. **A caveat worth stating: with no scrim, a variant can only change the TYPE.** The footage underneath is the same in all eight, so they are eight inks rather than eight looks. Giving `scrim` a role of its own — a gradient wash behind the copy — is the one change that would make each variant a materially different frame, and it is a change the reference does not have. ## The three renditions | | 9:16 | 1:1 | 16:9 | | --- | --- | --- | --- | | canvas | 1080×1920 | 1080×1080 | 1920×1080 | | box | 6% + 88% | 6% + 88% | 22% + 56% | | headline | 80.3px (`29`) | 81.0px (`59`) | 94.9px (`66`) | `font.size` is resolution-independent, which is the trap: the same stored number renders 1.78× larger on the 1920-tall canvas than on the two 1080-tall ones, so each ratio is solved against its own canvas. 1:1 shares the base's canvas WIDTH, so it keeps the base's absolute type size and only its stored number changes. 16:9 is nearly twice as wide, so the lockup is narrowed to a 56% box and the type scaled up 1.196× to fill it at the same fraction — which keeps the ragging the base has instead of stretching the block across the frame. ## Filling it The seven stills are generic dark business footage standing in for the reference's own shots, all from ONE still family so the pack reads as one shoot: a dusk financial district, a wall of trading monitors, a dark office corridor, a data-centre aisle, an after-hours analyst desk, an empty corner office and a long boardroom table. Four of them were brighter than this design can carry, and `_assets.py` **grades them down** rather than rescuing them with a scrim, which would have changed the three measured scenes. The grade is derived, not eyeballed: it measures the four vertical bands the copy actually lands in and finds the gentlest gamma that brings the brightest of them under 62 (gammas 0.73, 0.70, 0.39 and 0.26). The three measured scenes ship as found. They are all placeholders: every one is a `photo` slot at `fit: cover`, and the five narrating scenes are marked `broll` so a filled video cuts b-roll under them instead of holding one frame. Copy is the constrained part. Each `<br>` is a line the type does not shrink to fit: about nine characters a line in the big headlines, twelve in `series`, fourteen in `numbers` and eighteen in the standard three-liners, and the `maxLength` on each slot is that capacity rather than a guess.