format-ai-actor-demo: she calls it out, the real band proves it
1. Read first
knowledge/ad-formats/_FORMAT-CORE.md(doctrine, lane limits, gates, launch). Binding. Photoreal people run on ugc-omni's G0-G4 gates (§10 here).knowledge/ad-formats/_MODEL-REGISTRY.md. Every model below is named by ROLE; the registry says which model fills it today.references/beat-sheet.md(skeleton, word budget, line rules, register cells),references/sources.md(davidaistar videos step by step, what we keep and drop, our receipts).skills/ugc-omni/SKILL.md+scripts/ugc_omni/omni.py: THE photoreal production engine (Fish 10-06). This skill hands it a job.json; it never re-specifies the engine. Another session owns both: reference, never edit (same forskills/ugc-omni/references/davidaistar-diff-2026-10-06.md). Example job for this format:references/omni-job.example.json.output/dawn-combo-map-2026-10-05/MAP.md§2B (recipe B) andknowledge/brands/dawnbands/product-truth.md,knowledge/brands/dawnbands/claims-register.md.- Memory:
feedback_ai_avatar_broll_lane.md(the 9-30 rules ugc-omni's gates implement),project_dawn_yapper_2026-10-04.md(why ungated band-in-hand failed),feedback_reference_images.md,feedback_ugc_avatar_wardrobe.md,corrections-hot.md(10-05: simplest recipe first; beat the leader, don't mirror it).
2. When to use / when not
- Use when Fish wants a short, cheap, high-volume video cell: one callout line that stops her, the band shown doing its one job, and a guarantee. It's also the right cell for testing a winning static's callout as video (same stake, one variable: format).
- Evidence status: untested on Dawn.
- Coded Dawn data leans against what this format does by default. In statics,
device: demoran $153 at ROAS 1.10 (n1), testimonial $26.8K at 1.50, callout-direct $190K at 1.86. Short cartoon VO ran $314 at ROAS 0 (n10). MAP §2B: a person reads like a testimonial, and testimonials lose. - So the actor's job is to deliver a recipe-B callout, not a review.
- Outside Dawn, the source claims are GMV claims (shapewear clip ~$11K GMV, sleep-gummy challenge ad ~$68.8K). Those are TikTok Shop affiliate numbers, not Meta CPA.
- Don't use for:
- The accused-mom story (recipe A →
format-song/format-spoken-drama). - Anything over ~35 s (→
ugc-omnilong form). - Any generated product frame that has not passed ugc-omni's product gate (
pick --product≥7/10, right display state). Ungated band-in-hand scored 3-4/10 on 10-04. - A clone of a competitor's ad (10-05 rule: competitors are the gap map, not the template).
- Any paid step before G0 (Fish approves script + hooks + storyboard).
3. The format
- 9:16, 15-35 s (target 25-30 s), 6-9 spoken lines. One AI actor (a mom 35-54 who already SOLVED it) talks to a propped or held phone in one home location. There's a scene change at the demo.
- What the viewer sees:
- Hook to camera.
- One problem line, over real "kid sleeps through it" b-roll.
- The demo: on the scene change the band is already lying on the counter in front of her; on the demo line she picks it up and rests it across her palm toward the lens (continuous reveal, gated frames). Then b-roll of the band doing its job (on a sleeping kid's wrist, buzzing, the kid sitting up): gated omni b-roll, or real footage as the fallback. Her voice keeps running underneath.
- The result back on her face (calm kitchen, coffee).
- CTA, then an end card (optional,
--end-card; off by default per Fish 10-06) with the real product cutout. - Captions are script words on every line, plus a hook overlay on frame 0. "Dramatization" label on-screen or in primary text (Fish 10-06, all photoreal people ads).
- Reference shapes, paraphrased (never copied):
- davidaistar Rqim7SlMtZg: AI actress, proven TikTok Shop motion, product kept real.
- gpzy2ofG0Dw: "playful challenge" hook → time jump → proof.
- PmXqgiFn9_Y: 15-30 s "caveman English" native-voice talking head.
- CZwfTy7jZcQ: hook → problem → product → demo b-roll → CTA.
- Register options (one per ad): plain callout (default), challenge, caveman cell (Fish's ruling needed, see §11).
4. Why it sells
- Recipe B (MAP §2B):
- Brand-voice-style callout to HER ("If you're still the one waking him up…").
- Her daily burden as the stake.
- Exhaustion → relief.
- Authority = guarantee or science, not the actor's opinion.
- Payoff = his independence or her quiet morning.
- The actor adds a human face to the callout. The real demo adds proof the viewer can't get from a static: the band visibly buzzes and a kid gets up.
- Problem-aware: line 1 names her by an observable symptom ("…the seventh alarm", "…still knocking at 6:40"). The hook = emotion + curiosity gap + high stakes, starts in action, zero backstory.
- Why the product gate: a demo only persuades if the product looks real. A morphing generated band undoes the proof and breaks product truth, so every frame that carries the band is scored against the real pack before it becomes video (ugc-omni §5); real footage covers any shot that won't pass.
5. Beat sheet (full rules + word budget in references/beat-sheet.md)
Budget for 25-30 s at the locked Omni pace (~2.6-3.0 wps): 65-85 words, every line ≤10 s (Omni's cap), most lines 8-16 words.
| # | Beat | % runtime | Words | Visual | Must contain |
|---|---|---|---|---|---|
| 1 | Hook to camera | 0-12 | 8-14 | A-roll, avatar frame |
Her symptom/stake in action, 2nd person; overlay = this line; no product, no backstory |
| 2 | Problem in one line | 12-28 | 12-20 | real "sleeps through it" b-roll over her voice | The burden (knocks, trips, alarms) + root cause: sound doesn't reach a deep-sleeping brain; failed solutions generic |
| 3 | Demo | 28-60 | 18-26 | scene change (scene2, band on the counter) → product line product: true, end_frame: holding → band b-roll (gated omni or real) |
Touch gets through; silent to everyone else; keeps going, stronger, until he turns it off. Product named once |
| 4 | Result | 60-82 | 10-16 | A-roll scene2 (her calm morning) or real "kid out the door" b-roll |
Payoff on HER (she isn't the alarm anymore) + his independence |
| 5 | CTA | 82-100 | 8-12 | A-roll, then end card (optional, --end-card; off by default per Fish 10-06) 2.5 s |
"60 nights" guarantee (risk reversal, not the headline); no price spoken |
6. Pack spec (ugc-omni job.json, one job per ad)
-
Step 0 — combo plan (feedback loop,
workflow-combo-loop):python3 scripts/combo_loop/plan.py --format format-ai-actor-demo --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. -
Start from
references/omni-job.example.json(this format's shape, illustrative lines), validated againstskills/ugc-omni/job.example.json's schema. New slug per run. - Core §5 keys go in as top-level fields (omni.py ignores extra keys):
format: ugc-omni,format_skill: format-ai-actor-demo,brand,created,status,parent(the paying static/native whose callout this carries, with its CPA),iteration(the ONE variable),title,overlay(hook text),label: "Dramatization". - Engine keys:
style: photoreal,mode: cuts,aroll_model: flash,resolution: 1080p,image_arms: ["gpt2", "sd5"](Nano Banana retired 10-06),product_refs: ["@dawn"],product_name: "Dawn Band",product_truth= core §1 wording + ugc-omni's display-off sentence.say: {"\\bADHD\\b": "A-D-H-D"}; numbers spelled out intext. lines[]from the beat sheet:id,text,visual("AI UGC"or"broll:<id>"),hook(H1-H3 on line 1 only),frame(avataruntil the demo,scene2from the demo on), plussrc(the VOC/stake ID; extra key, required by this skill).- Product line (beat 3, first demo line):
visual: "AI UGC",frame: "scene2"(scene2 is picked--product: band lying on the counter),product: true,end_frame: "holding". - Every other A-roll line: no
productkey; hands low. prompt(the lock):scenestarts with the camera ("Static locked-off shot, UGC iPhone footage of a mom in her kitchen in the morning..."),says: "The woman says:",rules("Pace... One take, no jump cuts. Same avatar, same location, same camera framing. Do not recompose the shot. No captions, subtitles or on-screen text."), andproduct_action: one fixed sentence, natural hold: "She picks the band up off the counter and rests it across her open palm toward the camera, close to the lens; it stays in her palm and in frame." Never pinched upright between fingers.avatar: genetic change,wardrobe: "keep"(Fish 10-06; if the ref's top is grey/blank, pick another ref or name a specific real garment, never plain/basic; no grey tops), accessories, audio logic,background: keep. No watch or bracelet on her wrists (reads as a smartwatch).broll:{prompt, outfit, motion, duration}per KJ; band shots addproduct: true(display off); scenes without her setavatar: false. Real-footage fallback: same id,prompt: "REAL FOOTAGE",avatar: false; copy the clip to<job>/broll/<id>.mp4and never runbrollon that id.- Voice: no
voicepreset unless lock takes drift (thenvoice --spend, one change per roll).
7. Visual grammar
- A-roll: chest-up, phone propped at eye level or held. Never more than ~6 s straight on her face (
boardwarns at 7 s); never 4+ b-roll lines without a cut back to her. Hands low on every non-product line. - Scene change (
scene2: same actor, new spot, e.g. kitchen counter) lands on the demo line, with the band already in shot. That's KJ's ~60% re-hook pulled earlier for a short ad, and where he lands the product. - Product on screen (ugc-omni §5 gate, Fish 10-06): CLOSE framing (in a wide shot the band loses its ribs). Display off: every product prompt carries "Display off: a plain black ribbed silicone strap of even width all the way around, no visible screen, no screen pod, no raised module, no glossy rectangle; it looks like a plain sports band." Worn on a wrist or resting across a palm, never pinched upright. Continuous reveal:
scene2(band on the counter,--product) → product line →end_frame: holding(--product).product_actionlocked separately at G2. - Band b-roll: gated omni b-roll (band on a sleeping kid's wrist; kid sits up) with
pick --name broll_<id> --product. Real footage fallback when a frame won't pass: Fish's Dawn b-roll,python3 scripts/clip_library.py search --tags dawn-raw,product,waking-up --all -n 20(folderclip-library/raw/dawn-broll-2026-09-10/DAWN BROLL/: Jessica kid sleeping wearing the band, band vibrating on a counter, LoriIMG_3496/IMG_3546kid sits up,IMG_3458wrist-POV alarm off, KrisIMG_3223-3234teen out the door). Use.h264-clean.mp4files, never the "captions" versions. Dark display preferred; a real lit LED only with Fish's ok. - No readable text except overlay and captions. No logos. A boring, lived-in real reference frame, not an aspirational one (
feedback_reference_images.md).
8. Audio
- A-roll voice = Omni's native voice from the locked prompt. No ElevenLabs on the actor (Fish 10-04). CAPITALISE the stressed word; captions drop the caps.
- Her voice runs continuously under the b-roll (assemble maps only A-roll audio, so real clips are muted).
- No music bed, or a very low one; a TikTok-Shop demo reads as a person talking.
- Pace = the locked take's native speed.
verifyflags <2.6 wps, holds ≥0.4 s, cut-offs, transcript <0.90.
9. Production (ugc-omni; every paid step dry-runs until --spend)
# run from ~/.openclaw/workspace; job.json per §6
O=scripts/ugc_omni/omni.py; J=output/ugc_omni/<slug>
# G0 (free): script + hooks + storyboard
python3 $O mine <real mom-talking-to-phone URLs...> --keywords alarm,morning # FB/IG creators for 35-54
python3 $O board --job $J # structure clean; only "frame not picked yet" errors may remain → Fish
# G1: reference frame + avatar + product frames
python3 $O refscan --job $J --src <chosen video>
python3 $O ref --job $J --pick $J/ref/<cand>.jpg
python3 $O avatar --job $J --n 3 --arms gpt2,sd5 [--spend]
python3 $O pick --job $J --name avatar --file $J/avatar/<pick>.png
python3 $O variant --job $J --name scene2 --product --arms gpt2,sd5 --prompt "<same woman at her kitchen counter, the band lying flat on the counter in front of her. Display off: ...>" [--spend]
python3 $O pick --job $J --name scene2 --product --file $J/frames/<pick>.png # refuses <7/10 or wrong display
python3 $O variant --job $J --name holding --product --arms gpt2,sd5 --prompt "<same woman, same counter, the band resting across her open palm toward the camera, close. Display off: ...>" [--spend]
python3 $O pick --job $J --name holding --product --file $J/frames/<pick>.png
python3 $O board --job $J # now fully clean
# G2: lock (motion proof): same line good 3x, hook first, then the product line
python3 $O lock --job $J --line H1-1 --n 3 [--spend]
python3 $O lock --job $J --approve $J/lock/<take>.mp4
python3 $O lock --job $J --line D-1 --n 3 [--spend] # product_action locked separately
python3 $O lock --job $J --approve $J/lock/<take>.mp4
# G3: every A-roll line + b-roll + product check
python3 $O gen --job $J --lines all [--spend]
python3 $O verify --job $J
python3 $O broll --job $J --id wristdemo --stage frame --arms gpt2,sd5 [--spend]
python3 $O pick --job $J --name broll_wristdemo --product --file $J/broll/<pick>.png
python3 $O broll --job $J --id wristdemo --stage anim [--spend]
# (fallback) cp "<real clip>.h264-clean.mp4" $J/broll/wristdemo.mp4
# G4: assembled cut
python3 $O assemble --job $J --hook H1 # repeat H2, H3
python3 $O cost --job $J
python3 scripts/meta_preflight.py $J/final/<slug>-H1.mp4
- Cost (kie, omni.py): Omni A-roll/b-roll buckets $0.315 / $0.42 / $0.525 / $0.63 for 4 / 6 / 8 / 10 s (720p = 1080p price). Images ~$0.05 (gpt2) - $0.075 (sd5) each. Typical ad: avatar 3×2 arms + 3 variants×2 ≈ $1.1; 2 lock rounds ≈ $2.5-3.2; 6 lines + 2 hook takes ≈ $3.4; 2 b-roll ≈ $0.9; regens ~+30% → ≈ $9-11 per ad with 3 hooks.
omni.py costprices the job (it counts real-footage b-roll as Omni clips: subtract those). Check kie credit first (GET https://api.kie.ai/api/v1/chat/credit). - No draft→final step: the G2 3× lock is the proof; the approved prompt makes the finals. Tiers: every A-roll take is Omni; tiers only pick b-roll (A = band/hands → gated omni or real footage; C = band-free scene → cheapest omni 4 s or a real clip).
- Image arms: pass
--arms gpt2,sd5(omni.py's own default still lists nbp; its owner changes that). - Time: ref + avatar ~1.5 h by eye; product frames ~30 min; locks ~45 min; gen + assemble ~30 min.
10. Gates & QA checklist (ugc-omni G0-G4; every gate is Fish's)
- [ ] G0 script + hooks +
board: parent named with CPA, ONE variable; every line has asrc; stake caused by the mornings and lands on her; 2nd-person callout, not a review; mechanism lines are Fish's ruled lines; copy throughdirect-response-copywriter→humanizer→ red-team (core §1). No paid step before G0. - [ ] G1 reference frame (real creator video, refscan + eye) + avatar (genetic change, not the ref person; real clothes, no grey top; bare wrists) + product frames (
pick --productpassed, display off, natural hold, close). - [ ] G2 lock: hook line, same take good 3× (the 9-30 motion proof), then the product line with
product_actiongood 3×. Judge in a fixed order: face/hair/wardrobe stable → hands → line complete, in sync → room continuity → camera calm → clean ending → captions can sit clear of her mouth. One change per roll. Nogenbefore G2. - [ ] G3 every A-roll line watched (
verifyclean or each flag accepted; voice consistent by ear); every b-roll frame + band checked by eye against the real pack. - [ ] G4 assembled cut by eye and ear: captions = script, "Dramatization" label, end card only if
--end-card,meta_preflightrun. Say what you could not verify (lip-sync, voice likeness). Scores never pass a gate alone; Gemini QA is not a gate.
11. Variants & test plan
- Minimal test (G1-G2, ~$2): avatar rolls +
lock --n 3on the hook line. Fish judges realism, lips and voice. Stop here if it fails. - Full test: one ad, 3 hooks on a shared body (
assemble --hook Hn). Hook directions: (a) her burden count ("the seventh alarm in this house is you"); (b) stake on her (the school letter / late to her own job); (c) challenge ("can a wristband get a kid who sleeps through six alarms up in one buzz?"). - Launch: own ad set in Testing CBO (core §6). Read at 7 days on CPA vs the parent static, plus 3-s hold and lifetime frequency. Never pause; reduce.
- Then one variable per ad set: register cell (plain / challenge / caveman); actor (age, ethnicity); setting (kitchen / car at drop-off / hallway); length (15 vs 30 s); band b-roll (gated omni vs real footage); lane (AI actor vs real creator fallback A).
- Caveman cell: broken, literal short sentences ("Alarm loud. Kid sleep. Mom tired."). It fails the said-out-loud rule on purpose. Only if Fish rules the register in, never on an ADHD line, native voice only.
- Side arms (one variable vs the locked omni baseline, ugc-omni §6 recipe discipline):
mode: oneshotyapper single take (no b-roll; reveal viaend_frame); H3 native-voice yapper take (yapper.py); avatar arm A/B (pick the other arm's roll asavatar_sd5, thenlock --frame avatar_sd5). Seedance 2.5 product shots stay rejected (Fish 10-06).
12. Failure modes
- Band wrong in a generated frame (smartwatch pod, smooth ribs, lit face) → re-roll the frame (never patch);
pick --productrefuses <7/10; tighten framing and keep the display-off sentence; still failing → real footage. - Hand drops / band leaves frame mid-line →
product_actionmissing or unlocked; lock it on the product line (10-06 test: hand dropped at 0.25 s without it). - Pinched-upright band → rewrite the hold (worn, or resting across the palm).
- Watch on her wrist → bare-wrist avatar; re-roll the avatar.
- Testimonial drift ("I love it, five stars") → rewrite to a callout plus guarantee/science authority (MAP §2B).
- Voice drifts between takes → regen the worst take; then the
voicepreset (one change); never ElevenLabs over her. - Model says quoted words twice / adds words → transcript <0.90;
gen --lines X --redo. - Line too long for a bucket →
plan_lineerrors past 10 s; split it. A 10-word line at 4 s gets cut off (10-06): budget 6 s. - Real clip with burned-in captions or the wrong kid age → swap the clip; Kris has teen footage, Jessica/Lori younger boys.
- Provider refuses the face → another ref/route. Never blur, crop or distance a face to get past a likeness filter.
- ~1 in 10 avatars won't animate → new reference frame; don't fight the model.
- Fallback A, real creator + AI b-roll: cut a real Dawn creator's lines (clip library, or a new creator via
ugc-engine/sops/04-outreach-sop.md: perpetual paid usage, $200/video cap) intoaroll/<id>.mp4, settextto her real words,pick --name avatara still from her clip, thenverify→assemble. Confirm usage rights with Fish. - Fallback B, animated (cartoon-h3 narrator): EL mom narrator over literal shots, no lip-sync, band from the cartoonified ref with the wrist rule; pack per
format-spoken-drama§6 minusvoices:. Weakest prior (short cartoon VO = 0 purchases on n10). - NOT BUILT (needs Fish's go): a GMV-ranked TikTok Shop sourcing tool; in-model extend.
13. Sources
- davidaistar:
~/research/davidaistar/REPORT.md;analysis/gemini_Rqim7SlMtZg.md,gemini_gpzy2ofG0Dw.md,gemini_PmXqgiFn9_Y.md,gemini_CZwfTy7jZcQ.md,analysis/ugc_seedance.md,analysis/diff_ai_ugc.md,analysis/diff_cloning.md,foreplay/06_yapper.gemini.md; transcripts intxt/. - Our code:
skills/ugc-omni/SKILL.md,scripts/ugc_omni/omni.py,scripts/yapper/yapper.py,scripts/clip_library.py,scripts/register_dawn_broll.py,scripts/cartoon_h3/endcard.py. - Dawn data: MAP.md,
output/dawn-combo-map-2026-10-05/aggregate.txt, product-truth, claims-register. - Memory files in §1, and
project_ugc_engine.md.
Not built yet (needs Fish's go)
- NOT BUILT (needs Fish's go): a GMV-ranked TikTok Shop sourcing tool; in-model extend
- Motion transfer / recast is not wired (registry: NOT BUILT)
- Extend as a candidate role (registry: video extend, NOT BUILT)