Ugc video producer skill

Use when the user wants an end-to-end hyper-realistic UGC avatar video/ad for a digital or physical product — a talking-head spokesperson clip where the character looks real enough to look twice, says scripted copy in a chosen voice with lip-sync, and (for digital products) shows the real ebook/app on a device screen or (for physical products) holds the real product.

by kofiowusuai-lab·MIT license·★ 1 Stars on the repo·GitHub ↗

Use now

Inside this skill

SKILL.md · the author's own words
# UGC Video Producer

Produce a finished, hyper-realistic UGC talking-head ad from a product + script, using only tools that exist in this environment. Build ads…

> **READ FIRST: `reference/ugc_qa_bank.md`** — generation principles distilled from real productions
> (every entry is a mistake we already made, turned into a rule). It will save you the failures around
> clip length vs VO, flaky Grok video, voicing, screen/product staging, captions, and loudness. Append
> to it whenever a render breaks in a new way.

**Task monitor lane:** open this job's task monitor with `--lane ugc` so it routes to the UGC OPS chat (@UGCOPSbbot), separate from Before…

## Phase 0 — get the script (when handed only a product)

If the user gives you a **product** ("make a UGC ad for the AI Mastery Collection") and **not** a finished
script, do NOT improvise the copy — that's the weak link that decides whether the ad converts. Invoke the
**`ugc-ad-strategist`** skill first. It researches the audience + live winning ads, picks the single claim,

Word-for-word excerpt, not a result. Read the full SKILL.md ↓

Files of Ugc video producer

kofiowusuai-lab/main1 file shown
SKILL.md
Show the full text177 lines

UGC Video Producer

Produce a finished, hyper-realistic UGC talking-head ad from a product + script, using only tools that exist in this environment. Build ads as stitched 6–10s shots (Grok's hard limit), holding one consistent character across all of them.

READ FIRST: reference/ugc_qa_bank.md — generation principles distilled from real productions (every entry is a mistake we already made, turned into a rule). It will save you the failures around clip length vs VO, flaky Grok video, voicing, screen/product staging, captions, and loudness. Append to it whenever a render breaks in a new way.

Task monitor lane: open this job's task monitor with --lane ugc so it routes to the UGC OPS chat (@UGCOPSbbot), separate from Before Freedom — e.g. ID=$(~/.openclaw/scripts/task-monitor start "<short task name>" --lane ugc --stages "...").

Phase 0 — get the script (when handed only a product)

If the user gives you a product ("make a UGC ad for the AI Mastery Collection") and not a finished script, do NOT improvise the copy — that's the weak link that decides whether the ad converts. Invoke the ugc-ad-strategist skill first. It researches the audience + live winning ads, picks the single claim, writes the 6 hooks + the beat sheet (per-clip dialogue/emotion/action/grok_prompt/overlay), sets the platform cuts + voice.

It returns brief.json (contract: ugc-ad-strategist/reference/brief_schema.json). Read it and drive Phases 1–6 straight off it:

  • base_still_prompt → Phase 1 character identity.
  • each clips[] entry → one shot: dialogue is the spoken line, grok_prompt is the ready Phase-3 prompt, emotion/action are the delivery/camera directives, overlay is the burned caption.
  • a clip with screen_asset (digital product proof beat) → Phase 5 via ugc-device-screen with that pdf + pages, driven_by telling you whether the avatar scrolls it or a video plays.
  • a clip with product_shot (physical book beat, e.g. a true "hardcopies sold out" angle) → first build a photoreal hardcover from the REAL cover: python3 scripts/book_mockup.py --book <vol> --hold hands (or --cover <product_shot.cover_image>), run the codex/grok command it prints, then anchor that mockup into her hands (Phase 5 physical path). Never let Grok invent the cover. Only voice a sold-out line if product_shot.scarcity is set (the strategist sets it only when verified true).
  • voice.id/settings → Phase 4. hooks[] → generate the hook clip per variant for testing (tag by utm_content).

If the user hands you a script directly, skip Phase 0 and start at Phase 1 (back-compat).

If the user hands you an IMAGE ("bring this to life" / "animate this"), skip Phase 1 — that image IS the identity anchor. Go straight to Phase 3: grok image_to_video image="<their image>" duration=10 resolution_name="720p" prompt="Continue from this exact still: same person, same wardrobe, same setting, handheld micro-shake, natural blinks + small gestures, direct eye contact; he/she says: \"<line>\"". Then Phase 4 (voice via STS → pick a voice that matches the face, QA Bank D5). If the supplied image is low-res or stylized, optionally do ONE Codex image_edit pass first ("render this person fully photorealistic, keep the EXACT same face") — same trick as B1b — then animate. View a frame before voicing.

Phase 0.5 — STAGE THE SHOT (intake + shot plan, BEFORE any still)

Do NOT improvise a base-still prompt. Composing the scene yourself is how every format collapses into one lone talking-head in a generic room. Even in native (vision) mode, the shot planner writes the anchor prompt(s) for you — after you lock the format, people, camera angles, and continuity. The realism directives in scripts/realism_prompts.md are the ingredients; the planner is what decides the recipe for this specific ad. Skipping it is the mistake that produced the jump-cut-to-the-same-pose artifacts.

Step A — intake (ask up front, in ONE batch, before generating anything). If the user handed you only "make a UGC video" with no specifics, you are missing the inputs the planner needs. Collect them in a single AskUserQuestion/message round, never one at a time:

  1. What are we making — the product + the core message/claim (the planner's --request/--product).
  2. Format — talking_head / street_interview / podcast (or auto to let the planner pick).
  3. Spokesperson — gender/age/vibe, or "I'll send a reference photo" (best likeness), or me.
  4. Continuity — "Should these chain into one continuous video (a different angle per cut), or are independent cuts from the same identity fine?" → --continuity continuous|multiclip|auto.
  5. Platform + total length — TikTok/Reels/Shorts and ~15/30/45s (drives how many 6–10s shots).

If Phase 0 already ran (brief.json exists), most of this is answered — use base_still_prompt and the clips[] framings as the plan and skip straight to Phase 1. Phase 0.5 is for when you were handed a bare product/idea and no brief. If the user handed you an IMAGE, skip this entirely (that image IS the anchor — go to Phase 3).

Step B — run the planner. It picks format, people count, camera angles, and the continuity treatment, and writes a ratio-correct, Photorealism-Engine-grade image_prompt per frame:

~/.openclaw/scripts/ugc_shot_planner.sh --request "<what the user asked>" \
  [--product "<...>"] [--context "<audience/claim/angle>"] \
  [--format auto|talking_head|street_interview|podcast] \
  [--continuity auto|continuous|multiclip] \
  --out <run>/shot_plan.json

Read shot_plan.json → frames[].image_prompt. Format rules the planner enforces (trust them):

  • talking_head / testimonial → 1 frame, exactly ONE person, direct to camera.
  • street / public interview → one TWO-person frame per location (interviewer frame-LEFT with a visible handheld mic, guest frame-RIGHT). NEVER one lone person; the mic is ALWAYS visible.
  • podcast → several labelled angle frames (wide establishing, host close-up, guest close-up, optional over-shoulder), all the SAME people/wardrobe/set.

Continuity standard: when the plan is continuous/multi-angle, generate a SEPARATE anchor still per framing (re-pose/re-frame the SAME identity via Codex/Grok image_edit — change camera distance, height, and subject angle while holding face/wardrobe/set). That is what turns a jump-cut-to-the-same-pose into a natural multi-angle edit. multiclip may reuse one anchor but should still vary framing between clips. Re-run the planner on every new scene/location/hard cut; continuation clips in the SAME setting chain from the previous clip's last frame instead.

Native-mode handoff: unlike MiniMax mode (which hands the prompt to the user), here YOU generate the still — feed each image_prompt to Phase 1 (Codex image_gen/-i reference, or Grok image_gen) and View it before animating. If Claude is unavailable, the interview-only fallback is python3 ~/.openclaw/scripts/ugc_interview_prompt.py --topic "<t>" --setting mall|street.

Pipeline (each stage uses a verified tool)

⚠️ CHECK YOUR MODEL FIRST

Self-test: if you CANNOT Read/see an image, you are on MiniMax (Codex capped).

  • On MiniMax → STOP and follow the ugc-minimax-mode skill instead. It is the complete pipeline (Claude shot-planning + scriptwriting + anchor handoff to the user + Grok candidates + Claude vision QA + delivery + voice). Do NOT use the numbered steps below — you are blind and will collapse every format into one lone person.
  • On Codex / gpt-5.5 (native vision) → use the numbered steps below, unchanged. Codex composes and QAs natively; the MiniMax skill does not apply.
  1. Character identity — generate ONE base still of the spokesperson. Use the image_prompt from Phase 0.5's shot_plan.json (or base_still_prompt from brief.json) — do not write it from scratch. Codex image_gen.imagegen (via codex exec) or Grok image_gen. Save it as the identity anchor; every later shot references it. The realism directives in scripts/realism_prompts.md are already baked into the planner output; apply them manually only if you're editing a prompt by hand, so it reads as a real phone photo, not AI gloss.
  2. Stage each shot / keyframes — Grok or Codex image_edit from the base ref to make per-beat poses/expressions/settings, keeping the SAME person. For pose variety in one shot, make 2–4 keyframes.
  3. Animate — Grok image_to_video (single still) or reference_to_video (multi-keyframe). 6 or 10s, 720p, no audio input. Put the spoken line in the prompt as dialogue; Grok renders native lip-synced motion + mannerisms. Use a LOCKED-OFF camera when a screen or product must stay pinnable in post.
  4. Voice + lip-sync — default to STS, not TTS (QA Bank D1/D2). Grok already speaks the line inside the clip with matching lip motion, so voiceswap speech-to-speech swaps the timbre to the chosen voice while preserving timing + lip-sync — no stretch artifacts. If voiceswap's silence-segmenter rejects a chunk, STS the whole-clip audio and mux back (reference/../../ugc_pipeline/vol1_soldout/sts_voice.sh is a working reference: clean wav → voiceswap.sts → ffmpeg -map 0:V:0). Use scripts/voice_and_lipsync.py (ElevenLabs TTS, stretch, optional WaveSpeed re-sync) ONLY when the stretch factor stays ~0.8–1.25× — a long line in a 6s clip stretches to ~0.65× and chipmunks.
  5. Product in the scene:
    • Digital product (ebook/course/app): use the ugc-video-producer companion skill ugc-device-screen to pin the REAL PDF/app on a phone/laptop screen with sharp text. Rule: a screen only moves when the avatar drives it or a real video plays in it.
    • Physical product: Grok cannot invent a real product faithfully. Feed a REAL product photo as a reference: either reference_to_video with the product photo + the staged character keyframe, or image_edit the product into her hands/desk in the still BEFORE animating. Keep the real photo as the source of truth for label/shape.
    • Physical BOOK (digital product with a real/sold-out hardcover): there's no product photo, so build one from the REAL cover. python3 scripts/book_mockup.py --book vol1 --hold hands resolves the true cover (~/code/aimastery-salespage/covers/), prints a leak-proof "wrap the exact cover on a 3D hardback" prompt + the codex/grok command. Generate the mockup, then anchor it (image_edit into her hands or reference_to_video). The cover stays identical; only its physical form is generated. Dual-proof "sold out → ebook" ad: one beat holds the sold-out hardcover (book_mockup.py) + a true scarcity line, a second beat shows the real ebook on her screen (ugc-device-screen), CTA → the ebook funnel. Run the sold-out line ONLY when it's actually true (else it's false and breaks house style).
  6. Trim tails, then stitch.
    • Trim trailing dead air FIRST (especially for multi-shot pieces where short lines sit in fixed 6/10s containers): python3 scripts/trim_clip_tails.py --glob '<dir>/clip*.mp4' --out-dir <dir>_trimmed --tail 0.5. Each clip is cut to end 0.5s after the last spoken word; clips that already end tight are padded with a held last frame so every clip ends with a uniform 0.5s tail. Detect speech-end by DIRECT RMS windowing, NOT silencedetect — Grok fills the post-speech tail with low-level room tone that never drops below −20 dB, so silencedetect/reversed-silence report ZERO trailing silence even when there's 1–3s of dead air. The RMS method (last window above ~6% of peak) finds the true voice end.
    • Stitch — scripts/stitch_shots.sh out.mp4 shot1.mp4 shot2.mp4 ... joins shots into one vertical ad (uniform 720x1280/24fps). Grok clips carry TWO video streams; force -map 0:v:0 -map 0:a:0 per clip (the bundled stitch auto-selects, but map explicitly when scripting).

Grok video model pin (MANDATORY)

Every Grok video call — image_to_video, reference_to_video, or any clip generation — MUST run on the grok-build model. The default grok-composer-2.5-fast does NOT expose the video tools as native first-turn tools, so a headless agent burns its whole turn budget and exits "max turns reached" with no MP4 (the old ~42% silent-fail rate). image_gen / image_edit are fine on the default model and need no pin.

  • Preferred: python3 ~/.openclaw/scripts/grok_imagine.py video --prompt "..." --image /abs/frame.png --out /abs/out.mp4 — already pins -m grok-build, --max-turns 16, a 600s timeout, and harvest/retry. Use it whenever you do not need session continuity.
  • Raw grok (only for --single seed-image or --continue last-frame chaining): you MUST add -m grok-build --max-turns 16, e.g. grok -m grok-build --max-turns 16 --single "Call the image_to_video tool exactly once. ...".
  • Never run raw grok --single/--continue/-p for video without -m grok-build.

Quick commands

# Base still (Codex). NOTE: -i is variadic and eats the prompt -> pass prompt via stdin.
echo "<realism prompt>" | codex exec --skip-git-repo-check -s workspace-write -i ref.png - 

# Animate (drive via the Grok CLI; it calls image_to_video / reference_to_video)
grok -m grok-build --max-turns 16 -p 'Call image_to_video image="/abs/shot.png" duration=10 resolution_name="720p" prompt="...she says: \"<line>\"..."' --always-approve

# Voice + lip-sync a finished shot
python3 ~/.claude/skills/ugc-video-producer/scripts/voice_and_lipsync.py \
  --clip shot1.mp4 --script "Okay so I finally read this..." \
  --voice kPzsL2i3teMYv0FxEYQ6 --out shot1_voiced.mp4

# Real ebook on her laptop (digital product)  -> see ugc-device-screen skill
# Stitch shots
~/.claude/skills/ugc-video-producer/scripts/stitch_shots.sh ad_final.mp4 s1_voiced.mp4 s2_voiced.mp4

Best workflow ordering (proven)

Script-as-dialogue in Grok → Grok renders native lip-synced motion → ElevenLabs swaps the voice (timbre via speech-to-speech, or fresh TTS) → WaveSpeed re-syncs the mouth to the final track → composite product/screen → stitch. Animating first (not TTS-first) lets Grok set natural timing the lip-sync then locks onto.

Hard constraints / gotchas

  • Grok video: 6 or 10s only, 720p max, no audio-input param. Longer ads = multiple shots stitched.
  • WaveSpeed key required for real lip-sync: ~/.voiceswap.env currently has ELEVENLABS_API_KEY but NOT WAVESPEED_API_KEY. Until that key is added, voice_and_lipsync.py --no-lipsync only muxes the voice (mouth not re-synced). Tell the user to add the key for true lip-sync.
  • Codex usage-limited (resets hourly) → fall back to Grok image_edit for stills.
  • Default casual UGC voice (female): Brittney "Social Media Voice" kPzsL2i3teMYv0FxEYQ6, model eleven_multilingual_v2, settings stability 0.45 / similarity 0.75 / style 0.30. Add filler words ("okay so", "honestly", "I'm not gonna lie") to the script for realism — not the voice settings.
  • Male avatar voices (match gender + age to the face — QA Bank D5): Eric cjVigY5qzO86Huf0OWal (smooth/trustworthy, best default for a male educator avatar), Charlie IKne3meq5aSn9XLyUdCD (deep/confident/energetic), Liam TX3LPaxmHKxFdv7VOQHJ (energetic social-media creator), Brian nPczCjzI2devNBz1zQrb (deep/authority). STS 2–3 onto the same clip and let the user pick. A user's cloned voice is a drop-in swap — only the voice_id in the STS step changes.
  • Using your own cloned voice: register it with export UGC_MY_VOICE="me=<your_elevenlabs_voice_id>", then always STS via ugc_add_voice.py --voice me, never TTS — TTS breaks lip-sync, and a cloned voice's stored ElevenLabs defaults (high style / stability) can drift to a generic accent. If yours drifts, add a VOICE_SETTINGS override for its voice_id (style 0 / stability 0.45 / similarity 1.0 / speaker_boost) in ugc_add_voice.py. A cloned voice is a drop-in swap: only the voice_id in the STS step changes.
  • Best likeness comes from a reference image, not text (QA Bank B1b / realism_prompts.md): seed Codex with an existing portrait via -i identity_ref.jpg; if the source is illustrated, add "render FULLY PHOTOREALISTIC, NOT an illustration, keep this EXACT person."
  • Identity drift across shots → always pass the base ref to image_edit and lock face/skin/wardrobe explicitly.
  • Match script length to clip: ~10s ≈ 24–28 spoken words. voice_and_lipsync.py stretches the voice to the clip; keep the factor within ~0.8–1.25x or it sounds slow/fast. Too short → dead air; too long → chipmunked.

Assets

  • Ebook PDFs: ~/Desktop/AI Mastery Guide - Complete Series/, ~/aimastery*_assets/, ~/manifestation_workbook_assets/.
  • Voice/lip-sync engine: ~/voiceswap (revoice, voiceswap, wavespeed modules).
  • Reference build + test artifacts from the first end-to-end proof: ~/ugc_pipeline/.

Companion skills

  • ugc-device-screen — REQUIRED for any digital-product shot that shows the product on a screen.
  • ElevenLabs voice options live in ~/voiceswap.
1---
2name: ugc-video-producer
3description: Use when the user wants an end-to-end hyper-realistic UGC avatar video/ad for a digital or physical product — a talking-head spokesperson clip where the character looks real enough to look twice, says scripted copy in a chosen voice with lip-sync, and (for digital products) shows the real ebook/app on a device screen or (for physical products) holds the real product. Handed only a product (no script), Phase 0 invokes ugc-ad-strategist to research the audience, pick the single claim, and write the hooks + beat sheet. Triggers: "make a UGC ad for <product>", "ship a UGC video", "spokesperson talking-head ad", "AI creator promoting the book/course", "testimonial-style ad with my product in it". Drives ugc-ad-strategist (research+script), Codex/Grok image gen, Grok image-to-video, ElevenLabs voice, and WaveSpeed lip-sync.
4---
5 
6# UGC Video Producer
7 
8Produce a finished, hyper-realistic UGC talking-head ad from a product + script, using only tools that exist in this environment. Build ads as stitched 6–10s shots (Grok's hard limit), holding one consistent character across all of them.
9 
10> **READ FIRST: `reference/ugc_qa_bank.md`** — generation principles distilled from real productions
11> (every entry is a mistake we already made, turned into a rule). It will save you the failures around
12> clip length vs VO, flaky Grok video, voicing, screen/product staging, captions, and loudness. Append
13> to it whenever a render breaks in a new way.
14 
15**Task monitor lane:** open this job's task monitor with `--lane ugc` so it routes to the UGC OPS chat (@UGCOPSbbot), separate from Before Freedom — e.g. `ID=$(~/.openclaw/scripts/task-monitor start "<short task name>" --lane ugc --stages "...")`.
16 
17## Phase 0 — get the script (when handed only a product)
18 
19If the user gives you a **product** ("make a UGC ad for the AI Mastery Collection") and **not** a finished
20script, do NOT improvise the copy — that's the weak link that decides whether the ad converts. Invoke the
21**`ugc-ad-strategist`** skill first. It researches the audience + live winning ads, picks the single claim,
22writes the 6 hooks + the beat sheet (per-clip `dialogue`/`emotion`/`action`/`grok_prompt`/`overlay`),
23sets the platform cuts + voice.
24 
25It returns **`brief.json`** (contract: `ugc-ad-strategist/reference/brief_schema.json`). Read it and drive
26Phases 1–6 straight off it:
27- `base_still_prompt` → Phase 1 character identity.
28- each `clips[]` entry → one shot: `dialogue` is the spoken line, `grok_prompt` is the ready Phase-3 prompt,
29 `emotion`/`action` are the delivery/camera directives, `overlay` is the burned caption.
30- a clip with `screen_asset` (digital product proof beat) → Phase 5 via **`ugc-device-screen`** with that
31 `pdf` + `pages`, `driven_by` telling you whether the avatar scrolls it or a video plays.
32- a clip with `product_shot` (physical book beat, e.g. a true "hardcopies sold out" angle) → first build a
33 photoreal hardcover from the REAL cover: `python3 scripts/book_mockup.py --book <vol> --hold hands`
34 (or `--cover <product_shot.cover_image>`), run the codex/grok command it prints, then anchor that mockup
35 into her hands (Phase 5 physical path). Never let Grok invent the cover. Only voice a sold-out line if
36 `product_shot.scarcity` is set (the strategist sets it only when verified true).
37- `voice.id`/`settings` → Phase 4. `hooks[]` → generate the hook clip per variant for testing (tag by `utm_content`).
38 
39If the user hands you a script directly, skip Phase 0 and start at Phase 1 (back-compat).
40 
41**If the user hands you an IMAGE ("bring this to life" / "animate this"), skip Phase 1 — that image IS the
42identity anchor.** Go straight to Phase 3: `grok image_to_video image="<their image>" duration=10
43resolution_name="720p" prompt="Continue from this exact still: same person, same wardrobe, same setting,
44handheld micro-shake, natural blinks + small gestures, direct eye contact; he/she says: \"<line>\""`. Then
45Phase 4 (voice via STS → pick a voice that matches the face, QA Bank D5). If the supplied image is low-res
46or stylized, optionally do ONE Codex `image_edit` pass first ("render this person fully photorealistic, keep
47the EXACT same face") — same trick as B1b — then animate. View a frame before voicing.
48 
49## Phase 0.5 — STAGE THE SHOT (intake + shot plan, BEFORE any still)
50 
51**Do NOT improvise a base-still prompt.** Composing the scene yourself is how every format
52collapses into one lone talking-head in a generic room. Even in native (vision) mode, the
53**shot planner writes the anchor prompt(s) for you** — after you lock the format, people,
54camera angles, and continuity. The realism directives in `scripts/realism_prompts.md` are the
55*ingredients*; the planner is what decides the *recipe* for this specific ad. Skipping it is the
56mistake that produced the jump-cut-to-the-same-pose artifacts.
57 
58**Step A — intake (ask up front, in ONE batch, before generating anything).** If the user
59handed you only "make a UGC video" with no specifics, you are missing the inputs the planner
60needs. Collect them in a single `AskUserQuestion`/message round, never one at a time:
611. **What are we making** — the product + the core message/claim (the planner's `--request`/`--product`).
622. **Format** — talking_head / street_interview / podcast (or `auto` to let the planner pick).
633. **Spokesperson** — gender/age/vibe, or "I'll send a reference photo" (best likeness), or `me`.
644. **Continuity** — *"Should these chain into one continuous video (a different angle per cut), or
65 are independent cuts from the same identity fine?"* → `--continuity continuous|multiclip|auto`.
665. **Platform + total length** — TikTok/Reels/Shorts and ~15/30/45s (drives how many 6–10s shots).
67 
68If Phase 0 already ran (`brief.json` exists), most of this is answered — use `base_still_prompt`
69and the `clips[]` framings as the plan and skip straight to Phase 1. Phase 0.5 is for when you
70were handed a bare product/idea and no brief. If the user handed you an IMAGE, skip this entirely
71(that image IS the anchor — go to Phase 3).
72 
73**Step B — run the planner.** It picks format, people count, camera angles, and the continuity
74treatment, and writes a ratio-correct, Photorealism-Engine-grade `image_prompt` per frame:
75```bash
76~/.openclaw/scripts/ugc_shot_planner.sh --request "<what the user asked>" \
77 [--product "<...>"] [--context "<audience/claim/angle>"] \
78 [--format auto|talking_head|street_interview|podcast] \
79 [--continuity auto|continuous|multiclip] \
80 --out <run>/shot_plan.json
81```
82Read `shot_plan.json` → `frames[].image_prompt`. Format rules the planner enforces (trust them):
83- **talking_head / testimonial** → 1 frame, exactly ONE person, direct to camera.
84- **street / public interview** → one TWO-person frame per location (interviewer frame-LEFT with a
85 visible handheld mic, guest frame-RIGHT). NEVER one lone person; the mic is ALWAYS visible.
86- **podcast** → several labelled angle frames (wide establishing, host close-up, guest close-up,
87 optional over-shoulder), all the SAME people/wardrobe/set.
88 
89**Continuity standard:** when the plan is `continuous`/multi-angle, generate a SEPARATE anchor still
90per `framing` (re-pose/re-frame the SAME identity via Codex/Grok `image_edit` — change camera
91distance, height, and subject angle while holding face/wardrobe/set). That is what turns a
92jump-cut-to-the-same-pose into a natural multi-angle edit. `multiclip` may reuse one anchor but
93should still vary framing between clips. Re-run the planner on every new scene/location/hard cut;
94continuation clips in the SAME setting chain from the previous clip's last frame instead.
95 
96**Native-mode handoff:** unlike MiniMax mode (which hands the prompt to the user), here YOU generate the
97still — feed each `image_prompt` to Phase 1 (Codex `image_gen`/`-i` reference, or Grok `image_gen`)
98and View it before animating. If Claude is unavailable, the interview-only fallback is
99`python3 ~/.openclaw/scripts/ugc_interview_prompt.py --topic "<t>" --setting mall|street`.
100 
101## Pipeline (each stage uses a verified tool)
102 
103> ### ⚠️ CHECK YOUR MODEL FIRST
104> Self-test: if you CANNOT Read/see an image, you are on **MiniMax** (Codex capped).
105> - **On MiniMax → STOP and follow the `ugc-minimax-mode` skill instead.** It is the complete pipeline
106> (Claude shot-planning + scriptwriting + anchor handoff to the user + Grok candidates + Claude vision QA +
107> delivery + voice). Do NOT use the numbered steps below — you are blind and will collapse every format
108> into one lone person.
109> - **On Codex / gpt-5.5 (native vision) → use the numbered steps below, unchanged.** Codex composes and
110> QAs natively; the MiniMax skill does not apply.
111 
1121. **Character identity** — generate ONE base still of the spokesperson. **Use the `image_prompt` from Phase 0.5's `shot_plan.json` (or `base_still_prompt` from `brief.json`) — do not write it from scratch.** Codex `image_gen.imagegen` (via `codex exec`) or Grok `image_gen`. Save it as the identity anchor; every later shot references it. The realism directives in `scripts/realism_prompts.md` are already baked into the planner output; apply them manually only if you're editing a prompt by hand, so it reads as a real phone photo, not AI gloss.
1132. **Stage each shot / keyframes** — Grok or Codex `image_edit` from the base ref to make per-beat poses/expressions/settings, keeping the SAME person. For pose variety in one shot, make 2–4 keyframes.
1143. **Animate** — Grok `image_to_video` (single still) or `reference_to_video` (multi-keyframe). 6 or 10s, 720p, no audio input. Put the spoken line in the prompt as dialogue; Grok renders native lip-synced motion + mannerisms. Use a LOCKED-OFF camera when a screen or product must stay pinnable in post.
1154. **Voice + lip-sync** — **default to STS, not TTS** (QA Bank D1/D2). Grok already speaks the line inside the clip with matching lip motion, so `voiceswap` speech-to-speech swaps the timbre to the chosen voice while preserving timing + lip-sync — no stretch artifacts. If voiceswap's silence-segmenter rejects a chunk, STS the whole-clip audio and mux back (`reference/../../ugc_pipeline/vol1_soldout/sts_voice.sh` is a working reference: clean wav → `voiceswap.sts` → `ffmpeg -map 0:V:0`). Use `scripts/voice_and_lipsync.py` (ElevenLabs TTS, stretch, optional WaveSpeed re-sync) ONLY when the stretch factor stays ~0.8–1.25× — a long line in a 6s clip stretches to ~0.65× and chipmunks.
1165. **Product in the scene:**
117 - **Digital product** (ebook/course/app): use the **`ugc-video-producer` companion skill `ugc-device-screen`** to pin the REAL PDF/app on a phone/laptop screen with sharp text. Rule: a screen only moves when the avatar drives it or a real video plays in it.
118 - **Physical product:** Grok cannot invent a real product faithfully. Feed a REAL product photo as a reference: either `reference_to_video` with the product photo + the staged character keyframe, or `image_edit` the product into her hands/desk in the still BEFORE animating. Keep the real photo as the source of truth for label/shape.
119 - **Physical BOOK (digital product with a real/sold-out hardcover):** there's no product photo, so build one from the REAL cover. `python3 scripts/book_mockup.py --book vol1 --hold hands` resolves the true cover (`~/code/aimastery-salespage/covers/`), prints a leak-proof "wrap the exact cover on a 3D hardback" prompt + the codex/grok command. Generate the mockup, then anchor it (`image_edit` into her hands or `reference_to_video`). The cover stays identical; only its physical form is generated. **Dual-proof "sold out → ebook" ad:** one beat holds the sold-out hardcover (`book_mockup.py`) + a true scarcity line, a second beat shows the real ebook on her screen (`ugc-device-screen`), CTA → the ebook funnel. Run the sold-out line ONLY when it's actually true (else it's false and breaks house style).
1206. **Trim tails, then stitch.**
121 - **Trim trailing dead air FIRST** (especially for multi-shot pieces where short lines sit in fixed 6/10s containers): `python3 scripts/trim_clip_tails.py --glob '<dir>/clip*.mp4' --out-dir <dir>_trimmed --tail 0.5`. Each clip is cut to end **0.5s after the last spoken word**; clips that already end tight are padded with a held last frame so every clip ends with a uniform 0.5s tail. **Detect speech-end by DIRECT RMS windowing, NOT `silencedetect`** — Grok fills the post-speech tail with low-level room tone that never drops below −20 dB, so `silencedetect`/reversed-silence report ZERO trailing silence even when there's 1–3s of dead air. The RMS method (last window above ~6% of peak) finds the true voice end.
122 - **Stitch** — `scripts/stitch_shots.sh out.mp4 shot1.mp4 shot2.mp4 ...` joins shots into one vertical ad (uniform 720x1280/24fps). Grok clips carry TWO video streams; force `-map 0:v:0 -map 0:a:0` per clip (the bundled stitch auto-selects, but map explicitly when scripting).
123 
124## Grok video model pin (MANDATORY)
125 
126Every Grok **video** call — `image_to_video`, `reference_to_video`, or any clip generation — MUST run on the `grok-build` model. The default `grok-composer-2.5-fast` does NOT expose the video tools as native first-turn tools, so a headless agent burns its whole turn budget and exits "max turns reached" with no MP4 (the old ~42% silent-fail rate). `image_gen` / `image_edit` are fine on the default model and need no pin.
127 
128- **Preferred:** `python3 ~/.openclaw/scripts/grok_imagine.py video --prompt "..." --image /abs/frame.png --out /abs/out.mp4` — already pins `-m grok-build`, `--max-turns 16`, a 600s timeout, and harvest/retry. Use it whenever you do not need session continuity.
129- **Raw `grok` (only for `--single` seed-image or `--continue` last-frame chaining):** you MUST add `-m grok-build --max-turns 16`, e.g. `grok -m grok-build --max-turns 16 --single "Call the image_to_video tool exactly once. ..."`.
130- **Never** run raw `grok --single/--continue/-p` for video without `-m grok-build`.
131 
132## Quick commands
133 
134```bash
135# Base still (Codex). NOTE: -i is variadic and eats the prompt -> pass prompt via stdin.
136echo "<realism prompt>" | codex exec --skip-git-repo-check -s workspace-write -i ref.png -
137 
138# Animate (drive via the Grok CLI; it calls image_to_video / reference_to_video)
139grok -m grok-build --max-turns 16 -p 'Call image_to_video image="/abs/shot.png" duration=10 resolution_name="720p" prompt="...she says: \"<line>\"..."' --always-approve
140 
141# Voice + lip-sync a finished shot
142python3 ~/.claude/skills/ugc-video-producer/scripts/voice_and_lipsync.py \
143 --clip shot1.mp4 --script "Okay so I finally read this..." \
144 --voice kPzsL2i3teMYv0FxEYQ6 --out shot1_voiced.mp4
145 
146# Real ebook on her laptop (digital product) -> see ugc-device-screen skill
147# Stitch shots
148~/.claude/skills/ugc-video-producer/scripts/stitch_shots.sh ad_final.mp4 s1_voiced.mp4 s2_voiced.mp4
149```
150 
151## Best workflow ordering (proven)
152 
153Script-as-dialogue in Grok → Grok renders native lip-synced motion → ElevenLabs swaps the voice (timbre via speech-to-speech, or fresh TTS) → WaveSpeed re-syncs the mouth to the final track → composite product/screen → stitch. Animating first (not TTS-first) lets Grok set natural timing the lip-sync then locks onto.
154 
155## Hard constraints / gotchas
156 
157- **Grok video:** 6 or 10s only, 720p max, no audio-input param. Longer ads = multiple shots stitched.
158- **WaveSpeed key required for real lip-sync:** `~/.voiceswap.env` currently has `ELEVENLABS_API_KEY` but NOT `WAVESPEED_API_KEY`. Until that key is added, `voice_and_lipsync.py --no-lipsync` only muxes the voice (mouth not re-synced). Tell the user to add the key for true lip-sync.
159- **Codex usage-limited** (resets hourly) → fall back to Grok `image_edit` for stills.
160- **Default casual UGC voice (female):** Brittney "Social Media Voice" `kPzsL2i3teMYv0FxEYQ6`, model `eleven_multilingual_v2`, settings stability 0.45 / similarity 0.75 / style 0.30. Add filler words ("okay so", "honestly", "I'm not gonna lie") to the script for realism — not the voice settings.
161- **Male avatar voices** (match gender + age to the face — QA Bank D5): Eric `cjVigY5qzO86Huf0OWal` (smooth/trustworthy, best default for a male educator avatar), Charlie `IKne3meq5aSn9XLyUdCD` (deep/confident/energetic), Liam `TX3LPaxmHKxFdv7VOQHJ` (energetic social-media creator), Brian `nPczCjzI2devNBz1zQrb` (deep/authority). STS 2–3 onto the same clip and let the user pick. A user's **cloned voice is a drop-in swap** — only the `voice_id` in the STS step changes.
162- **Using your own cloned voice:** register it with `export UGC_MY_VOICE="me=<your_elevenlabs_voice_id>"`, then **always STS via `ugc_add_voice.py --voice me`, never TTS** — TTS breaks lip-sync, and a cloned voice's stored ElevenLabs defaults (high style / stability) can drift to a generic accent. If yours drifts, add a `VOICE_SETTINGS` override for its `voice_id` (style 0 / stability 0.45 / similarity 1.0 / speaker_boost) in `ugc_add_voice.py`. A cloned voice is a drop-in swap: only the `voice_id` in the STS step changes.
163- **Best likeness comes from a reference image, not text** (QA Bank B1b / realism_prompts.md): seed Codex with an existing portrait via `-i identity_ref.jpg`; if the source is illustrated, add "render FULLY PHOTOREALISTIC, NOT an illustration, keep this EXACT person."
164- **Identity drift** across shots → always pass the base ref to `image_edit` and lock face/skin/wardrobe explicitly.
165- **Match script length to clip:** ~10s ≈ 24–28 spoken words. `voice_and_lipsync.py` stretches the voice to the clip; keep the factor within ~0.8–1.25x or it sounds slow/fast. Too short → dead air; too long → chipmunked.
166 
167## Assets
168 
169- Ebook PDFs: `~/Desktop/AI Mastery Guide - Complete Series/`, `~/aimastery*_assets/`, `~/manifestation_workbook_assets/`.
170- Voice/lip-sync engine: `~/voiceswap` (revoice, voiceswap, wavespeed modules).
171- Reference build + test artifacts from the first end-to-end proof: `~/ugc_pipeline/`.
172 
173## Companion skills
174 
175- **ugc-device-screen** — REQUIRED for any digital-product shot that shows the product on a screen.
176- ElevenLabs voice options live in `~/voiceswap`.
177 

Discussion

Alternatives

Make a demo video with OpenScreenMake a polished video of an app or a feature with OpenScreen's MCP tools, from storyboard to recording, editing and export, then either attach it to a pull request or draft a post on X. Use when the user asks for a demo, a demo video, a screen recording, a product video, a launch clip, a video for X/Twitter, LinkedIn or a README, or to show a change in a pull request ("add a video to the PR", "show the feature to reviewers"). Also use to set OpenScreen up for an agent, and to continue an OpenScreen demo in a new session.Creator · MITFFmpeg for Video ProductionVideo and audio processing with FFmpeg. Use for format conversion, resizing, compression, audio extraction, and preparing assets for Remotion. Triggers include converting GIF to MP4, resizing video, extracting audio, compressing files, or any media transformation task.Creator · MITfake-screencast — screenshots → simulated screen recordingTurn static SCREENSHOTS into a simulated screen recording (TSX) — a fake screencast with an animated cursor that eases to targets and clicks, a browser URL bar that updates per page, hard-cut navigations, in-page filter crossfades, smooth scroll, and a ken-burns zoom onto the payoff. Use when a beat needs to show a walkthrough of a web app / dashboard / settings page and you'd rather build it from screenshots than get (or ask for) a real screen recording — "fake a screen recording", "turn these screenshots into a screencast", "simulate clicking through the dashboard", "animate this UI walkthrough", "cursor moving through the app". Built on remotion/src/lib/screencast.tsx. This is a technique WITHIN step 2 (make-tsx): defer timeline/render/bake orchestration to make-tsx and raw crash-free TSX rules to vidtsx-2d-generator. Not for a single static page clone (use WebBrowserFrame directly) and not when the point is genuine proof of real speed/output (use a real recording).Creator · MITKhan explainerUse when the user wants a Khan Academy style explainer video, a blackboard or whiteboard lesson, a hand-drawn chalk-talk animation, a short narrated video that teaches a concept ("explain X in a video", "explainer video", "teach X in 30 seconds"), or a tutorial that draws hand-written arrows, circles and captions over product screenshots ("draw over the UI", "annotated walkthrough"), or clips cut from a YouTube video or podcast where the speaker's real audio plays under a blackboard drawn to it ("khanify this video", "clip this with the Khan visual"), especially when it must be free, local, and use no paid APIs or keys. macOS only.Creator · MIT