# Movie Maker Fast

> >

- **Type:** Skill
- **Install:** `agentstack add skill-aeon-7-aeon-movie-maker-aeon-movie-maker`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [AEON-7](https://agentstack.voostack.com/s/aeon-7)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [AEON-7](https://github.com/AEON-7)
- **Source:** https://github.com/AEON-7/aeon-movie-maker

## Install

```sh
agentstack add skill-aeon-7-aeon-movie-maker-aeon-movie-maker
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Movie Maker Fast — LTX 2.3 cinematic video pipeline

> 📖 **For execution**, read [AGENTS.md](AGENTS.md) first — it has the
> glossary, decision tree, literal copy-pasteable recipes, and a
> troubleshooting table optimized for AI agents. **This file (SKILL.md)
> is the deep-dive reference** for prompt-engineering recipes,
> chunking strategy details, and advanced configuration. Use SKILL.md
> when you need to understand *why* something works the way it does;
> use AGENTS.md when you just need to *do* the thing.

> Companion to `radio-drama-production` (audio only), `music-producer` (standalone music), and `tts-voice-designer` (voice casting). This skill is the **video engine**; it imports all three of those for the audio passes.

## 0. Target host + tool

- **Host:** `${SSH_USER}@127.0.0.1` (Workstation — RTX 5090, 64 GB RAM)
- **Tool:** `${COMFYUI_ROOT}\scene_production_tool\movie_maker_fast.py`
- **Companion tools** (invoked by this one for audio):
  - `scene_production_tool/radio_drama.py` — dialogue TTS + SFX priority chain
  - `music_tool/music_maker.py` — music cues via ACE Step XL base + APG chain
- **ComfyUI endpoint:** `http://127.0.0.1:8188`

## 1. Why this skill exists (and when NOT to use it)

The original cinema pipeline (`AGENT_CINEMA_AUTOPILOT` using `render_all_acts.py` + WAN 2.1 MultiTalk) produces **very tight lip-synced dialogue** but takes ~20–30 min per shot. For a 10-minute drama that's 4–6 hours of render.

Movie Maker Fast uses **LTX 2.3 distilled fp8** — a video-only model tuned for speed. A 7-second clip at 832×480 renders in ~75 s warm on the 5090. The full 10-minute drama renders in ~30–40 min. **~10–15× speedup.**

**Use this skill when:**
- Visuals are the primary deliverable; lip-sync is "close enough"
- You want a cinematic film with musical scoring + SFX, dialogue may be VO or off-frame
- Speed matters (previews, iterations, multi-shot drafts before committing)
- The production has many scenes (>15) where MultiTalk's per-shot cost is prohibitive

**Use `AGENT_CINEMA_AUTOPILOT` (slow WAN) instead when:**
- On-screen character dialogue requires tight lip-sync (every word matches mouth)
- Hero shots where motion naturalness on the speaker is paramount
- Short-form work where the 20-min-per-shot cost is acceptable

Both pipelines can coexist — the same `screenplay.json` works for both.

## 2. Three render modes — `--mode fast | quality | abstract`

LTX 2.3 is trained predominantly on real-world video. Each mode tunes the LoRA stack + sampler for a different content class. Pick by **what kind of video you're making**:

| Mode | Content class | Stack | Sampler | CFG | Steps |
|---|---|---|---|---|---|
| **`fast`** (default) | Narrative / character / real-world scenes | Distilled + IC-union + VBVR physics | euler | 3.0 | 20 |
| `quality` | Higher prompt-fidelity / motion variety | Non-distilled FP8 + distill LoRA @ 0.5 + IC-union + VBVR | euler | 3.0 | 30 |
| **`abstract`** | Fractals, geometry, artwork in motion, psychedelic, non-physical | NO always-on LoRAs (physics would hurt) | **euler_ancestral** | **5.0** | **30** |

Why abstract drops the physics + reference LoRAs:
- **VBVR** enforces object permanence, gravity, and collision realism — exactly wrong for a pulsing mandala or fractal unfold.
- **IC-LoRA union control** carries reference-scene semantics that don't apply to non-representational content.
- **euler_ancestral** adds stochastic variation each step, which morphs abstract content more expressively than plain euler.
- **Higher CFG (5 vs 3) + 30 steps** compensate for the distilled model's natural-video bias when asked for unfamiliar geometry.

## 2a. Model stack (all on disk, all verified)

### Fast mode (DEFAULT — `--mode fast`)

| Slot | File | Role |
|---|---|---|
| Base | `ltx-2.3-22b-distilled-fp8.safetensors` (27 GB) | Video-only distilled 22B, fp8 |
| Video VAE | `LTX23_video_vae_bf16.safetensors` | |
| Text encoder | `gemma_3_12B_it.safetensors` | Base Gemma-3 12B IT (Comfy-Org/ltx-2 split) |
| Abliteration LoRA | `gemma-3-12b-it-abliterated_heretic_lora_rank64_bf16.safetensors` | Available on disk; not auto-applied (needs CLIP-side wiring — manual workflow only) |
| LoRA (always) | `ltx-2.3-22b-ic-lora-union-control-ref0.5.safetensors` @ 1.0 | Reference-based char/scene control |
| LoRA (always) | `ltx2/Ltx2.3-Licon-VBVR-I2V-96000-R32.safetensors` @ 1.0 | Physics / object permanence |

**No distilled-lora-384 in fast mode** — already baked into the checkpoint. Adding it would over-distill.

### Quality mode (`--mode quality`)

| Slot | File | Role |
|---|---|---|
| Base | `ltx-2.3-22b-dev-fp8.safetensors` (~29 GB) | Non-distilled FP8 base — higher prompt-fidelity, more motion variety |
| Video VAE | same | |
| Text encoder | same | |
| LoRA | `ltx-2.3-22b-distilled-lora-384.safetensors` @ 0.5 | Partial distill — compresses step count without baking in full distilled behaviour (root of `loras/` — no `ltx2/` prefix) |
| LoRA | `ltx-2.3-22b-ic-lora-union-control-ref0.5.safetensors` @ 1.0 | |
| LoRA | `ltx2/Ltx2.3-Licon-VBVR-I2V-96000-R32.safetensors` @ 1.0 | |

Quality mode is ~30–50% slower than fast mode. Use it when fast-mode output looks too "average" or when you need stronger prompt adherence. No joint-AV path — audio comes exclusively from the separate audio stack (Qwen3-TTS / ACE-Step / MMAudio).

## 3. Per-scene LoRA routing

Tags on a scene (or dialogue direction) route to extra LoRAs on top of the always-on stack. Substring-matched case-insensitively. Cap at 3 extras per clip to avoid model interference.

| Tag | LoRA added | Effect |
|---|---|---|
| `pose` | `ltx2/ltx23__demopose_d3m0p0s3.safetensors` @ 1.0 | Skeleton-driven motion |
| `zoomout` | `ltx2/ltx23_zoomout_z00m047.safetensors` @ 0.9 | Camera pulls back |
| `camera: dolly-left` | `ltx-2-19b-lora-camera-control-dolly-left.safetensors` @ 0.8 | Dolly motion |
| `camera: jib-down` | `ltx2/ltx-2-19b-lora-camera-control-jib-down.safetensors` @ 0.8 | Jib drop |
| `transition` | `ltx2.3-transition.safetensors` @ 1.0 | Scene-boundary clips (auto-added) |
| `style: claymation` | `ltx2/Claymation.safetensors` @ 0.8 | Stop-motion / clay |
| `style: ghibli` | `StudioGhibli.Redmond...` @ 0.7 | Ghibli watercolor |
| `style: ghibli_offset` | `ghibli_style_offset.safetensors` @ 0.6 | Lighter Ghibli shift |
| `style: galaxy` | `ltx2/LTX23-GalaxyAce.safetensors` @ 0.9 | Cosmic / nebular / starfield |
| `style: tribal` | `Smooth_Tribal.safetensors` @ 0.7 | Ornamental / pattern-rich |
| `style: illustration` | `Illustration concept Variant 3A.safetensors` @ 0.7 | Illustrative / graphic |
| `style: cyberpunk` | `CyberPunkAI.safetensors` @ 0.8 | Neon / tech noir |
| `character: talkinghead` | `ltx-2.3-id-lora-talkvid-3k.safetensors` @ 0.8 | Face consistency on close-ups |

> **LoRA sourcing**: Camera and motion LoRAs above are HuggingFace-hosted (free, requires `HF_TOKEN` for some). The **style LoRAs** (`style: claymation` / `ghibli` / `ghibli_offset` / `galaxy` / `tribal` / `illustration` / `cyberpunk`) are **Civitai-hosted** and require a `CIVITAI_TOKEN` (set in `.env`). See `setup.sh` for the download URL pattern. All LoRAs are optional — plain prompts without these tags work without any of them.

### Style shortcut

Instead of typing the full tag, use `--style `:

```bash
python movie_maker_fast.py clip --image abstract.png \
  --prompt "kaleidoscopic mandala, pulsing concentric circles, iridescent color shifts" \
  --mode abstract --style galaxy --duration 5
```

That appends `style: galaxy` to the tag list, which picks up the galaxy LoRA.

`transition` is automatically added to the last chunk of any multi-chunk scene so boundaries blend. You don't usually need to set it manually.

## 4. Image persistence & character consistency (the anti-drift toolkit)

LTX 2.3 can "wander" — the input image transforms into something unrelated over a 7 s clip, and chunks of the same scene can look like four unrelated shots spliced together. Three mechanisms, in decreasing order of impact, prevent this:

### 4.1 Last-frame carry-forward (ON by default)

For scenes auto-chunked into multiple clips, **chunk N+1 uses chunk N's last frame as its input image** instead of restarting from the original source. The `transition` LoRA (auto-added on boundary chunks) + matching seed across chunks carry the visual forward.

- `render_scene()` extracts the last frame via `ffmpeg -sseof -0.3` → `-frames:v 1` and stashes it at `input/_movie_fast_frames//scene_NNN_chunk_NN_last.png`.
- Disable with `--no-carry-last-frame` if you *want* hard-cuts between chunks (rarely useful).

This is the **single biggest lever for scene coherence** — multi-chunk scenes go from "4 unrelated shots" to a continuous arc.

### 4.2 Persistence knob (`--persistence 0..1`)

`LTXVImgToVideoInplace` has a `strength` parameter where HIGHER = more freedom to transform the input (paradoxical naming). The `--persistence` flag exposes an intuitive 0..1 scale:

| `--persistence` | i2v strength | Effect |
|---|---|---|
| unset (default) | 1.00 | Full motion freedom — LTX reinterprets the input aggressively |
| 0.3 | 0.82 | Dynamic action allowed but anchored |
| 0.5 | 0.70 | Balanced — good for most cinematic shots |
| 0.7 | 0.58 | "Hold the frame" — subtle motion only |
| 1.0 | 0.40 | Near-static; barely moves from input |

Per-scene override: add `"persistence": 0.7` to the scene dict in the screenplay.

### 4.3 Character seed stability

- `character_seed_offset("AYA", base_seed)` → stable hash-derived offset. Same name + same base_seed = same face every time.
- `focal_character(scene)` picks the first non-NARRATOR dialogue speaker (else first entry in `scene["characters"]`). The seed offset uses that name.
- All chunks of a scene share the same scene seed (`base_seed + scene_idx * 1000`), so characters don't shift appearance within a scene.

For a multi-episode series: copy the `characters` dict + `base_seed` from one episode's manifest to the next. Faces stay stable bit-for-bit.

### 4.4 What's *not yet* wired (but documented)

**IC-LoRA reference images per character** — the `LTXAddVideoICLoRAGuide` + `LTXICLoRALoaderModelOnly` node path (proven in the KJ pose-switches workflow) can take a per-character reference PNG and strongly anchor that character's appearance across every clip they're in. Always-on `ic-lora-union-control-ref0.5` is already loaded; wiring the guide image is a ~80-line addition that would supersede the seed-offset approach for strict multi-episode consistency. See Phase 2b in the tool's internal TODOs.

## 5. 7-second clip enforcement + auto-chunking

LTX 2.3 coherence degrades past ~8 s. Scenes longer than 7 s auto-split into ≤7 s chunks:

```
3.0 s  →  [3.0]                   (no split)
7.5 s  →  [7.0]                   (0.5s tail absorbed into the 7s chunk)
14.0 s →  [7.0, 7.0]              (even split)
20.0 s →  [7.0, 7.0, 6.0]         (last chunk is remainder)
23.5 s →  [7.0, 7.0, 7.0, 2.5]
```

All non-last chunks auto-get the `transition` LoRA so the xfade stitcher has smooth boundaries to work with.

## 6. Screenplay schema

Compatible with `AGENT_CINEMA_AUTOPILOT` / `produce.py` output. Minimum
viable scene (per-scene I2V flow):

```json
{
  "title": "my_film",
  "scenes": [
    {
      "description": "A woman stands at the archive's edge, cool-lit, shallow DOF.",
      "action": "Slow push-in. She turns toward an unseen presence.",
      "source_image": "styled_film_act1/shot_003.png",
      "duration": 10.0,
      "mood": "reverent",
      "camera": "dolly-in",
      "tags": ["transition"],
      "characters": ["LYRA"],
      "dialogue": [{"character": "LYRA", "line": "Someone is here.", "direction": "tender"}]
    }
  ]
}
```

Fields used by Movie Maker Fast:

| Field | Required | Purpose |
|---|---|---|
| `source_image` / `image_path` / `image` | ✓ for I2V flow | Input image (relative to `input/`); not required for `--use-relay` (relay does T2V on first scene of each sequence + carries last frame to subsequent sequences) |
| `prompt` / `action` / `description` | ✓ (one of) | Text prompt for LTX |
| `duration` / `duration_hint` | ✓ | Scene length in seconds; auto-chunks |
| `tags` | optional | Explicit LoRA routing tags. Tag `transition` (or `cut` / `scene_change`) forces a new Prompt Relay sequence (hard cut) under `--use-relay` |
| `mood` / `camera` / `style` | optional | Implicit tags (auto-prefixed `mood:` / `camera:` / `style:`); also forwarded into the relay prompt as natural-language suffixes |
| `characters` | optional | List of names. Under `--use-relay`, the wrapper prompt looks up each name in the top-level `characters` dict (see below) and injects the visual description |
| `dialogue` | optional | Forwarded into the relay prompt as `'CHARACTER says "line"'` patterns — this is what triggers LTX 2.3's joint-A/V dialogue + lipsync |
| `relay_break: true` | optional | Force this scene to start a new Prompt Relay sequence (alternative to using a `transition` tag) |

### Top-level fields specific to `--use-relay`

```json
{
  "title": "my_film",
  "style": "cinematic, golden-hour photography, photorealistic faces ...",
  "setting": "vibrant Middle Eastern medina at golden hour ...",

  "characters": {
    "DANIEL": "Western man in his early thirties, light olive skin, neatly trimmed dark beard, wearing a wrinkled beige linen shirt ...",
    "LEILA": "Middle Eastern woman in her late twenties, warm olive skin, long dark wavy hair partially covered by a colorful patterned headscarf in red and gold, wearing a flowing crimson and gold embroidered kaftan ..."
  },

  "negative_prompt": "music, soundtrack, score, instruments, drums, oud, sitar, melody, ambient music, deformed, mutilated, extra limbs, malformed face, blurry, low quality, watermark",

  "scenes": [...]
}
```

| Top-level field | Required | Purpose |
|---|---|---|
| `style` | recommended | Global style anchor; included in every sequence wrapper |
| `setting` | recommended | Global setting; included in every sequence wrapper |
| `characters` | recommended | **dict** mapping name → full visual description. Names alone don't anchor identity — the relay needs visual specificity. Falls back to a list-of-names format if no descriptions are available |
| `negative_prompt` | recommended | CLIP-encoded as the negative conditioning. Suppresses model-generated music in joint A/V output (so you can compose your own score and mux underneath the dialogue) + suppresses anatomy artifacts. CLI `--relay-negative-prompt` overrides |

### Authoring tips for the `--use-relay` flow

- **End the LAST scene of each sequence with visual action AFTER the
  dialogue line.** ("She lifts her cup and sips" / "He looks toward the
  window") This gives the model time to land the audio cleanly within the
  segment's frame budget. Without this, dialogue can clip at the segment
  boundary.
- **Add `tags: ["transition"]`** to scenes that genuinely need a hard cut
  (different location, new character entering, time jump). Within a
  sequence, scenes morph smoothly via the relay; between sequences,
  there's a hard cut with the previous sequence's last frame as the seed
  image of the next.
- **Don't pack 2+ dialogue exchanges into one scene** — give each line its
  own scene (or its own segment within a sequence). LTX 2.3 needs
  ~2-3 seconds of segment time per spoken line for clean audio + lipsync.
- **Visual descriptions in `characters` should be specific and physical**:
  skin tone, hair color/style/length, eye color, distinctive clothing
  with color, body type, expression. The wrapper carries these into every
  sequence, so they're the strongest identity signal across hard cuts.

## 7. CLI

```bash
# Single-clip (Phase 1)
python movie_maker_fast.py clip --image styled_film_act1/shot_003.png \
  --prompt "Cinematic slow push-in..." --duration 7 --mode fast --seed 42

# Persistent character shot (holds the frame, subtle motion only)
python movie_maker_fast.py clip --image character.png \

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [AEON-7](https://github.com/AEON-7)
- **Source:** [AEON-7/aeon-movie-maker](https://github.com/AEON-7/aeon-movie-maker)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-aeon-7-aeon-movie-maker-aeon-movie-maker
- Seller: https://agentstack.voostack.com/s/aeon-7
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
