---
name: Marketing Mega-Pipeline
slug: marketing-mega-pipeline
category: Automation
description: "Marketing Mega-Pipeline produces a product's full marketing asset suite in one run, including brand onboarding, UI polish, demo video, launch video, social clips, and OG assets. Use it when you want coordinated deliverables for a launch rather than a single asset or copy alone."
github: "https://github.com/ucsandman/marketing-studio/tree/main/skills/marketing"
language: JavaScript
stars: 225
forks: 31
install: "npx degit https://github.com/ucsandman/marketing-studio/tree/main/skills/marketing ~/.claude/skills/marketing"
installs_to: ~/.claude/skills/marketing
source_path: skills/marketing/SKILL.md
collection_size: 15
category_size: 1754
collection_url: "https://dirskills.com/collections/ucsandman/marketing-studio"
added: 2026-09-03T06:05:19.659Z
last_synced: 2026-09-03T06:05:19.659Z
canonical_url: "https://dirskills.com/skills/marketing-mega-pipeline"
---

# Marketing Mega-Pipeline

Marketing Mega-Pipeline produces a product's full marketing asset suite in one run, including brand onboarding, UI polish, demo video, launch video, social clips, and OG assets. Use it when you want coordinated deliverables for a launch rather than a single asset or copy alone.

**Install:**

```bash
npx degit https://github.com/ucsandman/marketing-studio/tree/main/skills/marketing ~/.claude/skills/marketing
```

## README

# Marketing Mega-Pipeline

One command produces a product's full asset suite: brand onboarding, UI polish, logo reveal, product demo, launch video with audio, social clips, and OG assets. The individual asset skills own their recipes; this skill owns sequencing, gates, and run state.

**REQUIRED BACKGROUND:** marketing-studio (engine-repo workflow shape and non-negotiables). All PLAYBOOK rules apply.

## Resume check — before anything else

Glob `out/*/marketing/run.json` in the engine repo. If an incomplete run exists (any asset not `delivered`), this invocation is a RESUME: skip Phase 0, load the saved intake answers from the manifest, and continue at the first asset whose status is not `approved`/`delivered`. If several incomplete runs match, ask which one. Only a fresh run proceeds to Phase 0.

On resume, still run the Phase 1 environment checks (shared-repo guard + `launch.py --check` — the previous process died mid-flight), but skip brand onboarding and Phase 2 polish if the manifest marks them complete. Trust a `rendered`/`approved` status only after confirming its artifact actually exists on disk; missing or truncated artifact → demote that asset to `planned`.

## Phase 0 — Intake: ONE batched question round, then silence

Fresh runs only. Ask everything in a single AskUserQuestion, then run without asking again (exceptions: per-asset stills gates in gated mode, final delivery):

1. **Product/brand + destination** — which brand, and where finished assets land in the product repo (default: its existing media/marketing dir).
2. **UI polish before filming?** Default YES: the demo films the real running app, so rough edges get rendered at 60fps forever. YES = impeccable → polish → frontend-verify on the product repo before any capture. NO = film as-is. This edits product code, so it is always the user's call — never silently skip it AND never silently do it.
3. **Audio** — music + voiceover is the default and the only thing a film ships with; ask only WHO narrates (brand voice id vs default) and whether music leads or narration leads. "None" is not an option and music-only is a recorded exception (`--music-only`), never a default: a film with no voice explaining the product is not done (CLAUDE.md, learned 2026-09-01).
4. **Social clips** — platforms and count (default: X + LinkedIn, one each).
5. **Checkpoint mode** — full-auto (self-check stills, user reviews the final gallery) or gated (user approves stills before each full render).

## Phase 1 — Foundation

1. Shared-repo guard + `python launch.py --check` (marketing-studio steps 0–1), then `node scripts/install-skills.mjs --check` — it warns when a bundled `skills/` copy and its installed `~/.claude/skills` copy have drifted, so the run does not follow a stale checklist. Warn only; fix the drift or note it, then continue.
2. Brand: if `brands/<id>.json` is missing, onboard per PLAYBOOK. Brand-token judgment stays in the main loop — do not delegate it.
3. Create the run manifest `out/<brand>/marketing/run.json`. It stores BOTH the Phase 0 intake answers (brand, destination, polish flag, audio choice, social config, checkpoint mode) AND one entry per planned asset. Statuses mean exactly this:
   - `planned` — not rendered yet. Gated mode: user approves pre-render stills before the render starts (that is the ONLY user gate per asset).
   - `rendered` — artifact on disk, post-render frame check pending (extract 2–3 frames from the artifact and inspect them — self-check in both modes).
   - `approved` — frame check passed; approval is recorded in the manifest the moment it happens, never inferred from chat history. A resumed session redoes the frame check for any `rendered` asset, showing the frames to the user first in gated mode.
   - `delivered` — copied to the product repo.
   Update the manifest after every status change. Never restart a run from scratch because the session died.
4. Infographic bridge: `node scripts/build-infographic-style.mjs <brand>` writes `out/<brand>/marketing/infographic-style.md`, the /epic-infographics design language built from the brand tokens; copy it to `~/.claude/skills/epic-infographics/references/design-languages/<brand>.md` and name it at that skill's step 6, so any infographic in this run renders on brand hexes instead of an invented palette.

**Content approval gate.** Once `out/<brand>/marketing/brief.json` is synthesized and passes `node scripts/lint-copy.mjs`, run `node scripts/build-storyboard.mjs <brand>` and show the user `storyboard.html` for content approval BEFORE any rendering; in full-auto mode the main-loop judge reviews it instead.

**Brief synthesis rules.** The zod schema (`studio/src/lib/brief.ts`) is the contract; fill the grounding sections, not just the copy: `audience` + `customerLanguage` + `objections` + `switchingForces` from the brief-inputs grounding, and a `proofPoints` entry (claim + source) for EVERY number the copy cites — an unsourced stat is fabrication, omit it instead (lint-copy WARNs on stat-shaped claims in a brief with no proofPoints). Draw `hook.headline` and each of the (up to two) `altHeadlines` from DIFFERENT hook categories per `references/hook-formulas.md`, record the categories in `hook.strategies`, and include at least one emotion-forward category (story/contrarian) against a value hook — evidence in `references/campaign-evidence.md` (read it before synthesis; it also lists debunked claims that must never appear in copy). Build `cta` with the [Action Verb] + [What They Get] formula. The storyboard renders the grounding sections so the approver can check copy against facts.

**Copy council (full-auto mode).** Before the main-loop judge accepts the storyboard, run a 3-judge council on the brief copy: three parallel Sonnet subagents (`model: claude-sonnet-5`, explicit), one per lens — positioning sharpness (would April Dunford sign it?), emotional resonance vs feature-dump, and evidence honesty (every claim traced to a proofPoint) — with the third judge additionally instructed to argue AGAINST shipping the copy (mandatory dissenter; kills the echo chamber). Issues raised by 2+ judges go back to synthesis; single-judge nits are noted, not blocking. In gated mode the human storyboard review replaces the council — offer it only if the user asks for a copy critique. (Pattern adapted from Corey Haines' marketing-council skill, MIT.)

## Phase 2 — UI polish (only if opted in)

In the PRODUCT repo: impeccable → polish → frontend-verify. Must fully complete before Phase 3 — re-shooting every asset because the UI changed after capture doubles the run. Commit product-repo polish separately from asset delivery.

## Phase 3 — Asset pipeline: STRICTLY SEQUENTIAL

The engine repo is shared mutable state (props builders, registries, render queue). Two asset skills at once collide and renders saturate the CPU. One asset at a time, in this order. (One blessed exception: /logo-reveal touches only the engine repo and captures nothing, so it may run concurrently with Phase 2 polish, which touches only the product repo — zero shared state, real wall-clock savings.)

| # | Skill | Why this position |
|---|-------|-------------------|
| 1 | /logo-reveal | Cheapest comp — surfaces brand-token bugs before the expensive assets |
| 2 | /product-demo | Films the (now polished) UI; footage feeds everything downstream |
| 3 | /launch-video | Picture-lock the hero video (composes demo + logo + copy). Before locking, when the brief carries altHeadlines: `node scripts/render-hook-variants.mjs <brand>` renders the competing hook takes and registers them as Mission Control variants — pick the winner there, then lock. Optionally `node scripts/render-variants.mjs <brand> logo-reveal` for hero takes. |
| 4 | /audio-track | MANDATORY, never skipped. Score the locked film: a bespoke film (studio/src/films/<brand>/) via `node scripts/build-<brand>-film-audio.mjs` + `node scripts/score-film.mjs <brand> <film.mp4>`; a LaunchVideo template film via build-<brand>-audio.mjs + merge + master to `launch-final.mp4`. Then set the launch-video asset's `artifact` to the SCORED file (keep the silent lock as `silentLock`) and copy it to `out/<brand>/launch.mp4` so postkit and the gallery carry the narrated cut. A silent launch card is a defect, not a variant (postflop shipped two silent cuts on 2026-09-01) |
| 5 | /social-clip × N | Reuse demo/logo footage per platform. SocialClip renders silent, so EVERY delivered clip is scored before it counts: `node scripts/score-social-clip.mjs <brand> <clipId> --vo <act>` per clip (music bed plus the ONE VO line that matches the plate, e.g. hook for the X clip), leaving `<clipId>-final.mp4` in out/<brand>/ so build-postkit picks it over the generic matrix row. The captioned 9:16/1:1 matrix rows are for MUTED autoplay, which is a viewer default, not a licence to ship them with no track (postflop's tiktok/shorts/instagram rows had none, 2026-09-01) |
| 6 | /og-assets | Statics + README GIF pulled from final footage |
| 7 | Cards (`node scripts/build-cards.mjs <brand>`) | One stat card per brief proofPoint plus a quote card from hook.headline, rendered as Card stills into out/<brand>/marketing/cards/; skips clean with exit 0 when there is no brief. Not an asset skill, a builder |

Per asset: stills gate before full render — `node scripts/contact-sheet.mjs <brand> <Comp>` is the standard gate artifact (each sub-skill enforces it), render logs `| tail -2`, then update the manifest. Assets #1 (/logo-reveal's Blender staging) and #2 (/product-demo's Playwright capture) check the content-hash footage cache first and skip the expensive stage when their inputs (product git state, capture/staging script, and resolved config) are byte-identical to the last run; pass `--force` to re-capture.

**Render budget: one full-resolution render per asset.** The renderer is not where a
two-hour run goes; correction rounds are. Measured 2026-09-01 on the 24-core box: a
full-res LaunchVideo render is ~9 minutes and `--x264-preset` barely moves it (Chrome
frame rendering is the bottleneck, not encoding), while `--scale=0.5` renders 3.3x
faster. So: judge every round from the contact sheet, and when a round needs motion,
render the preview at `--scale=0.5` as `launch-vN-preview.mp4`. The full-res render
happens ONCE, after the stills pass. The postflop launch step rendered three full
passes (27 minutes of the step's 48); this rule makes that one. A product bug found
mid-capture is a note in `run.json` judgeNotes for the user, not a fix inside the
run (postflop's demo step spent 64 minutes that way).

**Budget the VO before you dispatch #4, not after.** Picture-lock (#3) and audio (#4) are separate steps, and the trap between them is that measured VO word timings DERIVE act lengths, so scoring a locked film can push it past the 30-90s band `launchTiming.test.ts` enforces. Do the arithmetic yourself at dispatch time and hand it to the executor: `frames_available = 2700 - current_total`, minus the demo act which is FIXED (the PLAYBOOK forbids shortening a recorded demonstration to fit narration). Estimate each act's need at ~150wpm plus `VO_LEAD` + `VO_PAD`. If the narration overruns, say so in the brief and name the act to cut hardest — copy is trimmed ONLY in `build-<brand>-audio.mjs`, never by editing act constants. Measured on the practicalsystems run (2026-08-17): an 80.8s lock left 276 frames of headroom against ~564 needed, so ~25 words had to go. **Name any claim that must survive the trim**, because the shortest phrasing is often the false one — "cold outreach never sends without a human" compresses to "nothing sends without a human", which was untrue there.

**Phase 3.5 — Responsive export matrix.** Once the launch video is picture-locked and the social clips are rendered, run `node scripts/render-matrix.mjs <brand>` to fan the launch video and social clips into all four aspects (16:9, 1:1, 4:5, 9:16) by responsive layout, not crops. Variants land in `out/<brand>/matrix/` and register in the manifest's `exports[]`. Add `--stills-only` first to prove the layout with one still per aspect before committing CPU to full renders. The muted-autoplay rows (9:16 and 1:1) additionally emit an `<id>-captioned` variant with the VO burned into on-screen captions, and `node scripts/build-captions.mjs <brand>` writes matching `launch.srt`/`launch.vtt` sidecars — both require the brand's audio props (skipped silently without them).

## Execution mode — pick by session model

- **Opus or Sonnet session** (default): run each asset skill inline in the main loop. Visual-tuning loops go to Sonnet subagents (`model: claude-sonnet-5`, always explicit) so iteration stills die with their context. Mechanical checks: Haiku or inline. Escalate to Fable at most once, standalone, only if a new template must be designed mid-run.
- **Fable session** (e.g. `ultracode "/marketing"` with Fable as the main model): executor-judge mode, below. Fable never executes asset recipes inline — its context grows for hours at judging-grade rates while doing checklist work.

## Executor-judge mode (Fable session)

Fable is the judge and orchestrator; it holds only the intake answers, the manifest, dispatch prompts, and verdicts. Everything heavy happens in disposable executor contexts.

1. **Brand onboarding stays in the main loop** — one-time judgment work, exactly what Fable is for. If `brands/<id>.json` is missing, derive tokens from the product repo (DESIGN.md, tailwind, CSS vars per PLAYBOOK) and fold any underivable values into the Phase 0 intake batch — never a mid-run question to an absent user.
2. **Phase 2, if opted in, goes to one `claude-opus-5` executor** that runs impeccable → polish → frontend-verify in the product repo and returns before/after screenshots plus the verify result as raw data. Fable judges those before any capture starts — the polish pass is heavy UI work and does not belong in the judge's context.
3. **One executor subagent per asset, strictly sequential** (the engine repo and CPU rules from Phase 3 apply unchanged). Models, always explicit: `claude-opus-5` for /product-demo and /launch-video (capture choreography and copywriting need judgment); `claude-sonnet-5` for /logo-reveal, /audio-track, /social-clip, /og-assets (recipe execution).
4. **Dispatch prompt contract**: tell the executor to read the asset's SKILL.md, the marketing-studio skill, and the PLAYBOOK gotchas before acting; give it the brand id, manifest path, and intake answers; have it execute the recipe through full render and return raw data — output path, 3 extracted still paths, and any deviations. No prose reports.
5. **Judge protocol per asset**: Fable Reads the returned stills and judges against the brand's `voice` rules, composition quality, and copy (no em dashes, no hype). Approve → manifest `approved`, next asset. Problems → send a numbered correction list via SendMessage to the SAME executor (its context is intact; never respawn a fresh executor to fix its own work). If the resume fails because the executor's transcript is gone (it happens), spawn a MINIMAL corrections executor whose prompt carries the complete defect list plus file-level context — never re-run the whole asset recipe. Maximum 3 correction rounds per asset; after that, record the asset as `rendered` with judge notes and move on — the user adjudicates it in the final gallery.
6. **This mode is full-auto by definition** — Fable replaces the per-asset user gates as a stronger judge. The user still sees the final gallery (Phase 5 is unchanged), and delivery + commits stay in the main loop.
7. **Fable never spawns Fable**, and the 3-Fable session cap applies. Executors are the fleet; the judge is singular.

## Dynamic workflows — the only two uses

Whatever the execution mode, the Workflow tool touches only read-only fan-outs. Asset execution NEVER goes in a workflow: workflow agents run in the background with no channel back to the judge or the user, renders are CPU-bound and serial so fan-out buys zero wall-clock, and each fresh `agent()` re-reads the PLAYBOOK per call. Corrections need SendMessage to a live executor — a workflow can't do that. Mechanical single commands (`smoke.mjs`, file copies, manifest I/O) stay inline in Bash; a subagent spawned to run one command costs more than the command.

The two legitimate workflows, all agents Sonnet with `model` explicit:
1. Phase 4 brand-compliance sweep: `parallel()` one reviewer per asset still, each finding adversarially verified before it triggers a re-render.
2. Optional pre-delivery judge panel: 3 judges score the full gallery; only issues flagged by 2+ judges go back to Phase 3. In executor-judge mode this panel is a pre-filter — the panel flags, the Fable judge adjudicates.

Fable never goes inside a workflow (the model-guard hook blocks it in `parallel()`/`pipeline()` constructs anyway).

## Phase 4 — Final QA

1. `node scripts/smoke.mjs` — must pass.
1a. `node scripts/check-audio.mjs <brand>` — HARD gate, exit 1 blocks delivery: every delivery-surface mp4 has a mastered track with narration (see CLAUDE.md). Run it again after postkit, because postkit is where silent matrix rows sneak back in.
1b. Mechanical judges before any agent sweep (cheap, run all six): `node scripts/judge-av-sync.mjs <brand>` (VO overruns/caption dwell), `node scripts/judge-demo-pacing.mjs <brand>` (dead air), `node scripts/judge-palette.mjs <brand> <still>` (forbidden colors; low-confidence findings are product-UI suspects, treat per step 2's false-positive rule), `node scripts/judge-motion.mjs <brand>` (motion-craft conventions in studio src + brand motion/grade token bands), `node scripts/judge-drift.mjs <brand>` (cross-asset drift: scores the whole `out/<brand>/` as a SET, which is the only judge that can catch assets that are each individually on-brand but collectively fragment into several — run it LAST, after everything else has rendered, or the set is incomplete; pass `--ref out/<brand>/approved/<latest>/` when that directory exists, so drift is measured as distance from approved rather than from the set average, and in full-auto mode run `node scripts/mission-control.mjs <brand> --snapshot-approved` first because writing run.json directly never fills approved/), and `node scripts/check-budgets.mjs <brand>` (hard size gate — an OVER blocks delivery). judge-av-sync also reports the frame at which the first claim copy lands (`hook copy on screen at frame N`); a 5.0s static open is the shared LOGO_LEN default and `actLengths.logo` is the override. Their JSON reports feed the judge; only findings the reports can't decide go to the agent sweep. judge-drift also writes `drift-sheet.html`, a worst-first review grid — open that rather than eyeballing the whole gallery, because attention is reliable over about six tiles, not twenty.
2. Brand-compliance sweep: one Sonnet subagent reviews a still from every asset against the brand's `voice` rules (e.g. noban: profit gold `#d6c23c`, never green). Re-render only violators — but VERIFY findings against the product repo's source first. Product screenshots inside assets show the PRODUCT's own fonts/tokens, not the engine brand's stand-ins; a reviewer expecting the engine's mono will misread the product's mono as a violation (paperroute run 2026-07-10: 4 of 5 sweep findings were this exact false positive; the fifth was a real product bug, fixed in the product repo, no asset re-render needed).

## Phase 5 — Delivery

1. Copy every asset to the destination dir; write a README there listing each file and its intended use.
2. Launch the operator console: `node scripts/mission-control.mjs <brand>` (add `--port N` if 4600 is taken). Tell the user the URL it prints (default `http://localhost:4600/`). This is a live click-to-approve gallery reading `out/<brand>/marketing/run.json` — one card per asset with the embedded artifact, an Approve button, a Redo box, and variant pickers. An advisory bar under the header shows the mechanic
