---
name: fal-ugc-video-pipeline
description: "Use when creating Consumer AI Factory UGC/TikTok/Reels videos with FAL: pick a venture-specific angle, write a native creator prompt, generate one quality-gated FAL video, add subtitles/captions and CTA/link overlays, QA the result, and prepare it for Postiz posting."
version: 1.0.0
author: Mr Han
license: MIT
metadata:
  hermes:
    tags: [ugc, tiktok, fal, veo, video-generation, subtitles, consumer-ai-factory]
    related_skills: [consumer-traffic-sprint, posthog-venture-telemetry, paid-clipping-campaign-playbook]
---

# FAL UGC Video Pipeline

## Overview

This is the default pipeline for testing-lab short-form creatives. The goal is not to make internal mockups. The goal is to produce public-testable UGC-style TikTok/Reels assets quickly enough to learn which venture/hook earns attention and clickthrough.

The workflow is:

1. Select the venture and traffic objective.
2. Find a concrete emotional/user angle.
3. Write one native UGC prompt for FAL/Veo with an exact spoken line.
4. Generate exactly one quality-gated clip first.
5. Verify the MP4, audio, and aspect ratio.
6. Add subtitles and a small venture CTA/link overlay locally.
7. QA visually before creating more variants or posting through Postiz.

## When to Use

Use this when Antoine asks for:

- UGC videos for HappyCouple, HairMatch, Progress Photo Coach, or another Consumer AI Factory venture.
- TikTok/Reels creatives for the shared testing-lab account.
- FAL/Veo/Pika/Wan video generation.
- A cron or batch system that generates venture-specific short-form posts.
- A replacement for low-quality local placeholder videos.

Do **not** use this when:

- The task is only clipping approved source media from a paid campaign. Use `paid-clipping-campaign-playbook`.
- The user only wants a script or post caption, not a video asset.
- FAL credentials are unavailable and the user explicitly asked for photoreal/talking-head UGC; stop and report the credential blocker instead of producing toy local animations.

## Hard Rule

If Antoine asks for UGC and FAL credentials are available, **do not default to local synthetic/PIL mockups**. Use FAL first.

Local rendering is only for:

- subtitles;
- safe-zone CTA overlays;
- product screenshots/phone overlays;
- fallback placeholders clearly labelled as internal rough cuts.

## Venture Angle Map

### HappyCouple / Emma

Core product story: Emma is the app, not the creator. The creator used Emma in a real-feeling relationship-text moment.

Good angles:

- “I almost sent a text I would’ve regretted.”
- “I pasted the fight into Emma before replying.”
- “It gave me soft, direct, and repair versions.”
- “It told me what not to say, which was the sentence that would’ve made it worse.”

CTA/link:

- `happycouple.ai`
- “Paste the situation. Get the next text.”

### HairMatch

Core product story: stop guessing whether a haircut will work on your face.

Good angles:

- “I always save haircuts that look good on other people, then panic at the barber.”
- “I tested the cut on my own face before booking.”
- “This is the reference I’d actually bring to the barber.”
- “Would you trust this before changing your hair?”

CTA/link:

- `hairmatch-one.vercel.app`
- “Preview the cut before you commit.”

### Progress Photo Coach

Core product story: reduce gym-progress ambiguity; bulk/cut/recomp decision from photos + goal.

Good angles:

- “I couldn’t tell if I should bulk, cut, or recomp.”
- “My mirror lied; the weekly photo trend was clearer.”
- “It gave me one next-week plan instead of random fitness advice.”
- “Upload progress photos + goal; get the next adjustment.”

CTA/link:

- `body-guide-now.lovable.app`
- “Get a simple bulk/cut/recomp call.”

## Prompt Template

Use this structure for FAL/Veo native UGC clips:

```text
Vertical 9:16 TikTok-style UGC selfie video, filmed like a real creator on an iPhone front camera, not an ad. A relatable non-celebrity {persona} in a casual {setting}, natural daylight, slight handheld movement, imperfect framing, realistic skin texture. They speak directly to camera in a casual, honest tone and say exactly: "{spoken_line}"

The video should feel native to TikTok: low-production, human, slightly imperfect, not a polished commercial. No captions, no text overlays, no logos, no watermark, no TikTok logo, no platform watermark, no corporate presenter style, no cinematic ad lighting, no medical or clinical claims.
```

Prompt rules:

- Keep spoken line short enough for the model duration, usually 18-30 words for ~8 seconds.
- Ask for **no captions/text overlays** because local subtitles are more controllable.
- Avoid fake customer proof like “this saved my relationship” or clinical claims.
- For relationship/health/body ventures, avoid diagnostic or therapeutic claims.
- Use one creator speaking to camera unless the concept specifically needs B-roll.

## Recommended FAL Model Ladder

1. `fal-ai/veo3.1/lite`
   - First choice for creator/selfie/talking-head UGC with native audio.
   - Use 9:16, 720p, ~8s, `generate_audio: true` when accepted by the endpoint.
   - Generate one clip first.

2. `fal-ai/pika/v2.2/text-to-video`
   - Use for silent B-roll/phone-scene plates.
   - Composite TTS/subtitles/product overlays locally.

3. `fal-ai/wan/v2.2-5b/text-to-video/fast-wan`
   - Cheap exploration only.
   - Do not present it as public-quality UGC unless it passes QA.

## FAL Queue Pattern

For slower video generation, use the queue API and trust the returned URLs:

```bash
curl -sS -X POST "https://queue.fal.run/fal-ai/veo3.1/lite" \
  -H "Authorization: Key $FAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json
```

The response should include:

```json
{
  "request_id": "...",
  "status_url": "https://queue.fal.run/.../status",
  "response_url": "https://queue.fal.run/.../response",
  "cancel_url": "..."
}
```

Poll `status_url`. When complete, fetch `response_url`. Do **not** manually construct response URLs unless the endpoint omits them.

## Subtitle / Overlay Workflow

Preferred local finishing pass:

1. Download the FAL video to `raw/<venture>_<timestamp>.mp4`.
2. Create an SRT from the exact spoken line.
   - If there is no ASR available, split the exact spoken line into 2-4 subtitle chunks and time them across the clip duration.
   - If ASR exists, transcribe and use actual timestamps.
3. Burn subtitles with `ffmpeg` using high-contrast TikTok-safe styling.
4. Add a small top/bottom CTA overlay with the right venture link.
5. Export H.264/AAC 1080x1920 or model-native vertical resolution.

Caption style:

- White bold text, black border/shadow.
- Default to compact captions: roughly 7-9% of frame height for a two-line block, not giant meme text.
- Keep captions in the lower-middle safe zone, above the platform UI and below the mouth/face when possible.
- Keep lower 250px relatively clear for TikTok UI.
- Do not obscure faces/mouths.
- Keep URL/CTA small; the post caption contains the full tracked link.
- QA a midframe after the finishing pass; if captions feel too large, too high, or visually dominate the creator, regenerate the finishing pass as a versioned output like `final_subtitled_v2.mp4` instead of shipping the first burn-in.

## Script Helper

This skill includes `scripts/generate_fal_ugc.py`, a one-clip helper that:

- submits a prompt to the FAL queue API;
- polls the returned `status_url`;
- downloads the generated MP4;
- creates timed subtitles from the exact spoken line;
- burns subtitles + venture CTA overlay with `ffmpeg`;
- writes `metadata.json`, `midframe.jpg`, and `final_subtitled.mp4`.

Use it as a reusable implementation skeleton for one-off samples and cron generation. Endpoint payloads can vary by FAL model, so if a model rejects one field, revise the payload and rerun one clip — do not switch to local mockups.

See `references/subtitle-safe-zone-qa.md` for the session-derived QA rule on versioning subtitle/CTA finishing passes when the raw FAL clip is good but burn-in placement is not.

See `references/testing-lab-autopublisher-json-handoff.md` for the durable parser pattern when a Postiz publisher consumes generator stdout that may contain logs plus multiple JSON objects.

See `references/product-ui-meta-creative-generation.md` when Antoine asks for Meta/Facebook/Instagram creatives built around product screenshots, profile cards, map/opportunity animations, or outreach dashboards. In that case, treat the job as product creative generation first: use real screenshots, render 1080x1350 assets locally when appropriate, QA with vision, and use FAL only if the asset needs generated human video or b-roll.

## Output Directory Convention

Use a durable per-batch directory:

```text
/opt/mrhan/factory-vault/consumer-ai-factory-vault/07 Distribution/Testing Lab UGC/YYYY-MM-DD/<venture>/
  prompt.txt
  metadata.json
  raw.mp4
  final_subtitled.mp4
  midframe.jpg
  caption.txt
```

For quick one-off tests, `/opt/mrhan/tmp/testing_lab_ugc_fal/` is acceptable, but move approved assets into the vault before cron use.

## QA Gate Before Posting

Before reporting a video as post-ready:

- [ ] `ffprobe` confirms an MP4 with video stream.
- [ ] Audio stream exists or deliberate silent/B-roll status is stated.
- [ ] Aspect ratio is vertical 9:16 or acceptable vertical variant.
- [ ] Mid-frame visual QA passes:
  - no watermark/logo/platform contamination;
  - no obvious face/mouth/hand uncanny failure;
  - no corporate presenter or stock-ad look;
  - subtitles readable;
  - CTA/link not clipped;
  - content does not imply fake real-customer proof.
- [ ] Caption text includes the correct venture link or link-in-bio instruction with UTM.
- [ ] Asset path and duration are reported.

## Postiz / Testing-Lab Posting Context

Current testing-lab channels:

- Reddit: `u/Dapper-Analysis-6212`
- TikTok via Postiz: `@chronically.onlin313`

When preparing TikTok captions, use venture-specific links:

- HappyCouple: `https://happycouple.ai/?utm_source=tiktok&utm_medium=testing_lab&utm_campaign=ugc_{date}&utm_content={slug}`
- HairMatch: `https://hairmatch-one.vercel.app/?utm_source=tiktok&utm_medium=testing_lab&utm_campaign=ugc_{date}&utm_content={slug}`
- Progress Photo Coach: `https://body-guide-now.lovable.app/?utm_source=tiktok&utm_medium=testing_lab&utm_campaign=ugc_{date}&utm_content={slug}`

If posting via Postiz, verify the Postiz integration can see `@chronically.onlin313` before scheduling. Do not call posting “ready” until API auth, integration id, published-state polling, and public TikTok URL retrieval are each verified.

## Cron Pattern

For autonomous generation cron, separate generation from posting:

1. **Generator cron**: creates candidate prompts/videos, writes metadata, QA status, and captions.
2. **Publisher cron**: only posts assets with `qa_status=approved`.

Do not let a cron publish newly generated AI videos without a QA gate unless Antoine explicitly chooses fully autonomous posting risk. If he explicitly asks for automatic publishing, use a queue-based Postiz publisher that posts exactly one asset per run, records queue item state, and spaces posts apart instead of dumping a batch at once. Current local implementation pattern: `/opt/mrhan/hermes-home/scripts/testing_lab_ugc_postiz_autopost.py` publishes to the verified Postiz TikTok integration for `@chronically.onlin313`, seeded from `/opt/mrhan/hermes-home/state/testing_lab_ugc_post_queue.json`, then generates a new FAL asset when the queue is empty.

Three-hour cadence can rotate ventures:

```text
00:00 HappyCouple
03:00 HairMatch
06:00 Progress Photo Coach
09:00 HappyCouple
...
```

This avoids posting three TikToks at the same minute from one account.

## Common Pitfalls

1. **Using local toy videos when FAL is available.** This produces unpostable assets and wastes Antoine's review time. Use FAL first.

2. **Batching before QA.** Generate one clip, QA it, then scale variants.

3. **Letting FAL generate captions.** Ask for no captions/no overlays. Burn clean subtitles locally.

4. **Wrong venture link.** Every final caption must link to the promoted venture, not a generic lab page.

5. **Fake testimonial tone.** “I used this and it saved my relationship/body/hair” is too strong. Use “I tested / I pasted / I previewed” and show the app behavior.

6. **Overproduced ad look.** Prompts should say iPhone front camera, casual, imperfect framing, not cinematic.

8. **Ignoring TikTok safe zones.** Do not place key subtitles in the bottom UI area.

9. **Parsing generator stdout as one JSON blob.** The generator/helper chain can print queue/status logs and multiple JSON objects before the final post-ready object. Publisher scripts must not parse from the first `{` to EOF. Instead, scan stdout for JSON objects and keep the one containing the expected handoff keys, usually `final_video` and `caption`. A failure like `json.decoder.JSONDecodeError: Extra data` in `testing_lab_ugc_postiz_autopost.py` usually means the parser consumed multiple JSON objects/log chunks, not that FAL or Postiz auth failed.

## Verification Checklist

- [ ] Angle chosen from the venture map or justified as a new angle.
- [ ] Prompt includes exact spoken line and negative constraints.
- [ ] FAL generated raw MP4 and metadata is saved.
- [ ] Subtitled final MP4 exists.
- [ ] `ffprobe` duration/resolution/audio verified.
- [ ] Mid-frame QA completed.
- [ ] Caption includes the correct venture URL/UTM.
- [ ] Final asset path is reported.
