← Creative Lab
Gen Digital — 2025

Rapid Response Pipeline

Breach news becomes a finished, branded video — with nobody touching a keyframe

Breach news in the morning, branded video by the afternoon — 24 feeds read hourly, copy written, art generated, and the designers' live Figma templates animated in Jitter by a daemon. Nobody set a keyframe.

24
Feeds, Hourly
289
Videos Exported
0
Keyframes by Hand
The hard part

The templates were never files — each one was the designers' live Figma board, brought into Jitter, the only tool that could animate a real Figma frame. Automation could touch exactly five fields per template, by node id, so a design change upstream shipped in the next hour's run and the brand system stayed out of reach.

Client
Norton / LifeLock (Gen Digital)
Role
Creative Technologist Pipeline Architecture / Automation / AI Integration
Timeline
2025
One article, start to finish

Watch a single post become the video.

Every stage below is a real artifact from one run of the pipeline — the Google Security post about Chrome defaulting to HTTPS. Nobody touched it between the feed and the export.

  1. The article

    The hourly run reads 24 feeds. Among 942 items that morning is a Google Security post: Chrome will default to HTTPS. It is fetched, stripped to clean text, and pushed through the sieve — breach-pattern regexes plus a fuzzy title match against everything already in the ledger. It survives.

    security.googleblog.com/2025/10/https-by-default.html · feed: Google Security · ledger status: kept
    The source article on the Google Security blog: HTTPS by default
  2. The brief

    One model call turns the article into a fixed-shape brief: headline, brand, severity, attack vector, and twenty carousel snippets — every slot any template could ask for, written once. Severity 4 clears the bar; anything under 3 is dropped before art is ever generated.

    gpt-4o-mini · SummaryPayload · stored in the items ledger (SQLite)
    {
    "headline": "Chrome to Enable HTTPS by Default",
    "brand": "Google",
    "severity": 4,                    // under 3 is dropped
    "attack_vector": "Insecure HTTP connections",
    "when": "2026-10-01",
    "tags": ["Chrome", "HTTPS", "Security", "Web Safety"],
    "carousel_snippets": {
      "alert_primary":   "Urgent Security Update",
      "alert_detail":    "Chrome will default to HTTPS, enhancing your online safety.",
      "stat_primary":    "95% HTTPS usage",
      "stat_detail":     "Most Chrome navigations are now secure.",
      "action_primary":  "Stay Informed",
      "action_detail":   "Always check for HTTPS before entering sensitive information.",
      … 14 more slots, one per template field
    }
    }
  3. The photos

    Three of the five comps carry a photograph: the alert, the detail and the endcard. They come from the brand's own approved photo library, rotated by story so no two carousels in a run open on the same face. Story 1 draws the first three. An image agent can render bespoke shots with gpt-image-1 instead; this run stayed on-brand with the library.

    images/image_01 · 02 · 03 → Carousel_1-1 · 1-3 · 1-5 · agents/copy_agent.py
    Library photo: a woman in a car smiling at her phone
    01 · alert
    Library photo: a man checking his phone against city lights at night
    03 · detail
    Library photo: a smiling young man holding a phone and a basketball
    05 · endcard

    New stills can be generated on-brand, too. These three came out of the GenAI Brand Manager dashboard: pick Norton, a type and a variation, and the prompt is written in the brand's own visual language. The dashboard →

    Generated for Norton: two kids on a living-room rug using a phone and a tablet
    lifestyle · family
    Generated for Norton: a glowing shield with a keyhole rising from a laptop
    product · protection
    Generated for Norton: a woman in a mustard cardigan working on a laptop in a cafe
    lifestyle · work
  4. The rows

    The mapper is deterministic — no model in the loop. Copy is clamped to each comp's type spec, the icon is chosen by rule, and five rows are written out with the source URL riding along on every one. This is the whole hand-off: five comps, five fields each.

    out/daily/2025-12-03/agents-top8/rows_v2.json · story 1 of 8
    compstylecopy it carries
    Carousel_1-1TopicFeatureUrgent Security Update — Chrome will default to HTTPS, enhancing your online safety.
    Carousel_1-2StatTile95% HTTPS usage — Most Chrome navigations are now secure.
    Carousel_1-3DetailBodyChrome's HTTPS Default — Starting October 2026, Chrome will prioritize secure connections.
    Carousel_1-4SolutionStay Informed — Always check for HTTPS before entering sensitive information.
    Carousel_1-5LogoTileGoogle Security — Google is committed to keeping you safe online.
  5. The template — the designers' live Figma board

    The four templates were never exported files. Each one is the design team's own Figma board, brought into Jitter — at the time the only tool that could animate a real Figma frame. When a designer changed a colour, a type size or a motion beat in Figma, the next hourly run picked it up; nobody re-exported anything. The daemon knows five node ids per comp — headline1, headline2, buttonICON, buttonCTA, image — and a refresh script re-reads them whenever the board changes. Everything else on the board stays the designers'.

    Rapid Response Template · Carousel (Jitter, from Figma) · local_daemon/node_map.json · tools/refresh_node_map.py
    The Rapid Response carousel template open in Jitter, layers named headline1, headline2, buttonICON and image, lorem ipsum in place
    the board as the designers left it
    The same template duplicated and filled by the daemon with the Chrome HTTPS story
    the same board, filled by the daemon
  6. The daemon in Jitter

    A local daemon opens Jitter inside a Playwright-driven Chromium, duplicates the current template — whatever the designers last pushed from Figma — fills the five nodes per comp from the rows, and clicks export — Video · 1080p. A second rail hands the same payload to After Effects for the other template family. This is a screen recording of the daemon working; nobody is at the keyboard.

    local_daemon · Playwright + Jitter · exports/Story01_Template02_20251203-061113 · 5 × MP4 + 5 × PNG
    from the designers’ Figma templates into Jitter — real time, unattended
  7. The deliverable

    Five slides, one carousel, in the brand's own template — the alert, the stat, the detail, the solution, the endcard. Same morning, four template families, one payload. This is the one story; the page below shows the rest of the run and lets you drive the mapper yourself.

    Carousel_1-1 … 1-5 · H.264 · 1080 × 1080 · one carousel, five exports
    01 · alert
    02 · stat
    03 · detail
    04 · solution
    05 · endcard
Run the mapperreal ingested headlines — the row builder runs in your browser

The pipeline has two halves and they are not equally reproducible. Severity triage and summarisation are a language model making a judgement; the rest — which icon, which comp, which cells go in the spreadsheet After Effects renders from — is rules. Rules can run honestly in a browser, so they do. What you see below is rapid_response/mapper.py: _normalize() truncating summaries at 50 and 120 characters, _choose_icon() testing tags in its real order, and to_ae_rows() emitting one row per slide.

The tags below are the boundary. In production a model assigns them from the article body; here you set them yourself, which makes visible exactly where judgement stops and determinism starts. Everything to the right of that line is reproducible forever.

model — judgement, not reproduced here

rules — running now

What came outone story, five slides — exported unattended
01 · the alert
02 · the stat
03 · the detail
04 · the product
05 · the endcard

One breach story — Chrome moving to HTTPS by default — composed into a five-slide carousel: an alert, a statistic, the detail, the product line, the endcard. The headline, supporting line, icon, call to action and background image on every slide were chosen and placed by the system from a single summarization pass. The animation itself was built by designers months earlier and never touched again.

Four brand templates, one morningall four exported inside an hour — note 03 and 04 carry the same headline in different treatments
Template 01identity threat story
Template 02the same Chrome story
Template 03flat urgent treatment
Template 04same headline, photo-led
How a story becomes a videopress play, or step it

Ten stages, hourly, unattended. The spine runs left to right; the middle fans into the paper trail every run leaves behind; the end splits into two render rails that were both live — the same story payload driving a browser tool and After Effects.

the feeds ingest.py 24 sources · hourly ETag → 304 if unchanged the ledger db.py · rrp.db 942 items archived url_hash · idempotent the sieve filter.py 51 + 10 patterns fuzzy dedupe @ 92 the summary gpt-4o-mini · temp 0 8 fields + 20 slots severity < 3 dropped the cut agents/pipeline.py rows_v2.json copy under type caps 733 DOCX · 1,181 sheets · 8 workbooks the daemon FastAPI + Playwright · :8000 Jitter · no API 4 × 18 × 5 node map After Effects ae_watcher → aerender the deliverable 289 MP4s · 272 stills VIDEO/ + STATIC/ 0 keyframes by hand two rails, one payload
STEP 1/10 Twenty-four cybersecurity feeds, pulled hourly.
headline1 headline2 buttonICON buttonCTA image — the only five layers automation could touch
verified against the archive
Three things worth the write-upthe parts that were not obvious

Jitter has no API, so the daemon uses the editor like a person. The brand animation lived in a browser tool with no automation surface at all. Rebuilding it somewhere scriptable would have thrown away the designers' work, so instead a local service drives the real editor: it logs in once through a real Chromium window — MFA included — and keeps the session, then duplicates the template, selects a comp, and types each headline as genuine keyboard events. It reads every field back to verify what landed, because a dropped keystroke in a headline is invisible until it ships. When the tool has no API, resourcefulness is the skill.

Automation was allowed to touch exactly five layers. Per comp: headline1, headline2, buttonICON, buttonCTA, image — verified identical across all eighteen comps in the node map, with no escape hatch. Animation curves, easing, timing, layout, type and colour were not addressable by the pipeline, so they could not drift. Copy that would overflow was clamped upstream at composition time rather than breaking a layout downstream. This is what made the system safe to run unattended: it was structurally incapable of overwriting the brand system.

One payload, two render engines. The same composed story data drove the Jitter rail and the After Effects rail — a watcher picking up render sheets and calling aerender against the original template. Both were live; After Effects came first and kept working after Jitter became primary. A tool change was a new rail, not a new pipeline.

What the sieve actually did942 items, one archived ledger
arrived942items ingested and hashed into the ledger
kept31733.7% — passed the keyword sieve and the severity gate
rejected8442 no keyword match · 32 fetch failures · 5 bad JSON · 5 below severity
unprocessed541ingested but never carried through enrichment

Worth being precise about: the severity gate is the part people expect to do the filtering, and it accounts for five rejections. Stories overwhelmingly die earlier — at the keyword sieve or at the fetch. The gate's real job was keeping model spend proportional to the news, not culling the feed.

The receiptscounted on disk
artifactcountwhat it is
RSS feeds24breach reporters, CISA, MSRC, NVD
story ledger942 itemsSQLite, 1.50 MB, status per row
export sessions9562 of them produced video; 20 more archived
exported MP4s289272 in VIDEO/, 17 held in the old folder
final-frame stills272captured per comp at export
copy-block documents733one per story, across 8 dated folders
render + QA sheets1,181651 AE render sheets, the rest editorial QA
image sessions55108 generated stills
Jitter wiring map4 × 18 × 5templates × comps × mutable slots

Built solo for a real client context and run through late 2025. It is archived now — the point of this page is the preserved evidence, not a system waiting to be restarted. The class of problem it answers is the one where the volume or speed a brand needs exceeds what a manual team can produce, and the brand system still has to survive contact with the automation.

Scope

Project Elements

Pipeline ArchitectureRSS IngestionAI SummarizationPrompt EngineeringBrowser AutomationTemplate SystemsBrand GuardrailsSocial VideoUnattended Operation
Next Project
LANTERN →

Have a Project in Mind?

Animation direction, VFX and creative technology. Message me on LinkedIn or get in touch.