format-skit — one gag, sound off, the buzz is the punchline
1. Read first
knowledge/ad-formats/_FORMAT-CORE.md(doctrine, lane limits, gates, launch). Binding.references/beat-sheet.md(timings, word budgets, gag ladder, gag bank),references/sources.md(Beaverpro + Zach-D breakdowns).knowledge/hook-taxonomy.md: golden rule "avoid chaos in the first 3 s" is this format's main tension. Absurd is fine; confusing is not.output/dawn-combo-map-2026-10-05/MAP.md§1 (stake on HER, mornings caused it) + §2B (recipe B, the skit's recipe).- Gag premises:
output/creative-strategy-cooper-2026-10-05/dawn-stakes.md(#9 fire department, #11 fifty trips, #12/#13 with staging limits, see §7). skills/cartoon-h3/SKILL.mdSHARED BODY + HOOKS × LEADS MATRIX (hook-only use). Song bodies:project_song_lane_2026-09-19memory (hooksplice flow).
2. When to use / when not
- Two uses. (A) Hook-only (default entry): a 3-5 s skit replaces the opening of a body that already sells; one variable, cheap (one H3 batch), read on hook rate + CPA. (B) Standalone skit: 12-30 s, its own gag → turn → buzz → CTA.
- Evidence status: untested on Dawn. Beaverpro (Foreplay #1, 15 s, 100% AI slapstick) runs for hair oil, but it's unaware traffic with no CTA. REPORT §3 rates skits Low for Dawn because the awareness gate needs a symptom callout. So the callout is non-negotiable and (A) comes first: it tests whether a gag opening beats our current opening without betting a whole concept on it.
- Don't use for: pure absurdity with no symptom on screen (unaware lane is parked); violence gags (stake bank #10, the swing at mom); gags that need photoreal people (avatar gates, core §3); crowd gags of teen-age extras (identity contamination); recipe A stories. A skit can't build an accuser and a vindication in 20 s, so leave those to songs and spoken drama.
3. The format
- 9:16, animated: pixar / disney3d / claymation (exaggerated faces carry the comedy; one style per ad, anchored on a paying frame). No photoreal.
- Standalone: 12-30 s ≈ 40-100 spoken words at 3.4-3.8 wps. Hook-only: 3-5 s ≈ 10-17 words, then the base body.
- Frame 0 = ONE readable picture: the kid asleep, ONE absurd noise source at full blast, mom deadpan in the doorway, and the overlay naming her symptom. The gag escalates 1-2 steps. The punchline is silence: the band buzzes on a wrist resting flat on the blanket, he sits up, and the dog / little sister / noise-maker in the same wide keeps sleeping. That last part is the competitor-swap test: a louder alarm can't do it.
- Sound-off first: the overlay + script captions tell the whole joke with the sound off (Beaverpro is SFX-led and unreadable muted; ours must not be).
- Reference shapes: Foreplay
01_skits(Beaverpro: crash → instant use → instant result → someone grabs for it); Zach-D grammar (analysis/gemini_IolBFaQIrl4.md): bold captions, a written hook separate from the spoken one, 3 visual-hook concepts storyboarded before committing.
4. Why it sells
- The gag buys the 3-second view; the callout makes it HER problem (problem-aware). The exaggeration states a belief she already holds ("nothing wakes him") as a literal picture, sourced from VOC (stake bank #9: "slept through the fire department coming into our apartment"). That's the concept formula: proven structure + verbatim customer line + her belief + the buyer.
- The punchline shows the mechanism instead of telling it: noise fails, touch gets through, silent to everyone else, keeps going until he turns it off.
- Recipe B (core §1): callout or confession device, her daily burden, exhaustion → relief, payoff = kid independence / calm morning, authority = the 60-night guarantee. Hook-only inherits the body's recipe (A on a song body): the skit only replaces the opening and has to hand off to the body's first line.
5. Beat sheet (full rules + word budgets in references/beat-sheet.md)
| Beat | % runtime | Job | Must contain |
|---|---|---|---|
| 1 Callout gag | 0-20 | Stop the scroll on HER | Overlay names her symptom; line 1 names it too; ONE noise source, kid asleep, mom deadpan |
| 2 Escalation | 20-45 | Raise the absurdity one step per shot | 1-2 bigger attempts, one action per shot; kid still asleep; the cost on her (time, voice, coffee gone cold) |
| 3 Turn | 45-55 | Root cause, one line | Fish's ruled line verbatim: sound doesn't reach a deep-sleeping brain |
| 4 Punchline | 55-80 | The silent buzz | Product named; wrist resting, buzz lines, eyes open, he sits up; someone in the same wide stays asleep; "keeps going until he turns it off" |
| 5 CTA | 80-100 | Offer | Product + 60 nights, spoken; this line plays UNDER the end card (optional, --end-card; off by default per Fish 10-06) (overlay, not append) |
| - Hook-only: beats 1-2 only, inside 3-5 s; it ends on the open loop (kid still asleep, her face). No product, no turn, no buzz: the body owns those, and showing the product early breaks the body's reveal. |
6. Pack spec
-
Step 0 — combo plan (feedback loop,
workflow-combo-loop):python3 scripts/combo_loop/plan.py --format format-skit --brand dawn→ pick one combo (a paying parent + ONE changed dimension) and paste its block into the pack front matter / job or spec JSON ("combo": {...}; no file →tags.py register --prefix):combo_avatarcombo_anglecombo_povcombo_authoritycombo_stakecombo_stake_oncombo_emotioncombo_root_causecombo_mechanismcombo_payoffcombo_devicecombo_formatcombo_parentcombo_variablecombo_ad_prefix(= the launched Meta ad-name prefix).python3 scripts/combo_loop/tags.py check <pack>must PASS before concept approval; the weekly refresh reads results back by that prefix. -
Core §5 keys, plus:
format: cartoon-h3,format_skill: format-skit,parent:(hook-only: the base cut with its CPA; standalone: the video it competes with, with CPA),iteration:(hook-only: "opening → skit gag, body identical"), title:(= the overlay,|splits lines),end_card:(standalone only; hook-only keeps the base's),cast:naming EVERY figure incl. extras ("the tuba player", "the dog") so clipqa doesn't flag a planned extra person. - Standalone with 3 gags:
body_start:= the turn line. The 3 gag packs share turn + punchline + CTA (shared-body cache); h1 runs to completion first. - Hook-only, EL body: copy the approved base pack and change ONLY lines 1..body_start-1 (or 1..lead_start-1) + their intents,
title,iteration,format_skill. Never touchelevenlabs_voice_id,voices,vo_tempo,max_gap,gap_same,gap_turn,seam_gap,style_*,tempo_*:vo.pyhashes voice + body speakers + voices + cfg (minushook_tempo) into the body cache key, and any change re-renders the body (paid).hook_tempois safe. A new speaker only in the hook changesvoices, so the hook speaks in the base's voices. ## VO Script: one sentence per line; every on-screen shot = one sentence ≥4 words (≥1.2 s). Shorter sentences merge into the previous beat (storyboard.py SHORT_BEAT_S = 1.2) and the gag loses its cut.## Scene visual intents:N. **role** — <env>: <ONE subject doing ONE big action>, <framing>, <kid's state>. Roles:gag,escalation,turn,product reveal(contains "reveal" → batch capped at 3 panels),cta.- Word trap:
pack.py PRODUCT_IN_FRAME_REmatches "the band", "wristband", "black band". In a marching-band gag write "the marching band" / "the tuba player", never "the band", or the gag shot gets product refs and product rules. The reverse holds too: a punchline intent must say "the band" / "Dawn band" / "black ribbed band" ("a band on his wrist" does NOT match) or the product shot goes out without the product ref. - Cast: mom + kid (11-17; vary age and gender across gags) + at most one non-human or adult noise-maker. Envs: 2-3 (teen room, hallway, kitchen).
7. Visual grammar
- No chaos in frame 0. One subject, one action, one noise source. The chaos grows across the gag, but every shot reads in one glance.
- 1-3 shots per gag, each ≥1.2 s, hard cuts on action (Beaverpro's edit; we have no last-frame chaining, so batch seams are hard cuts anyway). ≤4 panels per H3 batch; a 3-5 s hook = one batch (H3 bills a 5 s minimum,
MIN_GEN_S = 5). - Escalate by scale, not count: knock → pots and pans → tuba in the doorway → fire truck at the window. Each rung is one shot. Stop at two rungs in a hook.
- The kid is still, the world moves. The comedy is his total stillness against the noise and mom's deadpan. Mom is never the butt of the joke; the kid isn't lazy (he can't, not won't).
- Staging limits: kid dressed, on top of the covers; adults at the doorway or bedside, never leaning over him (Gemini refuses adult-over-child-in-bed frames; Higgsfield NSFW tripped on a hand on a sleeping son under a blanket). That rules out literal ankle-dragging (#12) and water-pouring (#13): show the aftermath or the doorway wide instead.
- Punchline shot (wrist rule): wrist flat on the blanket, band side-on, display dark; buzz = small cartoon motion lines at the wrist + eyes snapping open; next shot a wide where the dog / sibling / tuba player is still asleep. Never a raised wrist, never a lit face.
- No readable text in scenes (fire truck without lettering, clock hands only). Product only in beats 4-5 (standalone), never in a hook-only cut.
- Morphing: Beaverpro gets away with a third hand because nobody's looking for it. We don't tolerate it on the kid's face or the band; elsewhere a sub-second glitch in a fast gag shot is a Fish's-eyes call (Gemini samples ~1 fps).
8. Audio
| Voice choice | When | How |
|---|---|---|
| Mom deadpan narrator (default) | standalone; recipe B confession | single EL narrator, ≥3.4 wps (vo_check FAIL below) |
| Brand-voice callout | standalone; recipe B callout ("If you're his fifth alarm…") | single narrator; test vs mom as the one variable |
| In-scene shouts, no narrator | the yelling IS the gag | dialogue pack, [MOM] "Ethan. Up. Now."; staged through the door / from behind (no lip-sync, core §3) |
| Base's voice | hook-only | whatever the base pack uses (body hash, §6) |
| Wordless (gag SFX carry it) | Not built yet (needs Fish's go) | VO is the clock (every pack line is an EL take), assemble strips clip audio (-an) and lays ONE bed: no tuba, no smoke alarm on the track |
| - Silent gag pauses don't exist in this lane: narrator dead air >0.4 s FAILS vo_check. Write a line for every shot; the timing comes from the words. | ||
- One ducked bed (--music <path>). audio-library/INDEX.md has no comedic/upbeat bed (warm, cinematic, transition stings only); pick the least solemn one or source a licensed bed first (free task, Fish picks). |
||
- End card (optional, --end-card; off by default per Fish 10-06) 3 s, an overlay on the last 3 s; the spoken CTA plays under it. |
9. Production (free until core §4 gate 4)
# A) STANDALONE (style keys in front matter; refs in <slug>.args: --char-ref "label=<png>" ... --env "<room>=<png>" ... --characters "Mom, Ethan and the tuba player")
P=output/concept-packs/dawnbands-skit-<gag>-h1-<date>.md
A=(${(z)"$(python3 -m scripts.cartoon_h3.packargs $P --storyboard)"}); A=(${(Q)A}) # core §5; re-run without --storyboard once sheets exist
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage vo # EL + vo_check gate
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage storyboard # free; Fish reviews storyboard.md
touch output/cartoon-h3/<slug>/storyboard.approved # Fish only
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage canvas # paid, ~$0.22/batch
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage gen --prompts-only
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage gen --spend --backend fal --model h3-max
python3 -m scripts.cartoon_h3.run "${A[@]}" --stage assemble --title-style dragon --music <bed> # dragon = overlay held 4-6 s
# B1) HOOK-ONLY on an EL narrator/dialogue body (base = approved pack with body_start, already rendered)
B=output/concept-packs/<base>.md; H=output/concept-packs/<concept>-h<N>-l1-<date>.md # copy of B, hook lines swapped (§6)
# base already has lead_start → write ## Hook h<N> sections instead and: python3 -m scripts.cartoon_h3.matrix --base $B --variants <skit-hooks.md> --write
python3 -m scripts.cartoon_h3.run --pack $H --stage vo # log must say "body …s (shared <hash>)"
python3 -c "import json;print(json.load(open('output/cartoon-h3/<base-slug>/vo-receipt.json'))['body_hash'])" # must equal <hash>; else STOP
python3 -m scripts.cartoon_h3.run --pack $H <base refs> --stage storyboard # cache guard fails if body intents differ
# then canvas / gen as in A: log "shared segments: N clip files pulled from cache"; only the hook batch is paid
# B2) HOOK-ONLY on a SONG body (9-19 flow; hook is sung, lyrics block = base lyrics with the hook lines swapped, same suno_style)
python3 -m scripts.cartoon_h3.song --pack $H --takes 1 # kie, ~12 cr per task (2 takes)
python3 -m scripts.cartoon_h3.hooksplice --pack $H --base output/cartoon-h3/<base-slug> [--take N]
python3 -m scripts.cartoon_h3.run --pack $H --song <base refs> --stage storyboard
python3 -m scripts.cartoon_h3.hooksplice --pack $H --base output/cartoon-h3/<base-slug> --copy-body # writes body-reuse.json hook_batches
# canvas → gen → clipqa → assemble with --batches <hook_batches> (hookrun.sh does these 4 but is hard-coded to the 9-19 bluey refs: run them by hand)
- Cost: standalone 20 s ≈ 2-3 batches ≈ 20-25 gen-seconds; hook-only ≈ 1 batch (5 s min) + 1 canvas.
h3.py FAL_PRICEsays h3-max 768P $0.05/s but its own comment says $1.20/15 s: read the fal pricing page before quoting. Higgsfield 2.5 cr/s. Sheets ~$0.15-0.30 each; reuse the base's sheets for hook-only. - Shot tiers (core §2b) + draft→final (core §4 gate 6b). Tag every batch A/B/C before approval: run.py does it itself (
scripts/cartoon_h3/tiers.py, alsopython3 -m scripts.cartoon_h3.tiers <run>: A = first batch/hook, reveal/CTA/product beats, 3+ characters in a shot; C = no person in any shot; else B) intoplan.json+<run>/tiers.mdwith the per-batch fal cost; re-tag in review if the word match is wrong. Per-tier models:run.py --tier-models "A=h3-max,B=h3-max,C=h3"(fal only; default =--modelfor every tier, i.e. all H3-max).h3on B/C is a candidate until a one-batch side-by-side passes Fish's eye (registry "How to adopt"). Draft→final:run.py --draft= 480P ($0.05/s vs $0.08/s at 768P, fal page re-read 10-06) into<slug>-draft, seeded from the approved run (VO, plan, approval, canvases), never the shared-body cache, no upscale/end card (optional,--end-card; off by default per Fish 10-06); it prints the native 768P re-render command for the approved batches. Finals re-render natively, never a 480P→--hdupscale (Fish judged native sharper 10-04). A re-render is a new sample: judge staging and prompts on the draft, not the exact take. In a skit almost every shot is tier A (hook seconds, the buzz, CTA); a hook-only cut is one tier-A batch, so the draft pass costs about as much as the final: skip it unless the gag needs prompt iteration. - Limits in code: hooksplice needs an in-lane base run (
vo.mp3,lines.json,plan.json) andoutput/concept-packs/<base-slug>.mdwithbody_start. The paying songs have none today: the sl0919 runs aren't inoutput/cartoon-h3/, and exhibit A exists only as an unrendered re-skin pack. Paying parents made outside the lane: the concat step is BUILT 10-06:python3 -m scripts.cartoon_h3.concat --hook <skit-hook-final.mp4> --out <out.mp4> <paying-final.mp4> [--xfade-frames 6](size/fps follow the paying final, the hook is gained to the same -14 LUFS, burned captions untouched, receipt<out>.concat.json). A spoken skit hook in front of a song body (song.py --from-file <hook.mp3>then hooksplice) is untested: a dry voice crossfading into a sung mix is a register jump.
10. Gates & QA checklist
- [ ] Parent named with CPA; ONE variable stated (hook-only: the opening; standalone: format vs the video parent).
- [ ] Gag premise traced to a VOC line (stake bank row or review); stake lands on HER and the mornings caused it.
- [ ] Overlay + line 1 name her symptom; the joke reads with the sound off (watch it muted).
- [ ] Frame 0 = one subject, one action, one noise source; ≤3 shots per gag; every shot sentence ≥4 words.
- [ ] Punchline shows someone else still asleep (silent to everyone else); wrist rule in every product intent; display dark.
- [ ] Hook-only: no product in the hook; the hook's last line hands off to the body's first line; the body hash matches the base's before storyboard.
- [ ] No "the band" in non-product intents; every extra named in
cast:; no adult leaning over the bed. - [ ] vo_check PASS; Fish listened; storyboard approved; motion prompts reviewed; balances checked before
--spend. - [ ] Every batch tagged tier A/B/C in
storyboard.md; any draft→final pass followed §9's route (drafts never left in a shared-body cache). - [ ] Placement preview (starpop facebook-instagram-ad-sizes-and-safe-zones, how-to-preview-a-facebook-ad-before-publishing): scrub to the hook frame, the reveal frame and the end card (optional,
--end-card; off by default per Fish 10-06) on a 9:16 overlay; header, captions, product and offer sit inside Meta Reels' safe box (top 14 %, bottom 35 %, sides 6 % are UI = keep content in y 14-65 %) and survive the Feed 4:5 centre crop (~15 % lost top and bottom). Remotiontiktok/tiktokbox/dragoncaptions centre at ~68-74 % = inside the Reels bottom band on Meta: flag it to Fish, never re-burn on your own. - [ ] Final: freezes 0, dark 0, captions from the script, overlay held through the gag, end card only if
--end-cardwas asked (off by default, Fish 10-06) (standalone), Fish watched it muted AND with sound.
11. Variants & test plan
- Test 1 (default): skit hook vs current hook on the same body. Matrix anchor design: h1 = the current opening (control), h2-h3 = two skit gags, same l1 + body. Ad names
<concept>-h<i>-l1. Each cut gets its own ad set in Testing with equal floors (Meta starves shared ad sets; readout flags "Meta picked"). Meta writes need Fish's go. - Read with
python3 -m scripts.cartoon_h3.readout --concept <concept> --days 7 --write: hook rate (3 s views / impressions, floor 2,000 impr per cut, z-tested), hold rate, then CPA at 7 days. A skit wins only if hook rate is up AND CPA ≤ control. Hook rate up with CPA worse means the gag stopped people who don't buy (it drifted unaware): keep the control, log it in the hook-lead ledger. Never pause; reduce. - Test 2 (standalone): 3 gags on one shared turn/punchline/CTA body, own ad set in Testing with a floor, readout picks the gag; CPA at 7 days vs the cheapest current video parent.
- Then one variable at a time: gag premise (stake bank order: #9 → #11), narrator (mom deadpan vs brand voice), style (re-skin).
- Floor math (starpop how-much-budget-to-test-meta-ad-creatives): name the decision spend before launch = target CPA × a multiple you choose; each cut's floor ≥ decision spend ÷ 7 days. If the Testing budget can't carry 3 cuts at that floor, launch the gags in waves (h1 vs control first) instead of thinning all three.
- Upload hygiene (starpop are-ai-generated-ads-allowed-on-meta): Advantage+ creative enhancements stay OFF (Meta's tools have added music and altered products on finished ads). The launchers copy
degrees_of_freedom_specfrom a model ad and silently drop it if that post fails, which falls back to Meta's defaults: check the created creative. Day 1: open the live preview in Feed AND Reels for added music, re-crops or altered frames.
12. Failure modes
- Pure absurd opener, no symptom → great hook rate, no buyers. Fix: overlay + line 1 name her symptom.
- Chaos in the first 3 s (crowd, two actions) → the brain scrolls. Fix: one subject, one action.
- Gag beat under 1.2 s merged into the previous shot → the punch lands on the wrong picture. Fix: ≥4-word sentences per shot.
- "the band" in a marching-band intent → product refs on a gag shot. Fix: "the marching band".
- Planned extra flagged by clipqa as an extra person → name it in
cast:. - Refusal / NSFW on wake shots → doorway staging, kid dressed on top of the covers.
- Lit band or raised wrist at the buzz → wrist rule;
--regen Nthat batch. - Hook-only body re-rendered (paid) → a hash-feeding front-matter key changed; restore the base's keys and re-run
--stage vo. - Hook doesn't land into the body's first line → rewrite the hook's last line, never the body.
- Dead air where the gag "breathes" → vo_check FAIL; write a line, never pad.
13. Sources
REPORT §3 row 1 + §4; Foreplay foreplay/01_skits.gemini.md; analysis/gemini_IolBFaQIrl4.md, analysis/animation.md, analysis/diff_animation_styles.md; skills/cartoon-h3/SKILL.md; scripts/cartoon_h3/{hooksplice,matrix,readout,vo,pack,storyboard,endcard,assemble,run}.py, hookrun.sh; MAP.md; dawn-stakes.md; feedback_hook_taxonomy; corrections-hot 10-05/10-06; project_song_lane_2026-09-19.
Not built yet (needs Fish's go)
- Wordless (gag SFX carry it) Not built yet (needs Fish's go) VO is the clock (every pack line is an EL take), assemble strips clip audio (-an) and lays ONE bed: no tuba, no smoke alarm on the track
- analysis/diff_animation_styles.md: last-frame chaining across batches is not built (P1 gap), so our batch seams are hard cuts. Fine for a skit (cut on action), wrong for continuous Zach-D flow. The cheap-video path for simple-motion styles