MARS Bromont CCI 2026 — Graphics Build Plan
Show: MARS Bromont CCI 2026 (CCI4*-L/S, CCI3*-L + U25, CCI2*-L + U25, Bromont Rising)
Day 1: 2026-06-04 (T-19 days from 2026-05-16)
Owner: Mike Schiffman / Real Neat Solutions
Distribution: YouTube Live, Bromont brand only (no CMH/H&C lockups, no broadcaster compliance)
Brand source: brand-packs/bromont.json + Bromont/bromont-brand-book/ (https://bromont.schifftacular.com/)
Architecture (locked)
| Layer | Engine | Where it runs | Role |
|---|---|---|---|
| Pre-rendered motion (intros, bumpers, stings, EOD, story package) | After Effects (rendered to ProRes/PNG-seq, played from OBS Media Source) | Mac Mini at Hickory Hills, pre/post-show only — does NOT run during the live stream | Primary |
| Live rundown layer (lower-thirds, scorebug, leaderboard, fence callouts) | SPX-GC (browser source) | VPS in the cloud; iMac consumes as a browser source over the public internet | Primary |
| Live redundancy | NewBlue Captivate | iMac at Hickory Hills, open and running for every minute of the broadcast alongside OBS | Co-running redundancy (not cold). Mike triggers from Captivate when AE/SPX falls over OR when Captivate is faster to fire. Refines 2026-04-29 split-engine memo per [[project_bromont_build_decisions]] + [[project_bromont_architecture_corrections]]. |
| Atomic chassis swap (primary slot) | SPX-GC | VPS | Operator-fired from console menu |
Build rule: Anything that needs to swap atomically on primary-slot change or fire from the operator menu mid-rider lives in SPX-GC. Anything cinematic, stinger-like, or longer than ~5s of motion lives in AE.
Captivate fallback rule: A graphic only earns a Captivate twin if its absence would break the show's information contract with the viewer (rider name, score, country, leaderboard, sponsor bug). Cinematic motion is not mirrored — if AE dies, we live without bumpers, not without lower-thirds.
No TPS for Bromont ([[project_bromont_no_tps]]). Every "data-bound" graphic below sources from Postgres on the VPS, populated by operator action or manual scorer entry — not from a venue timing feed. No auto-fire on TPS events anywhere.
Phase 0 — Pre-Show / Cross-Phase
Tier 0 floor
| Graphic | Engine | Asset list | Data binding | Trigger | Captivate fallback | Effort | Dependencies |
|---|---|---|---|---|---|---|---|
| Corner bug | AE (looped PNG-seq) + SPX-GC (static fallback) | bug.svg from brand pack, MARS-Bromont indigo bug 52px | Static asset reference | Always-on (OBS source toggled per scene) | Yes — static PNG on OBS scene | S | Brand pack ratified |
| Lower-third banner (rider name / country / horse) | SPX-GC | Rider roster JSON, country flag set | shows/bromont-2026-06/data/riders.json → SPX rundown row | Operator menu (per-rider) | Yes — full Captivate twin, identical fields, indigo chassis | M | Roster import |
| Lower-third banner (score / penalties) | SPX-GC | Score schema per phase | Postgres scores table (manual entry by scorer or scraped from OC's published results) | Operator menu | Yes — Captivate twin with manual data entry | M | Score data pipeline, phase schema |
| Leaderboard (sortable per phase) | SPX-GC | Full division roster, current standings | Postgres view per division/phase | Operator menu (toggle on/off, scroll) | Yes — Captivate static top-10 page per division/phase, refreshed manually | L | Postgres scores schema, sort logic, EN/FR labels |
Commentator dossier / teleprompter surface is tracked as its own non-broadcast workstream — see the dossier project plan, not this document.
Tier 1 cross-phase
| Graphic | Engine | Asset list | Data binding | Trigger | Captivate fallback | Effort | Dependencies |
|---|---|---|---|---|---|---|---|
| Division indicator (CCI4-L/S, CCI3-L + U25, CCI2*-L + U25, Bromont Rising)** | SPX-GC | Division ID strings, level color treatment from brand pack | Division flag in show config | Operator menu (set at top of each division block) | Yes — Captivate static division ID card | S | Division roster keyed in show config |
| EOD wrap template | AE pre-render | Final standings top-10 + Sunday tease still | Postgres final standings export → AE data merge (one render per division per day) | Operator end-of-day cue | No — AE-only acceptable | M | EOD render workflow |
| Story package template (rider feature, 30-60s) | AE pre-render | Rider portrait, B-roll, captions, music bed | Hand-edited per package | Operator menu | No — AE-only | L | Story selection + B-roll capture by Hank's cam crew |
| Replay bumper (in/out stinger) | AE pre-render | 1–2s stinger each | Static, no data | Operator menu (paired with OBS replay scene) | No — AE-only; without it, replay just cuts cleanly | S | Brand motion ratified |
Phase 1 — Dressage
Dressage rail color: mauve #7B5BAA (phase token). Intro-card rail uses this tint; type stays indigo. Live scoring graphics fall back to the cross-phase lower-third (score / penalties).
| Graphic | Engine | Asset list | Data binding | Trigger | Captivate fallback | Effort | Dependencies |
|---|---|---|---|---|---|---|---|
| Per-rider intro card (bio / horse / country / last result / story-link) | AE pre-render (one per starter, batch-rendered ~1 hr before phase block) | Rider portrait, horse photo, flag, last-result string | riders.json + dossiers.json → AE data merge via brand pack tokens | Operator menu — fires from on-deck list | Yes — Captivate "intro card lite": name + country + horse only, no portrait | L | Roster + portraits + dossier text |
Name-order rule (locked): Intro cards render FIRST name in big UPPERCASE on top, LAST name title-case smaller below (see [[feedback_rider_card_name_order]]). Opposite of football convention. Inter 700–800.
Phase 2 — Show Jumping
SJ rail color: arena turf #3E8B5C.
| Graphic | Engine | Asset list | Data binding | Trigger | Captivate fallback | Effort | Dependencies |
|---|---|---|---|---|---|---|---|
| SJ Timer scorebug (Bromont-skinned) | Browser-source HTML app (sj-timer.schifftacular.com, already prototyped) | Bromont brand tokens, course config (jumps, time allowed) | Local timer state + Postgres score sync | Operator (sj-timer UI) | Yes — Captivate static fault/time card, manually updated | M | Timer app re-skin to Bromont brand, course config import |
| SJ per-rider intro card | Reuse Phase-1 AE card (same template, SJ phase tint) | Same as D intro | Same | Operator menu | Yes — same Captivate lite card | S | Phase-1 card built |
| Fault / refusal indicator | SPX-GC | Penalty schema | Timer app + manual operator confirm | Auto on event | Yes — Captivate twin | S | SJ Timer integration |
| SJ final standings (per division, end-of-phase) | SPX-GC (leaderboard view filtered to SJ) | Standings | Postgres | Operator | Yes — Captivate static top-10 | S | Leaderboard built |
Phase 3 — Cross-Country (highest density)
XC rail color: saddle leather #A4733A.
XC menu-fired graphics
All XC content fires from the operator console menu (locked design pattern). Templates must accept a primary-slot ID and render atomically on swap.
| Graphic | Engine | Asset list | Data binding | Trigger | Captivate fallback | Effort | Dependencies |
|---|---|---|---|---|---|---|---|
| XC opener (live wide + pre-recorded fence broll cut-ins) | AE pre-render (B-roll edit) + OBS scene composite (live wide) | Fence broll captured pre-show, music bed, anniversary title card | None (cinematic) | Operator (top of XC block) | No — AE-only | L | Fence broll capture day, 50th-anniversary lockup design |
| Per-rider stopwatch (running clock on-air) | SPX-GC | Inter tabular numerics, indigo chassis | Local timer state, atomic swap on primary-slot change | Manual operator press when rider leaves the start box (console button / shuttle). No TPS auto-start. | Yes — Captivate twin (loses atomic-swap fidelity; manual cut acceptable in fallback mode) | M | Primary-slot mechanic implemented in console |
XC layout templates (4 total)
These are OBS scene compositions authored to take the SPX-GC overlay + camera buses as inputs. They're not graphics in the strict sense — they're the chassis the graphics live in. Listed here because they gate the visual product.
| Layout | Description | Engine | Effort |
|---|---|---|---|
| HERO | Single full-frame cam + chassis | OBS scene | S |
| START BOX PiP | Hero + start-box inset | OBS scene | S |
| REPLAY + LIVE | Replay full + live PiP | OBS scene | M |
| LEADERBOARD + INSET | Leaderboard full + live cam inset | OBS scene + SPX leaderboard | M |
Built via orchestrator/scripts/obs_scene_builder.py from shows/bromont-2026-06/obs/scene_config.yaml. Don't hand-edit in OBS.
Tier 2 (stretch — only if Tier-1 is complete by 2026-05-30)
| Graphic | Engine | Effort | Risk |
|---|---|---|---|
| Course-map graphic with live position dots | Browser source (SVG + operator-driven or CV-driven position state) | L | High — Bromont has no TPS feed, so position data comes from either manual operator scrubbing of the rider's last known fence (from POC chatter) or Claude CV detection on the Mac Mini (not built). Likely slips. |
| Sponsor fire-count tracker | Browser source (counts bumper plays per sponsor across show) | M | Low — data-only; cosmetic |
Asset Gathering Checklist
Nothing below is optional. Anything missing on 2026-05-30 is a build blocker — escalate immediately.
Rider / horse data
- Final rider roster per division (CCI4*-L, CCI4*-S, CCI3*-L, U25 CCI3*-L, CCI2*-L, U25 CCI2*-L, Bromont Rising) — CSV or JSON, FEI ID where possible
- Horse data per pair (name, breed, age, owner, sire/dam if available)
- Rider portraits (min 1200px square, headshot framing) — gap-fill with generic silhouette card
- Country / flag mapping (ISO 3166-1 alpha-3, render via standard flag set)
- Last-result string per rider (for intro card "FROM: <previous show> <result>")
- Story-link / dossier text per rider (1-2 sentence pre-written for commentator)
- Hometown strings in the bromonthorsetrials.com press-release style ("Dunham, Quebec's Colleen Loach")
Course / venue
- Final XC fence list with numbers + names + GPS coordinates (gates Tier-2 course map)
- XC fence broll capture day scheduled before 2026-06-03 — fixed plates for XC opener cut-ins
- SJ course config per division (jump count, time allowed, distance) for SJ Timer
- Venue wide shot / drone plate for XC opener
Sponsor logos
- Title sponsor — MARS Bromont lockup SVG (already in brand pack at
assets/brand/bromont/MARS-Bromont-LOGO-2020-TALL_SIGNAGE_RGB.svg) — drives the persistent corner bug - 50th-anniversary lockup — currently a placeholder in brand pack. Needs design or confirmation that anniversary stays off-broadcast.
Sponsor inventory beyond the title sponsor + anniversary lockup is out of scope for this graphics package — corner rotation, sponsor lower-third, and marquee fence bumpers were all dropped. If any sponsor placement comes back into scope (EOD wrap acknowledgments, etc.), reopen this section and pull tier-partner + official-partner logos at that point.
Brand pack ratification
-
brand-packs/bromont.jsonaccepted as-is (no edits expected — palette/type are HIGH confidence). Confirm anniversary gold#C8A557is contractually correct or drop from broadcast. - EN/FR bilingual strings pre-typeset for every persistent label (lower-third, leaderboard headers, division IDs)
- Fraunces + Inter + Recursive Mono fonts licensed and installed on AE rig and SPX-GC server
Pipeline / infra
-
shows/bromont-2026-06/data/populated with roster + dossier + scores schema - Postgres
scorestable provisioned with phase + format columns - OBS
scene_config.yamlwritten and applied viaobs_scene_builder.py - Operator console menu wired to SPX-GC rundown + AE media triggers
- Replay rig OBS scene built (paired with replay bumper)
Captivate Fallback Roster (minimum redundancy set)
These graphics must exist in Captivate as well as their primary engine. If the AE/SPX rig fails on show-day, the show can continue on Captivate alone with degraded but coherent graphics.
| Graphic | Why mirrored |
|---|---|
| Corner bug | Identity contract |
| Lower-third (name / country / horse) | Information contract |
| Lower-third (score / penalties) | Information contract |
| Leaderboard (top-10 per division/phase) | Viewer can't follow the show without this |
| Division indicator | Show structure clarity |
| Per-rider intro card (LITE version — name/country/horse only, no portrait) | Identifies who's on |
| Per-rider stopwatch | Operational (atomic-swap fidelity lost; manual cut acceptable) |
| SJ fault/refusal indicator | Information contract |
| SJ Timer scorebug (static fault/time card variant) | Information contract |
AE-only acceptable (no Captivate twin)
- XC opener, EOD wrap, story package, replay bumper, 50th-anniversary stings, anything cinematic > 2s.
Rationale: In fallback mode, the show loses gloss but keeps the viewer informed. Bumpers and openers are sacrificable; the scoreboard is not.
Risk Flags (19 days to Day 1)
| Risk | Severity | Why | Mitigation |
|---|---|---|---|
| Course-map graphic with live position dots (Tier-2) | HIGH | No TPS feed for Bromont. Position data has to come from either manual operator scrubbing (driven off POC chatter from XC ops on the ground) or Claude CV detection on the Mac Mini — neither is built. Tier-2 only. | Do NOT cut into Tier-1 time. If Tier-1 isn't fully done by 2026-05-30, drop entirely. |
| Per-rider intro cards across ~6 divisions × ~30 riders each = ~180 batch renders | MEDIUM | AE batch-render time + roster late-arriving. One template serves dressage + SJ. | Render in batches per division as roster firms. Build template once; data-merge automated. Reserve 2026-06-02 EOD as final-batch day. |
| EN/FR bilingual pre-typesetting | MEDIUM | French strings ~20% longer; lower-thirds need truncation allowance designed in | Decide language policy now: bilingual stacked? alternating? Or EN-only broadcast graphics with FR-only social cutdowns? Confirm with Sue Ockendon. |
| 50th-anniversary lockup is a placeholder in brand pack | MEDIUM | Without ratified anniversary art, the XC opener has a hole | Confirm by 2026-05-23 whether anniversary is on-broadcast or dropped. If dropped, simplify XC opener. |
| SJ Timer re-skin to Bromont brand | LOW | Prototype already lives at sj-timer.schifftacular.com on Tryon skin | Token swap from Tryon → Bromont brand pack. Allow 1 dev-day. |
| Story package template requires editorial content (rider features) | LOW | Hank's cam crew + Mark must commit to specific riders for features | Confirm 3-5 feature riders by 2026-05-26. Don't try to feature everyone. |
| Atomic primary-slot swap on chassis (stopwatch + name + nationality) | LOW–MEDIUM | Locked design pattern; SPX-GC must hold ms-accurate state across two riders being switched | Test on console in dev rig by 2026-05-25 with simulated operator-driven start events (no TPS — Bromont is manual). |
AE-MCP wrapInTransaction=false quirk | LOW | Known footgun — silently rolls back edits when default true | All AE-MCP execute_script calls in template authoring scripts pass wrapInTransaction=false and manage their own undoGroup. Documented in [[feedback_ae_mcp_wrap_in_transaction]]. |
Build order (suggested, 19 days)
- Days 1-3 (2026-05-17 → 2026-05-19): Asset gathering sprint. Title-sponsor lockup, anniversary art (decision), rider portraits, roster, fonts. Brand pack ratified.
- Days 4-7 (2026-05-20 → 2026-05-23): SPX-GC templates — corner bug fallback, lower-third (name/country/horse), lower-third (score/penalties), leaderboard, division indicator, SJ fault/refusal indicator, per-rider stopwatch chassis. Captivate twins built in parallel by same operator.
- Days 8-11 (2026-05-24 → 2026-05-27): AE primary work — intro card template (data-merge driven, serves dressage + SJ), replay bumper, EOD wrap. SJ Timer re-skin to Bromont brand. Begin XC layout
scene_config.yamlfor the 4 OBS scenes (HERO, START BOX PiP, REPLAY + LIVE, LEADERBOARD + INSET). - Days 12-14 (2026-05-28 → 2026-05-30): XC opener (B-roll edit + anniversary title card), story package template. Integration testing: operator console → SPX-GC + AE media triggers. Primary-slot atomic-swap test on stopwatch.
- Days 15-17 (2026-05-31 → 2026-06-02): Rehearsal with operator. Batch-render all intro cards across divisions. Captivate fallback drill — operator runs a mock segment with primary rig "dead."
- Days 18-19 (2026-06-03 → 2026-06-04): On-site setup, fence broll capture for XC opener cut-ins, dress rehearsal, Day 1 go-live.
Tier-2 graphics enter the schedule only if Tier-1 hits a clean checkpoint by 2026-05-30. Otherwise, defer.
This plan respects the locked scope. No version-2 features. No CMH/H&C lockups. Bromont brand only. YouTube Live only. AE+SPX primary, Captivate fallback. Operator-menu-driven. Build directly from this in the morning.