> **ARCHIVED 2026-03-02.** LoRA pipeline eliminated Feb 27, 2026. Retained for potential future
> re-adoption of open-source identity models. For the current visual pipeline, see
> `../PRODUCTION_PIPELINE_GUIDE.md` Phase 6.

# Generation Workflows — Master Reference

**Last updated:** 2026-02-22
**Applies to:** All visual generation use cases across the Recoil production pipeline

This document is the single source of truth for engine selection, parameters, known issues, and workflows across all generation use cases. For LoRA training candidate generation specifically, see `candidate_generation_engines.md`.

---

## A. Engine Selection Decision Tree

```
What are you generating?
│
├── Hero Stills (concept art, pitch images, social media)
│   ├── With LoRA identity: Flux 2 Dev + LoRA (scale 1.0, 28 steps, guidance 2.5)
│   ├── Without LoRA: NBP / Gemini 3 Pro Image Preview (standalone, ~18s)
│   └── Maximum quality: MidJourney (manual, for keystones)
│
├── LoRA Training Candidates
│   └── Three-pass pipeline: Qwen MA → NBP → SeedVR2
│       (see candidate_generation_engines.md for full spec)
│
├── Production Keyframes (storyboard → frames)
│   ├── Previz (fast/cheap): Z-Image Turbo + LoRA (512x896, 8 steps)
│   ├── Single-character shots: Z-Image Turbo + LoRA (768x1344, 8 steps)
│   ├── Multi-character shots: Flux 2 Dev + dual LoRA (768x1344, 28 steps)
│   └── Quality upscale: SeedVR2 (fal.ai)
│
├── Video (image-to-video)
│   └── WAN 2.2 FLF + LoRA (720p 9:16, 40 steps, 49 frames)
│
└── A/B Testing / Comparison
    └── ab_test_models.py (side-by-side HTML comparison)
```

**Default production engine:** Z-Image Turbo (fast, cheap, good anatomy).
**Override to Flux 2 Dev** when: multi-character dual LoRA, hero stills with LoRA, or Z-Image quality insufficient.

---

## B. Per-Engine Parameter Cards

### 1. Flux 2 Dev + LoRA (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint** | `fal-ai/flux-2/lora` |
| **Cost** | ~$0.02/image |
| **Speed** | ~9s per image |
| **Resolution** | 768x1344 (9:16 portrait), 1536x912 (triptych strip) |
| **Steps** | 28 |
| **Guidance** | 2.5 |
| **LoRA scale (solo)** | **1.0** (NOT 1.3 — causes blowout) |
| **LoRA scale (dual)** | 0.5 per character |
| **Supports img2img** | Yes (via same endpoint with `image_url` + `strength`) |
| **Prompt style** | Narrative E-style prose (~170 words, action-first, film stock suffix) |

**Best for:** Hero stills with LoRA identity, multi-character shots (dual LoRA), triptych strips, quality-critical production keyframes.

**Gotchas:**
- LoRA scale **must be 1.0** for Flux 2 Dev. Scale 1.3 (the Z-Image default) causes generation blowout — muddy abstract textures, destroyed faces. This is the single most important parameter difference between engines.
- Structured `prompt_compiler` output doesn't work well — use narrative E-style prompts instead.
- Skin can appear slightly plastic/architectural (baked into distilled model weights).

---

### 2. Z-Image Turbo + LoRA (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint (T2I)** | `fal-ai/z-image/turbo/lora` |
| **Endpoint (img2img)** | `fal-ai/z-image/turbo/image-to-image/lora` |
| **Cost** | ~$0.005-0.009/image |
| **Speed** | ~3-5s per image |
| **Resolution** | 768x1344 (production), 512x896 (previz) |
| **Steps** | 8 |
| **Guidance** | Not supported (no `guidance_scale` parameter) |
| **LoRA scale (solo)** | 1.3 |
| **LoRA scale (dual)** | 0.5 per character |
| **Supports img2img** | Yes (via dedicated img2img endpoint) |
| **Prompt style** | BFL structured + HEX colors + action verbs (prompt_compiler output works well) |

**Best for:** Production keyframes (default engine), previz, single-character shots, fast iteration.

**Gotchas:**
- No guidance scale control — what you get is what you get.
- Attention fades after ~75 tokens (~55 words). Later content in long prompts may be ignored.
- More photographic than Flux 2 Dev (often preferable for production).
- Dual LoRA total scale must not exceed 1.0 (0.5/0.5).

---

### 3. NBP / Gemini 3 Pro Image Preview

| Property | Value |
|----------|-------|
| **Endpoint** | Gemini API (`gemini-3-pro-image-preview`) |
| **Cost** | ~$0.134/image |
| **Speed** | ~18-40s per image |
| **Resolution** | Variable (typically 1024x1024 or similar) |
| **LoRA support** | No |
| **Prompt style** | Natural language, conversational |

**Best for:** Hero stills without LoRA, Pass 2 in three-pass LoRA candidate pipeline (background swap + expression), standalone concept art.

**Gotchas:**
- Rotates heads on back-view inputs — skip NBP for back/profile angles.
- No LoRA support — cannot enforce character identity mathematically.
- Higher cost than fal.ai engines.

---

### 4. Nanobanana Flash / Gemini 2.5 Flash Image

| Property | Value |
|----------|-------|
| **Endpoint** | Gemini API (`gemini-2.5-flash-image`) |
| **Cost** | ~$0.039/image |
| **Speed** | ~60s per image |
| **LoRA support** | No |
| **Prompt style** | Natural language |

**Best for:** Diversity generation (legacy), quality upscale alternative.

**Gotchas:**
- Can't hold angles — back/low/high angle inputs produce frontal outputs.
- Slower than NBP for comparable quality.
- Largely superseded by NBP for candidate generation.

---

### 5. Qwen Multi-Angle (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint** | `fal-ai/qwen-image-edit-2511-multiple-angles` |
| **Cost** | ~$0.035/image |
| **Speed** | ~7-37s per image |
| **LoRA support** | No (uses hero image + numeric angle params) |
| **Prompt style** | No text prompt — numeric angle parameters only |

**Best for:** Pass 1 in three-pass pipeline (angle geometry from hero reference). Handles low/high/back angles that Gemini cannot.

**Gotchas:**
- No prompt control — angle only, from a source image.
- Output may need refinement (Pass 2/3) for production quality.

---

### 6. Qwen Edit (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint** | `fal-ai/qwen-image-edit-2511` |
| **Cost** | ~$0.035/image |
| **Speed** | ~10-20s per image |
| **Status** | **Legacy** — replaced by NBP for background swap |

**Best for:** Background swap (legacy). NBP now preferred.

---

### 7. SeedVR2 (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint** | `fal-ai/seedvr2` |
| **Cost** | ~$0.001/image |
| **Speed** | ~5-10s per image |
| **LoRA support** | No |

**Best for:** Pass 3 quality upscale in three-pass pipeline. Sharpens texture and detail at minimal cost.

**Gotchas:**
- Upscale only — not a standalone generator.
- Skip for face angles (skin texture priority handled by NBP in Pass 2).

---

### 8. WAN 2.2 FLF (fal.ai)

| Property | Value |
|----------|-------|
| **Endpoint** | `fal-ai/wan/v2.2-a14b/image-to-video/lora` |
| **Cost** | ~$0.15/video |
| **Speed** | ~138s per video |
| **Resolution** | 720p 9:16 (portrait) |
| **Steps** | 40 |
| **Frames** | 49 |
| **LoRA support** | Yes (dual adapters: high-noise + low-noise) |

**Best for:** Image-to-video production. First-Last Frame interpolation for all motion shot types.

**Gotchas:**
- VFX language in prompts ("targeting reticles," "data streams," "holographic HUD") causes literal spirals/geometric noise on faces. Save VFX language for motion prompts only.
- Dual LoRA adapters required (high_noise + low_noise) — both must be available in `lora_registry.json`.

---

### 9. MidJourney (Manual)

| Property | Value |
|----------|-------|
| **Access** | Discord or web UI (manual) |
| **Cost** | Subscription-based |
| **Speed** | ~30-60s per image |
| **LoRA support** | No |

**Best for:** Keystones (7-8 hero images per character for identity anchoring), maximum quality concept art.

**Workflow:**
1. Generate 7-8 hero angles in MidJourney (front, 3/4 L/R, profile L/R, full body, close-up, back)
2. All neutral expression — keystones establish identity geometry
3. Place in `[project]/visual/lora_candidates/[CHAR]/keystones/`
4. AI candidates fill remaining coverage gaps

---

## C. Known Issues & Gotchas

| Issue | Details | Fix |
|-------|---------|-----|
| **Flux 2 Dev LoRA scale blowout** | Scale 1.3 produces muddy abstract textures, destroyed faces | Use scale **1.0** for Flux 2 Dev. 1.3 is for Z-Image only. See `lora_registry.json` engine-specific fields. **ENFORCED:** `generate_storyboard_keyframes.py` rejects Flux 2 LoRA scale >1.1 before API call. |
| **Prompt style mismatch** | Structured `prompt_compiler` output doesn't work well with Flux 2 Dev | Use narrative E-style prompts (~170 words) for Flux 2 Dev. prompt_compiler output is designed for Z-Image. |
| **lora_registry scale_solo** | `inference.scale_solo: 1.3` is Z-Image tuned | Registry now has `flux2_scale_solo: 1.0` for engine-specific lookup. `generate_storyboard_keyframes.py` selects automatically. |
| **NBP back angle head rotation** | NBP rotates heads on back-view inputs | Skip NBP for back/profile angles in three-pass pipeline. |
| **Gemini Flash can't hold angles** | Back/low/high angle inputs produce frontal outputs | Use Qwen MA for angle geometry instead. |
| **VFX prompt poisoning** | "Targeting reticles," "holographic HUD" etc. cause spirals on faces in T2I | Only use VFX language in video motion prompts, never in T2I prompts. **ENFORCED:** `prompt_compiler.py` strips 20+ VFX regex patterns from all T2I prompts (not video). |
| **Z-Image attention window** | Z-Image attention fades after ~75 tokens (~55 words) | Keep per-panel content within attention window. ~195 words total for 3 panels. **ENFORCED:** `prompt_compiler.py` hard-truncates Z-Image prompts to 60 words at sentence boundaries. |
| **Dual LoRA scale cap** | Total scale above 1.0 causes image corruption | Max total: 1.0 (use 0.5/0.5 for two characters). **ENFORCED:** `generate_storyboard_keyframes.py` rejects dual LoRA total >1.0 before API call. |
| **Flux 2 skin texture** | Plastic/waxy skin baked into distilled weights | No prompt fix. Z-Image is more photographic. |
| **Mixed training data** | Mixed-source LoRA training images dilute face geometry | Use single-source data; face-heavy dataset composition (33-40% close-ups). |
| **First/Last prompts identical** | `_build_action_pose()` fell through to same `action` field for both frame types because storyboard uses `first_frame`/`last_frame` prose, not `anticipation_action`/`aftermath_action` | **FIXED Feb 22.** Compiler now falls back to `shot["last_frame"]` for last and `shot["hero_frame"]` for hero. Different prompt hashes confirmed. |
| **Mid frames radically different** | Mid/hero frames generated independently with no img2img conditioning, bypassing prompt compiler entirely (raw `hero_frame` prose used) | **FIXED Feb 22.** Mid frames now: (a) route through prompt compiler with `frame_type="hero"`, (b) img2img conditioned from first frame for lighting/wardrobe/skin coherence. |
| **img2img strength needs A/B test** | Default corrected to 0.40 (was 0.55, from unrelated Qwen test). Still untested empirically — too low = nearly identical frames, too high = visual divergence. | Needs A/B testing across 0.3/0.4/0.5/0.6 range. Use `--img2img-strength` flag to compare. |
| **Three-pass final win rate 46%** | Three-pass pipeline (Qwen MA → NBP → SeedVR2) results had lowest win rate (46%) in JT's curation. MidJourney originals = 80%, SeedVR2 standalone = 73% | Three-pass still recommended for LoRA candidate coverage, but hero/pitch images should use MidJourney + NBP. |

---

## D0. Frame Coherence & img2img Conditioning

### How Frame Chaining Works

The pipeline generates frames in sequence and chains them via img2img conditioning:

```
Shot generation order (per shot):
  hero → first → last  (if hero_action exists)
  first → last          (standard FLF)
  first → mid → last    (with --fmlf flag)

Conditioning chain:
  hero:  fresh T2I (or img2img from previous shot's frame via continuity_from)
  first: img2img from hero (strength 0.40)
  mid:   img2img from first (strength --img2img-strength, default 0.40)
  last:  img2img from hero (strength 0.40) or first (strength --img2img-strength)
```

### Key Parameters

| Parameter | Default | Flag | What it controls |
|-----------|---------|------|-----------------|
| `img2img_strength` | 0.40 | `--img2img-strength` | Deviation from source frame (0.0=copy, 1.0=fully new) |
| `location_ref_strength` | 0.35 | `--location-ref-strength` | Deviation from location reference image |
| Hero→First strength | 0.40 | hardcoded | How much first frame can deviate from hero |
| Hero→Last strength | 0.40 | hardcoded | How much last frame can deviate from hero |
| Punch-in strength | 0.30 | from storyboard `continuity_from.strength` | Cross-shot continuity |

### FMLF Mode (First-Mid-Last Frame)

Use `--fmlf` to promote standard FLF shots to generate 3 frames instead of 2:

```bash
python3 generate_storyboard_keyframes.py leviathan/ -e 1 --model flux2 --fmlf
```

This adds a mid frame between first and last for all `standard_flf` shots. The mid frame:
- Routes through prompt compiler with `frame_type="hero"` (peak moment of shot action)
- Gets img2img conditioning from the first frame for visual coherence
- Provides better interpolation input for WAN 2.2 video generation

**Without `--fmlf`:** EP001 generates 62 frames (31 shots × 2 FLF)
**With `--fmlf`:** EP001 generates ~87 frames (25 standard × 3 + 5 triptych × 3 + 1 held × 1)

### Open Questions (Needs Testing)

1. **Optimal img2img strength per shot type** — Close-ups may need lower strength (more coherence) vs. wide shots (more freedom). No A/B data exists.
2. **Qwen Multi-Angle for "presentational" fix** — JT noted LoRA-generated images tend to be too "to-camera." Using Qwen MA to rotate the entire scene 90 degrees could break this bias. Not yet tested.
3. **WAN 2.2 identity drift** — How much does character identity shift during FLF interpolation? No metrics exist.
4. **Cross-shot coherence** — Episode-level visual consistency (environment, lighting, wardrobe) is the biggest unsolved production challenge.

---

## D. Hero Still Generation Workflow

Hero stills are concept art / pitch images that showcase a character in a key scene. They're used for pitch decks, social media, and series identity.

### Step-by-Step

1. **Write a narrative E-style prompt** (~170 words)
   - Action-first: lead with what the character is DOING
   - Include environment, lighting, wardrobe details
   - End with film stock suffix (e.g., "Shot on Arri Alexa Mini LF with Kodak Vision3 500T 5219")
   - Use kinetic verbs ("mid-stride pivots" not "stands in corridor")

2. **Generate across engines for comparison:**
   - **Flux 2 Dev + LoRA** (scale 1.0, 28 steps, guidance 2.5) — best LoRA identity lock
   - **NBP** (no LoRA, standalone) — different aesthetic, good for non-LoRA characters
   - **MidJourney** (manual, for maximum quality keystones)

3. **Review and select** — pick winner per character/scene

4. **Place in:** `[project]/visual/hero_stills/`

### Prompt Template (E-Style)

Based on the working Jinx hero still prompt:

```
[CHARACTER TRIGGER] [ACTION VERB] [ENVIRONMENT CONTEXT].
[DETAILED WARDROBE — specific garments, materials, colors, wear patterns].
[PHYSICAL DETAILS — skin, hair, scars, distinguishing features].
[POSE AND BODY LANGUAGE — what the body communicates].
[ENVIRONMENT — where they are, what surrounds them, atmosphere].
[LIGHTING — source, quality, color temperature, shadows].
[MOOD — emotional tone of the image].
Shot on [CAMERA] with [FILM STOCK]. [LENS AND APERTURE].
```

**Key rules:**
- LoRA trigger word FIRST (e.g., "JNXCHAR")
- ~170 words total (Flux 2 Dev attention window)
- No structured JSON — pure narrative prose
- No VFX language in T2I prompts

---

## E. Lab Test Findings Summary

Consolidated findings from 18 lab experiments (Jan 27 — Feb 8, 2026). ~277 frames generated, ~$15 R&D cost.

| Test | Date | Key Finding | Action |
|------|------|-------------|--------|
| `flux2_lora` | Feb 6 | LoRA essential for identity lock. Scale 1.0 works, J1 (with LoRA) vs J2 (without) conclusive. | Always use LoRA for character shots. |
| `base_vs_turbo` | Feb 7 | Turbo avg 4.3s vs Base avg 6.7s. Both generate successfully. Turbo more photographic. | Use Turbo for production (speed + quality). |
| `cfg_test` | Feb 7 | Higher guidance = more literal but quality ceiling unchanged. | Default guidance 2.5 for Flux 2 Dev. |
| `wardrobe` | Feb 7 | Z-Image T2I > Flux 2 Edit > img2img. Wardrobe = prompt problem, not pixel conditioning. | Describe wardrobe in prompts, don't condition via images. |
| `controlled_lora_comparison` | Feb 8 | Same 20 images tested across Flux 2 Dev, Z-Image Turbo, Z-Image Base. Mixed-source data dilutes face geometry across all. | Single-source training data only. |
| `gemini_swap_v1` | Feb 7 | Gemini face-swap inconsistent quality. | Archived — not production-grade. |
| `gemini_swap_v2` | Feb 7 | Refined swap better than v1 but inferior to prompt-level approach. | Archived — prompt-level approach wins. |
| `prompt_strategies` | Feb 4 | BFL structured + HEX colors + action verbs wins among 7 strategies. ~55 word attention window per panel. | Use BFL + HEX for Z-Image. E-style for Flux 2 Dev. |
| `settings` | Feb 4 | 8 settings variants tested. Higher guidance = more literal, no quality improvement. | Archived. |
| `triptych` | Feb 4 | Wide format (1536x912) provides best panel separation. ~195 words for 3 panels optimal. | 1536x912 for triptych strips. |
| `innovations` | Feb 6 | Decisive Moment, Multi-Camera Grid, Panel Fix all work. Hero-first generation order confirmed optimal. | Hero-first ordering in pipeline. |
| `dual_lora` | Feb 7 | 0.5/0.5 scale works. Above 1.0 total causes corruption. | Max total dual LoRA scale = 1.0. |
| `flux2_vs_zimage` | Feb 7 | Z-Image Turbo won for production (anatomy, speed, cost: 10x cheaper). | Z-Image Turbo = default production engine. |
| `lora_dataset` | Feb 7 | 32 candidates curated to 20 selected for training. | Coverage matrix: 33-40% close-up, 25-30% medium. |
| `lora_verification` | Feb 8 | Production LoRA quality matches controlled test LoRA. | Production pipeline validated. |
| `pose` | Feb 4 | Pose & action control tested. Kinetic verbs produce more dynamic results than static poses. | Use "mid-stride pivots" not "stands in corridor." |
| `comprehensive` | Feb 7 | 5-method comprehensive test across 6 shots. Z-Image T2I consistently best. | Z-Image T2I = production standard. |
| `base_vs_neg_v2` | Feb 7 | Z-Image Base + heavy negative prompts tested. Base has better physicality but smooth skin. | Turbo preferred overall (photorealism). |

### Key Decisions from Testing

| Decision | Winner | Evidence |
|----------|--------|----------|
| Default T2I engine | Z-Image Turbo | A/B test: anatomy, speed, cost (10x cheaper than Flux 2) |
| Identity lock method | LoRA (per character) | With/without comparison conclusive |
| Prompt system (Z-Image) | BFL + HEX + verbs | 7-strategy comparison |
| Prompt system (Flux 2) | Narrative E-style | Structured prompts fail, narrative works |
| Wardrobe method | Prompt-level descriptions | 3-method A/B test |
| Multi-shot format | Triptych (1536x912) | 4 format variants tested |
| Generation order | Hero-first (decisive moment) | Innovation tests |
| Dual LoRA scale | Max 1.0 total (0.5/0.5) | Corruption above 1.0 |
| LoRA data quality | Single-source, face-heavy | Mixed-source dilutes identity |

### Cost Model (Per Series of 60 Episodes)

| Item | Cost |
|------|------|
| Per frame (Z-Image Turbo) | $0.005 |
| Per episode (~21 shots × 2 frames + triptych splits + hero) | ~$2.76 |
| Per series (60 episodes, full keyframe coverage) | ~$166 |
| Video generation | Additional (WAN 2.2 ~$0.15/video) |

---

## Cross-References

| Document | Relationship |
|----------|-------------|
| `candidate_generation_engines.md` | LoRA training candidate pipeline detail (three-pass architecture) |
| `lora_training_best_practices.md` | Caption strategy, trigger words, training config |
| `appendix_e_flux2_protocols.md` | Flux 2 prompt engineering (hybrid JSON+prose, HEX, lens) |
| `voice_direction_guide.md` | Voice/TTS direction (separate pipeline) |
| `visual_production_findings.md` | **Living document** — all testing findings, decisions, bug fixes, open questions |
| `lora_registry.json` | Per-character LoRA paths + engine-specific scales |
| `generate_storyboard_keyframes.py` | Production keyframe generator (reads registry, routes per engine) |
| `ab_test_models.py` | Side-by-side engine comparison tool |
