Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 34 additions & 16 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ This is especially critical for background commands where the working directory
|------|-------|-------------|
| **Project tools** | voiceover, music, music_gen, sfx, sync_timing | During video creation workflow |
| **Utility tools** | redub, addmusic, notebooklm_brand, locate_watermark | Quick transformations on existing videos |
| **Cloud GPU** | image_edit, upscale, dewatermark, sadtalker, qwen3_tts, music_gen, flux2 | AI processing via RunPod or Modal (`--cloud runpod\|modal`) |
| **Cloud GPU** | image_edit, upscale, dewatermark, sadtalker, echomimic3, qwen3_tts, music_gen, flux2 | AI processing via RunPod or Modal (`--cloud runpod\|modal`; echomimic3 is Modal-only) |
| **Publishing** | youtube_upload | Upload a finished render to YouTube (use `/publish` for the guided workflow) |

Utility tools work on any video file without requiring a project structure.
Expand Down Expand Up @@ -340,29 +340,47 @@ uv run tools/dewatermark.py --setup # One-time setup

**Local mode** requires NVIDIA GPU (8GB+ VRAM). Mac users should use `--runpod`.

### Talking Head Generation (SadTalker)
### Talking Head Generation (EchoMimicV3 vs SadTalker)

Two generators, and the deciding factor is **how big the narrator is on screen and how long
the viewer looks at it**.

```bash
# Basic usage
uv run tools/sadtalker.py --image portrait.png --audio voiceover.mp3 --output talking.mp4
# EchoMimicV3 — diffusion, follows the input aspect ratio, ~6.5x the cost (Modal only)
uv run tools/echomimic3.py --image presenter_16x9.png --audio voiceover.mp3 \
--steps 5 --size 640 --output narrator.mp4

# For NarratorPiP integration (recommended settings)
# CRITICAL: --preprocess full preserves image dimensions (otherwise outputs square crop)
uv run tools/sadtalker.py \
--image presenter_16x9.png \
--audio voiceover.mp3 \
--preprocess full --still --expression-scale 0.8 \
--output narrator.mp4
# SadTalker — warp-based, fast and cheap, square crop unless --preprocess full
uv run tools/sadtalker.py --image presenter_16x9.png --audio voiceover.mp3 \
--preprocess full --still --expression-scale 0.8 --output narrator.mp4
```

| Need | Use |
|------|-----|
| Narrator large in frame, or a shot held long enough to watch | **echomimic3** |
| Small PiP overlay, drafts, or many takes to choose between | **sadtalker** |
| Non-square source image you don't want to fight | **echomimic3** (no `--preprocess` needed) |

**Cost is the trade-off, and wall clock more than money.** EchoMimicV3 is ~$0.009 per second
of output against SadTalker's ~$0.0014 — a 3-minute narrator is ~$1.76 vs ~$0.27. But it also
runs at 22.8-47.8x realtime, so that same 3 minutes is **1.5-2.4 hours** of generation.
Generate per-scene narrator clips ahead of time rather than one long render.

**Key flags for NarratorPiP:**
- `--preprocess full` — **Critical!** Preserves input dimensions (default `crop` outputs square)
- `--still` — Reduces head movement for professional look
- `--expression-scale 0.8` — Calmer expression (default 1.0)
- echomimic3: `--steps 5 --size 640` — the cheap pass; 16:9 in gives 16:9 out, no crop workaround
- sadtalker: `--preprocess full` — **Critical!** Preserves input dimensions (default `crop` outputs square)
- sadtalker: `--still` and `--expression-scale 0.8` — calmer, more professional look

**Image requirements (both):** Face 30-70% of frame, front-facing, 16:9 for NarratorPiP, 512px+.

**Image requirements:** Face 30-70% of frame, front-facing, 16:9 for NarratorPiP, 512px+ recommended.
**Gotchas that cost hours** (full list in `docs/echomimic3.md`):
- EchoMimicV3's `transformers==4.49.0` pin is load-bearing. A newer version silently removes
**all lip sync** — no error, just a dead mouth.
- Keep `--wav2vec chinese` even for English audio; the `english` encoder under-articulates.
- Don't score talking-head quality with a mouth-crop metric. It ranked highest the one
variant with a visible eye defect. Whole-face, or human review.

See `docs/sadtalker.md` for detailed options and troubleshooting.
See `docs/echomimic3.md` and `docs/sadtalker.md` for detailed options and troubleshooting.

### Redub Sync Mode

Expand Down
22 changes: 22 additions & 0 deletions _internal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,29 @@ All notable changes to claude-code-video-toolkit.
## Unreleased

### Added
- **EchoMimicV3 talking head** (`tools/echomimic3.py` + `docker/modal-echomimic3/`) — diffusion-based
audio-driven talking head (Ant Group, Apache 2.0), Modal-only. Preserves the input aspect ratio, so
16:9 presenter images come back 16:9 with no `--preprocess` workaround. Runs alongside SadTalker
rather than replacing it: ~$0.009/second of output against ~$0.0014, and 22.8-47.8x realtime, so
SadTalker stays the right call for small overlays and drafts. Decision table in CLAUDE.md, full
detail in `docs/echomimic3.md`. (#77)
- **`--anchor-retreat`** — fixes a bug where a segment seam landing mid-blink made the next segment
start closed-eyed and hold it. Anchor windows are now scored by upper-frame motion and the calmest
is chosen, backing off up to N frames. `0` restores the old behaviour. (#77)
<!-- NOTE: the Kiro entry below already shipped in v0.19.0; left in place rather than silently
dropped, but it should come out when this section is cut into a release. -->
- **Kiro CLI support** (`scripts/migrate_to_kiro.py`) — sibling of the Codex migration script. Installs the toolkit skills into `~/.kiro/skills` (Kiro shares Claude Code's `SKILL.md` frontmatter format, so they copy verbatim), generates a wrapper skill per `.claude/commands/*.md` invoked as the same `/video`, `/setup`, … slash commands, and generates `.kiro/steering/video-toolkit.md` from `CLAUDE.md` inside a managed marker block. Wrappers pin the toolkit's absolute path so commands work from any directory (Claude Code parity — Kiro doesn't walk up the directory tree). Supports `--force`, `--dry-run`, `--reset`, `--workspace-skills`, and `kiro/migration_map.json` for skips/renames. See `docs/kiro.md`.

### Changed
- **`docker/modal-echomimic3/` keeps its weights in a Modal Volume**, unlike the other six Modal apps
which bake them into the image. Measured: rebuild after a dependency change is 1.8-8.2s against
79-385s baked, while cold start and generation speed are unchanged. Needs a one-off
`modal run …::populate_weights`. The settled apps stay baked. (#76)
- Upstream repo ref and all four model revisions in `modal-echomimic3` pinned by SHA — weights in a
Volume aren't tied to the image, so nothing else prevents drift. (#76, same lesson as #71/#74)
- **`NarratorPiP`** honours its `objectPosition` prop, which was declared and documented but silently
ignored by a hardcoded value, and gains an `objectFit` prop (default `contain`, unchanged behaviour).

---

## 2026-08-27 (v0.19.0)
Expand Down
45 changes: 45 additions & 0 deletions _internal/toolkit-registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,41 @@
"created": "2026-01-11",
"updated": "2026-01-12"
},
"echomimic3": {
"path": "tools/echomimic3.py",
"description": "Generate talking head videos from portrait image + audio using EchoMimicV3-Flash — preserves the input aspect ratio (16:9 in, 16:9 out)",
"usage": "uv run tools/echomimic3.py --image presenter_16x9.png --audio voiceover.mp3 --steps 5 --size 640 --output narrator.mp4",
"status": "beta",
"category": "video-generation",
"backend": "echomimicv3-flash",
"requires": "Modal account",
"options": {
"size": [
512,
640,
768
],
"steps": "5 (fast) to 8+ (quality)",
"wav2vec": [
"chinese",
"english"
],
"videoLength": "frames per segment, default 81",
"overlap": "frames cross-faded between segments, default 8",
"anchorRetreat": "max frames to back off a blink at a seam, default 6, 0 disables",
"guidanceScale": "3-6 text CFG",
"audioGuidanceScale": "1.8-3.0 audio CFG",
"seed": true,
"fps": 25
},
"envVars": [
"MODAL_ECHOMIMIC3_ENDPOINT_URL"
],
"estimatedCost": "~$0.009 per second of output (measured 28.9x realtime at --steps 5 --size 640)",
"documentation": "docs/echomimic3.md",
"created": "2026-08-30",
"updated": "2026-08-30"
},
"qwen3_tts": {
"path": "tools/qwen3_tts.py",
"description": "Generate speech using Qwen3-TTS - built-in voices, emotion control, voice cloning",
Expand Down Expand Up @@ -911,6 +946,16 @@
"gpu": "A10G",
"estimatedCost": "$0.05-0.30 per video"
},
"echomimic3": {
"appFile": "docker/modal-echomimic3/app.py",
"envVar": "MODAL_ECHOMIMIC3_ENDPOINT_URL",
"operations": [
"echomimic3"
],
"gpu": "A10G",
"weights": "modal-volume",
"estimatedCost": "~$0.11 per 12s of output"
},
"dewatermark": {
"appFile": "docker/modal-propainter/app.py",
"envVar": "MODAL_DEWATERMARK_ENDPOINT_URL",
Expand Down
Loading
Loading