Video Production Workflows
Video production workflows handle standalone video generation tasks — face swapping, talking-head avatars, motion transfer, slideshows, Reddit story videos, and formula-driven style cloning. For composed multi-stage pipelines (research → video, hot topics → video), see Composed Pipelines.
Local Model Support
Section titled “Local Model Support”All video workflows support fully local execution with no external API calls. Use quality=local or quality=local-power to run entirely on-device.
Local Video Generation Models
Section titled “Local Video Generation Models”| Model | VRAM | Quality | Speed | Notes |
|---|---|---|---|---|
wan:1.3b | 8 GB | Good | Fast | Default for local preset |
wan:14b | 24 GB | High | Moderate | WAN 2.1 |
wan2.2:14b | 24 GB | Best | Moderate | WAN 2.2 (MoE), default for local-power |
ltx-video:2.3 | 8 GB | Good | Fast | LTX-2.3 distilled |
ltx-video:2 | 8 GB | Good | Fast | LTX-2 |
hunyuanvideo | 24 GB | High | Moderate | CUDA only (Tencent) |
open-sora | 16 GB | Good | Moderate | CUDA only (HPC-AI Tech) |
cogvideox:2b | 6 GB | Decent | Slow | CUDA only |
cogvideox:5b | 12 GB | Good | Slow | CUDA only |
Local TTS Models
Section titled “Local TTS Models”| Model | Quality | Voice Cloning | Notes |
|---|---|---|---|
kokoro | High | No | Default local TTS, 6 voices (3M/3F) |
chatterbox | High | Yes | Zero-shot voice cloning from single sample |
voxtral | High | No | Apple Silicon only (MLX) |
piper | Decent | No | Lightweight, CPU-friendly |
Local Music Models
Section titled “Local Music Models”| Model | VRAM | Quality | Notes |
|---|---|---|---|
musicgen-small | 4 GB | Decent | Default for local preset |
musicgen-medium | 8 GB | Good | Default for local-power |
musicgen-large | 12 GB | High | Best MusicGen quality |
stable-audio-open | 6 GB | High | Stable Audio Open 1.0 via diffusers |
Local LLM Models
Section titled “Local LLM Models”| Model | VRAM | Quality | Notes |
|---|---|---|---|
qwen3:8b | 5 GB | Good | Default for local preset |
qwen3:14b | 9 GB | High | Default for local-power |
qwen3:latest | 19 GB | Best | 32B Q4, for high-end hardware |
gemma3:4b | 3 GB | Decent | Lightweight, for local-light |
Override any model per-run: --input broll_model="wan2.2:14b" or --input bgm_model="stable-audio-open".
Face Swap
Section titled “Face Swap”Workflow: video/face-swap
Swaps a persona face onto a source image or video using FAL, then uploads the result as a Fabric asset.
# Direct URLsfab-workflow video/face-swap \ -i source_url=https://example.com/dance-still.jpg \ -i target_url=https://example.com/persona-face.png \ -v
# From org galleryfab-workflow video/face-swap \ -i source_url=https://example.com/dance-still.jpg \ -i persona_gallery_id=YOUR_GALLERY_ID \ -i persona_index=0curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/face-swap" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "source_url": "https://example.com/dance-still.jpg", "target_url": "https://example.com/persona-face.png" } }'Pipeline
Section titled “Pipeline”resolve_inputs → swap_face (FAL) → upload_result| Parameter | Type | Default | Description |
|---|---|---|---|
source_url | string | required | Base image/video to swap the face into |
target_url | string | — | Direct URL to the persona face image |
persona_gallery_id | string | — | Org gallery ID to pull the face from |
persona_index | int | 0 | Which gallery item to use |
One of target_url or persona_gallery_id is required.
Output
Section titled “Output”{ "output_path": "/tmp/face-swap-result.png", "output_asset_id": "018f...", "output_url": "https://...", "workflow": "face-swap"}Avatar (Talking Head)
Section titled “Avatar (Talking Head)”Workflow: video/avatar
Generates a single lip-synced talking-head video from a portrait image and audio clip. Uses the same provider dispatch as the AI Shorts pipeline but exposed as a standalone workflow.
# Local filesfab-workflow video/avatar \ --input actor.path=./portrait.png \ --input audio.path=./voiceover.mp3 \ --input prompt="Person speaking to camera, warm lighting"
# With a specific modelfab-workflow video/avatar \ --input actor.path=./portrait.png \ --input audio.path=./voiceover.mp3 \ --input avatar_model="seedance/2.0"# Using Fabric asset IDs (upload assets first via POST /v1/assets)curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/avatar" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "actor": {"asset_id": "018f..."}, "audio": {"asset_id": "018a..."}, "prompt": "Person speaking to camera, warm lighting", "avatar_model": "seedance/2.0" } }'
# Using direct URLscurl -X POST "$FABRIC_URL/v1/workflows/run?name=video/avatar" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "actor": {"url": "https://example.com/portrait.png"}, "audio": {"url": "https://example.com/voiceover.mp3"}, "prompt": "Person explaining with natural hand gestures" } }'Pipeline
Section titled “Pipeline”render_avatar (resolve refs → generate talking head → persist)| Parameter | Type | Default | Description |
|---|---|---|---|
actor | AssetRef | required | Portrait image (PNG/JPG) — face must be clearly visible |
audio | AssetRef | required | Audio clip to lip-sync (MP3/WAV) |
prompt | string | "Person speaking directly to camera..." | Stylistic prompt for avatar generation |
avatar_model | string | "fal-ai/kling-video/ai-avatar/v2/standard" | Provider/model ID |
AssetRef accepts Fabric asset IDs, HTTP(S) URLs, or local file paths.
Supported Models
Section titled “Supported Models”| Model | Style | Notes |
|---|---|---|
fal-ai/kling-video/ai-avatar/v2/standard | Lip-sync + head movement | Default, good quality |
seedance/2.0 | Full-body animation | Higher quality, slower |
bytedance/omnihuman* | Research-grade | Experimental |
Output
Section titled “Output”{ "video_path": "/tmp/avatar.mp4", "asset_id": "018f...", "avatar_model": "fal-ai/kling-video/ai-avatar/v2/standard"}Talking Head (End-to-End)
Section titled “Talking Head (End-to-End)”Workflow: video/talking-head
Generates a complete talking-head video from just a topic or script — no pre-existing audio or portrait required. Handles script generation, actor portrait creation, optional voice cloning, TTS, and avatar rendering in a single pipeline. Unlike video/avatar (which requires pre-made audio + portrait), this workflow is fully end-to-end.
# Minimal — just a topicfab-workflow video/talking-head \ --input topic="3 tips for better sleep"
# With explicit script and voice stylefab-workflow video/talking-head \ --input script_text="Hey everyone, here are three tips for sleeping better..." \ --input voice_style="warm female" \ --input presenter_look="professional woman in her 30s, dark hair"
# With voice cloning from a samplefab-workflow video/talking-head \ --input topic="3 tips for better sleep" \ --input voice_sample.path=./my-voice-sample.mp3
# With a pre-existing actor portraitfab-workflow video/talking-head \ --input topic="3 tips for better sleep" \ --input actor.path=./portrait.png \ --input voice_id="TxGEqnHWrfWFTfGW9XjX"# From a topic (everything auto-generated)curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/talking-head" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "topic": "3 tips for better sleep", "duration_secs": 30 } }'
# With voice cloningcurl -X POST "$FABRIC_URL/v1/workflows/run?name=video/talking-head" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "topic": "3 tips for better sleep", "voice_sample": {"url": "https://example.com/my-voice.mp3"} } }'
# With pre-existing actor + explicit scriptcurl -X POST "$FABRIC_URL/v1/workflows/run?name=video/talking-head" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "script_text": "Hey everyone, here are three tips...", "actor": {"asset_id": "018f..."}, "voice_id": "TxGEqnHWrfWFTfGW9XjX" } }'Pipeline
Section titled “Pipeline”prepare_script │ ┌───┴───┐resolve resolve_actor _voice └───┬───┘ │generate_tts → render_talking_head → finalize_output| Parameter | Type | Default | Description |
|---|---|---|---|
topic | string | — | Video topic (auto-generates script). Required when script_text is empty |
script_text | string | — | Explicit narration text (skips script generation) |
actor | AssetRef | — | Actor portrait image. Auto-generated when omitted |
presenter_look | string | "" | Actor appearance for AI generation (ignored when actor is set) |
voice_sample | AssetRef | — | Audio sample for voice cloning (MP3/WAV) |
voice_id | string | — | Explicit TTS voice ID (overrides voice_sample and auto-selection) |
voice_style | string | "" | Descriptive voice style (e.g. "warm female", "deep narrator") |
avatar_model | string | "fal-ai/kling-video/ai-avatar/v2/standard" | Avatar model override |
duration_secs | int | 30 | Target duration when generating a script |
language | string | "en" | Script and TTS language |
Output
Section titled “Output”{ "video_path": "/tmp/talking-head.mp4", "asset_id": "018f...", "script_text": "Hey everyone, here are three tips...", "voice_id": "TxGEqnHWrfWFTfGW9XjX", "avatar_model": "fal-ai/kling-video/ai-avatar/v2/standard"}Motion Transfer
Section titled “Motion Transfer”Workflow: video/motion-transfer
Animates a character image using a reference video’s motion (dance, gestures, expressions). The character performs the same movements as the driving video.
# Direct URLsfab-workflow video/motion-transfer \ -i source_image_url=https://example.com/persona.png \ -i driving_video_url=https://example.com/dance-reference.mp4
# With Seedance (full-body, higher quality)fab-workflow video/motion-transfer \ -i source_image_url=https://example.com/persona.png \ -i driving_video_url=https://example.com/dance-reference.mp4 \ -i motion_model="seedance/2.0"
# From org galleryfab-workflow video/motion-transfer \ -i persona_gallery_id=YOUR_GALLERY_ID \ -i driving_video_url=https://example.com/dance.mp4curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/motion-transfer" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "source_image_url": "https://example.com/persona.png", "driving_video_url": "https://example.com/dance-reference.mp4", "motion_model": "seedance/2.0" } }'Pipeline
Section titled “Pipeline”resolve_inputs → transfer_motion (FAL/Seedance) → upload_result| Parameter | Type | Default | Description |
|---|---|---|---|
source_image_url | string | — | Character image URL |
driving_video_url | string | required | Motion reference video URL |
persona_gallery_id | string | — | Org gallery ID to pull the character from |
persona_index | int | 0 | Which gallery item to use |
motion_model | string | "fal-ai/live-portrait" | Provider/model for motion transfer |
One of source_image_url or persona_gallery_id is required.
Output
Section titled “Output”{ "output_path": "/tmp/motion-transfer-result.mp4", "output_asset_id": "018f...", "output_url": "https://...", "workflow": "motion-transfer"}Slideshow / Carousel
Section titled “Slideshow / Carousel”Workflow: video/slideshow
Generates listicle carousels with triple output from a single run: individual PNG slides (for native carousel upload), stitched MP4 video, and multi-page PDF (for LinkedIn document carousels). Includes cross-run topic deduplication.
# Basicfab-workflow video/slideshow \ --input topic="5 AI tools that replaced my entire workflow" \ --input quality=standard
# Full controlfab-workflow video/slideshow \ --input topic="5 AI tools that replaced my entire workflow" \ --input niche="productivity" \ --input quality=premium \ --input slide_layout=numbered \ --input mixed_media=true \ --input num_items=7curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/slideshow" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "topic": "5 AI tools that replaced my entire workflow", "niche": "productivity", "quality": "premium", "slide_layout": "numbered", "mixed_media": true, "num_items": 7 } }'Pipeline
Section titled “Pipeline”generate_listicle │ ┌────┼──────────────────────────────────┐source_ generate_ generate_ generate_images voiceover bgm video_hook └────┼──────────────────────────────────┘ │ merge_slideshow_assets → compose_slides → export_pngs → assemble_video → generate_pdf → platform_metadataQuality Presets
Section titled “Quality Presets”| Preset | Images | TTS | Music | Script Model |
|---|---|---|---|---|
free | Stock | Piper (local) | Skip | qwen3:8b (local) |
budget | AI-generated | FAL Kokoro | Stable Audio | gemini-2.5-flash |
standard | AI-generated | ElevenLabs | Stable Audio | gemini-2.5-flash |
premium | AI-generated | ElevenLabs | Stable Audio | gemini-2.5-flash |
local | Stock | Kokoro (local) | MusicGen (local) | qwen3:8b (local) |
| Parameter | Type | Default | Description |
|---|---|---|---|
topic | string | required | Listicle topic |
niche | string | "" | Content niche |
num_items | int | 5 | Number of list items |
quality | string | "standard" | Quality preset |
slide_layout | string | "overlay_gradient" | Layout: overlay_gradient, numbered, card |
slide_duration | float | 3.5 | Seconds per slide in the video |
transition_duration | float | 0.5 | Transition time between slides |
mixed_media | bool | false | Generate a video clip for the hook slide (Instagram mixed-media carousel) |
style_hint | string | "" | Visual style hint for image sourcing |
brand_kit | dict | {} | Brand colors, fonts, logo |
language | string | "en" | Language for script and voice |
Output
Section titled “Output”{ "output": { "slide_png_paths": ["/tmp/slide_01_hook.png", "/tmp/slide_02_item.png", "..."], "video_path": "/tmp/slideshow.mp4", "pdf_path": "/tmp/slideshow.pdf", "hook_video_path": "/tmp/hook_video.mp4", "platform_metadata": { "tiktok": {"format": "carousel", "description": "...", "hashtags": ["..."]}, "instagram": {"format": "mixed_media_carousel", "caption": "..."}, "youtube_shorts": {"format": "video", "title": "..."}, "linkedin": {"format": "document", "post_copy": "..."} }, "topic": "5 AI tools that replaced my entire workflow", "hook_text": "I deleted 12 apps last month. These 5 replaced all of them.", "slide_count": 7 }}Reddit Stories
Section titled “Reddit Stories”Workflow: video/reddit-stories
Converts Reddit posts into narrated videos with screenshot overlays on background video — the classic Reddit story video format. Two modes: comments (top comments as individual segments) and story (post body paginated into segments).
# From a specific Reddit postfab-workflow video/reddit-stories \ --input reddit_url="https://reddit.com/r/AskReddit/comments/..." \ --input mode=comments \ --input quality=standard
# Search a subreddit for a topicfab-workflow video/reddit-stories \ --input subreddit=tifu \ --input topic="worst cooking disaster" \ --input mode=story
# Local-only (free TTS, no background video)fab-workflow video/reddit-stories \ --input reddit_url="https://reddit.com/r/..." \ --input quality=free# From a specific Reddit postcurl -X POST "$FABRIC_URL/v1/workflows/run?name=video/reddit-stories" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "reddit_url": "https://reddit.com/r/AskReddit/comments/...", "mode": "comments", "quality": "standard" } }'
# Search a subreddit for a topiccurl -X POST "$FABRIC_URL/v1/workflows/run?name=video/reddit-stories" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "subreddit": "tifu", "topic": "worst cooking disaster", "mode": "story" } }'Quality Presets
Section titled “Quality Presets”| Preset | TTS | Background Video | Screenshots | Subtitles | Voice Mode |
|---|---|---|---|---|---|
free | Piper (local) | None | 1x scale | No | Single |
budget | Kokoro (local) | Random | 2x scale | Yes | Alternating |
standard | ElevenLabs | Random | 2x scale | Yes | Alternating |
local | Kokoro (local) | Random | 1x scale | Yes | Alternating |
| Parameter | Type | Default | Description |
|---|---|---|---|
reddit_url | string | — | Direct URL to a Reddit post |
subreddit | string | — | Subreddit to search in |
topic | string | — | Search query within subreddit |
mode | string | "comments" | "comments" or "story" |
max_comments | int | 6 | Max comments to include |
min_score | int | 10 | Min upvote score for comments |
min_length | int | 100 | Min comment length (chars) |
max_length | int | 600 | Max comment length (chars) |
theme | string | "dark" | Screenshot theme: dark, light, transparent |
overlay_opacity | float | 1.0 | Screenshot overlay opacity (0.0–1.0) |
tts_model | string | preset | TTS model override |
voice_mode | string | preset | "single", "alternating", or "random" |
background_video | string | preset | Video ID, category, "random", or "none" |
quality | string | "standard" | Quality preset |
platform | string | "youtube_shorts" | Target platform |
language | string | "en" | Target language |
At least one of reddit_url, subreddit, or topic is required.
Formula Shorts
Section titled “Formula Shorts”Workflow: global/formula-shorts
Loads a VideoFormula (extracted style DNA from reference videos) and maps its constraints — hook type, segment structure, camera work, color grade, subtitle style, voice, music — onto the AI Shorts pipeline. The formula acts as a style template; the topic is new.
# Named formula (from ~/.fabric/formulas/)fab-workflow global/formula-shorts \ --input formula="my-style" \ --input topic="Why cold showers boost productivity"
# Formula file pathfab-workflow global/formula-shorts \ --input formula="/path/to/formula.json" \ --input topic="The psychology of procrastination"# With an inline formula dictcurl -X POST "$FABRIC_URL/v1/workflows/run?name=global/formula-shorts" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "formula": "my-style", "topic": "Why cold showers boost productivity" } }'Pipeline
Section titled “Pipeline”load_formula → apply_formula_inputs → [ai_shorts_pipeline]The apply_formula_inputs task maps formula fields to AI Shorts overrides:
| Formula Section | Mapped To |
|---|---|
script.hook_type | Hook style constraint in script generation |
script.tone | mood override |
script.structure.segment_types | Segment arc (e.g., hook → context → insight → CTA) |
visuals.overall_aesthetic | visual_style with color palette |
visuals.camera_work | Camera style constraints in b-roll prompts |
audio.voice | Voice gender and style overrides |
audio.music | Music mood and volume |
effects.subtitles | Subtitle highlight/inactive/outline colors, position, size |
effects.color_grade | FFmpeg filter hint and effects style |
effects.hook_overlay | Hook text overlay style |
| Parameter | Type | Default | Description |
|---|---|---|---|
formula | string or dict | required | Formula name, file path, or inline dict |
topic | string | required | Video topic (passed through to AI Shorts) |
| All AI Shorts inputs | — | — | Any AI Shorts parameter can be passed; explicit values override formula defaults |
Recreate From Format
Section titled “Recreate From Format”Workflow: video/recreate-from-format
Takes format DNA and a recreation blueprint from research/reference-format-analysis and generates an original reel plan — script, shotlist, overlay captions, and edit recipe — that follows the same structural format without copying source content. Supports generating N variants per run.
# Generate a single variantfab-workflow video/recreate-from-format \ -i format_dna_json_path="output/analysis/format_dna.json" \ -i recreation_blueprint_json_path="output/analysis/recreation_blueprint.json" \ -i topic="5 morning habits for productivity" \ -i creator_persona="confident lifestyle coach" \ -i tone="energetic" \ -i platform="instagram_reels" \ -o output/recreation/
# Generate 3 variants with TTSfab-workflow video/recreate-from-format \ -i format_dna_json_path="output/analysis/format_dna.json" \ -i recreation_blueprint_json_path="output/analysis/recreation_blueprint.json" \ -i topic="Why cold showers boost focus" \ -i creator_persona="health-focused creator, calm authority" \ -i tone="informative" \ -i platform="tiktok" \ -i variants=3 \ -i include_tts_audio=true \ -o output/recreation/curl -X POST "$FABRIC_URL/v1/workflows/run?name=video/recreate-from-format" \ -H "Authorization: Bearer $FABRIC_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "format_dna_json_path": "format_dna.json", "recreation_blueprint_json_path": "recreation_blueprint.json", "topic": "5 morning habits for productivity", "creator_persona": "confident lifestyle coach", "tone": "energetic", "platform": "instagram_reels" } }'Pipeline
Section titled “Pipeline”load_and_extract_constraints → generate_scripts → generate_shotlists_and_overlays → generate_edit_recipes → emit_recreation_artifactsPer-variant outputs
Section titled “Per-variant outputs”Each variant gets its own directory (variant_0/, variant_1/, …) containing:
script.json— structured script with per-segment narration, visual intent, emotional intensityscript.md— human-readable formatted scriptshotlist.json— beat-by-beat shot plan with framing, motion, composition typeoverlay_captions.json— timed on-screen captions matching the reference format’s overlay styleedit_recipe.json— machine-readable edit plan with transitions, pauses, music guidance, emphasis pointsvoiceover.txt— narration text (if voiceover enabled)voiceover.wav— TTS audio (if TTS enabled)
Two-workflow flow
Section titled “Two-workflow flow”reference_reel.mp4 │ ▼research/reference-format-analysis │ ├── format_dna.json ├── recreation_blueprint.json └── summary.md │ ▼video/recreate-from-format │ ├── variant_0/script.json ├── variant_0/shotlist.json ├── variant_0/overlay_captions.json ├── variant_0/edit_recipe.json └── recreation_manifest.json