---
name: face-swap
description: "Swap one face onto a target image or video, preserving pose & lighting"
agent_rule: "User wants a face photo placed onto a target image/video — call create_media with face-swap-image or face-swap-video."
task: [edit]
domain: [image, video]
persona: [editor]
scope: episode
category: capability
type: capability
trigger_keywords:
  - face swap
  - face-swap
  - swap face
  - swap my face
  - put my face on
  - replace face
  - my face on this
  - the same person in
  - one face six lives
when_to_use: >
  The user wants the identity of a face in image A to replace the face in image
  or video B, while keeping B's body, pose, lighting, and scene intact. This is
  identity replacement, NOT character-LoRA generation — the source must be a
  real face photo, not a text description.
when_NOT_to_use: >
  - For consistent character identity ACROSS multiple new generations: train a
    LoRA via `submit_lora_train` and use that instead. Face-swap is per-asset
    not per-project.
  - For garment / outfit swaps: use `fashn-tryon` or `flux-vto`.
  - For lipsync / talking-head: use `lipsync`, `talking-head`, or `heygen-twin`
    — those preserve identity AND drive mouth motion. Face-swap does identity
    only, no mouth-motion control.
  - For LIVE LV2V streams: see `cast-live-broadcast.md` (planned PR-C); the
    fal face-swap caps are HTTP-batch only and cannot run inside a streaming
    pipeline.
---

# face-swap — capability skill

## Quick reference

| Cap name | Backend (fal) | Surface | Cost | Cap |
|---|---|---|---|---|
| `face-swap-image` | `half-moon-ai/ai-face-swap/faceswapimage` | image | **$0.009 / generation** | 4 concurrent |
| `face-swap-video` | `half-moon-ai/ai-face-swap/faceswapvideo` | video (≤25 fps, ≤25 min input) | **$0.024 / second** | 2 concurrent |
| `face-swap` *(alias)* | → `face-swap-image` | image | same | same |

The bare `face-swap` name is kept as an alias for backward compatibility — old prompts and agents that say `face-swap` still resolve to the image variant.

## What it does

- Takes two inputs: a TARGET (image or video) and a SOURCE FACE (a single identity photo).
- Re-renders the target with the source's face inserted, preserving:
  - The target's pose, body, hands, clothing
  - The target's scene, lighting, background
  - The target's camera/composition
- Does NOT preserve the target's facial expression — the swap inherits the source's facial geometry but adapts expression to the target's pose.

## Calling pattern (today, via create_media)

The structured `face_swap` action enum lands in a follow-up PR. Today, use the existing `generate` action with an explicit `model_override`:

```
mcp__storyboard__create_media({
  action: "generate",
  prompt: "face swap — see source_url for the target",  // human-readable label
  model_override: "face-swap-image",                     // or "face-swap-video"
  source_url: "<TARGET image or video URL>",             // the body / scene
  // face_ref_url is passed via the SDK passthrough to half-moon's
  //   "face_image_url" field — the half-moon API expects this name
})
```

Half-moon's request schema (the param the BYOC adapter forwards):
- `image_url` (image variant) OR `video_url` (video variant) — the TARGET
- `face_image_url` — the SOURCE identity photo
- Optional: `multi_face: true` for scenes with multiple faces in the target

## Use scenarios (real)

1. **Product film personalization.** A DTC brand films one generic 60s product reel; the customer uploads a selfie; storyboard face-swaps every scene to the customer in ~6 minutes. The customer sees themselves wearing the product. Per-customer marginal cost: ~$1.50.
2. **Episodic cast adoption.** A creator has a /story or /film project with a generic protagonist. They want to make it about a specific person (their kid, their grandparent, a friend). One identity photo → all scenes swapped → an episode that's actually about that person.
3. **Webtoon-to-cinema casting.** A webcomic creator wants to pitch their IP as a Netflix-style short. They generate a 60s reel with a generic AI actress, then face-swap to the actor they're attaching. The pitch packet now shows the actor in cinematic scenes — zero production cost.
4. **Stock-to-personal.** A creator uses stock footage with a generic person. Face-swap personalizes it for a vlog or a campaign without re-shooting.
5. **Memorial / family.** Restore an old family photo's face to a video clip of a similar scene — "what dad would have looked like at the beach" without faking history (use with disclosure).

## Reliability ceiling (be honest in the delivery note)

Expect ~80–90% of frames to swap cleanly on frontal, well-lit footage; profiles, occlusion, small faces, and fast motion WILL produce missed or flickering frames — that's the cap's ceiling, not a retry-able bug. Retry ≤1 with a better-matched source photo (lighting + gaze), then deliver with an honest note ("identity holds in N of M shots"); for consistency across many *new* generations, fall back to a character LoRA instead.

## Failure modes & quality gates

| Symptom | Cause | Fix |
|---|---|---|
| Output looks like the source face is "stuck on" — flat, wrong lighting | Source face is from a very different lighting environment | Pick a source photo whose lighting matches the target scene better, OR run `flux-erase` + relight as post-process |
| Face not swapped on some frames of a video | Half-moon's face detector missed the face (occluded, profile, very small) | Enable `multi_face` mode if multiple faces present; otherwise accept the partial swap — most video clients tolerate it |
| Mouth/expression looks wrong | The source's neutral expression collided with the target's open-mouth speech | Pair face-swap with `lipsync` as a downstream step — face-swap first for identity, then lipsync to drive mouth motion |
| Eyes look unfocused / off-axis | The source face was looking in a different direction than the target | Pick a source photo with eye gaze matching the target's eye-line. For multi-shot reels, use 3-4 source photos with varied gaze. |

**Pre-flight check the agent should do before calling face-swap-video on a long clip:**
- Is the input <60s? If not, chunk to 5s segments first via `ffmpeg-trim`, swap each, then concat via `ffmpeg-concat`. Half-moon-video's pricing scales linearly so chunking does not raise cost; it does protect against single-call timeouts.

## Cross-surface parity (where to call this from)

| Surface | Today | After PR-B |
|---|---|---|
| MCP | `create_media({action:"generate", model_override:"face-swap-image", source_url, face_ref_url})` | Same + structured `action: "face_swap"` |
| Webapp chat | "swap my face from card-1 onto card-2" → agent routes via MCP | Right-click card → "Face swap…" → modal picks identity |
| CLI | `livepeer create-media generate --model face-swap-image --source <url> --face-ref <url>` | New shortcut `livepeer face-swap <source> --face <ref>` |
| Slash | `/swap <target-card> --face <identity-card>` | Same |

All four surfaces resolve to the same backend cap, no behavior drift.

## Honest deferrals

- **Live LV2V face-swap** is not reachable with these caps. fal has no streaming face-swap endpoint. The path is the Scope graph node (`PR-C` in the roadmap) running `inswapper-512-live` open-source at ≥30 FPS @ 512×512 inside the fal Scope runner. Tracked as the live-cast extension to OPUS 1 / MAYA / ATELIER showcases.
- **Audio-driven mouth motion** stays on `lipsync` / `talking-head`. Face-swap does not animate mouths.
- **Identity preservation across many videos** (vs across many frames of one video) should use a trained LoRA + identity-locked prompts. Face-swap is a per-asset operation; running it 60 times is fine but conceptually a LoRA does it better.

## Consent / disclosure note

Face-swap of identifiable real people is a legal surface as much as a technical one. The agent should:
- Default to a consent gate: ask the user to confirm they have rights to use the source identity (their own face, or an explicit consent from the subject).
- Apply a small "AI-altered" watermark via `pillow-watermark` on outputs intended for public publishing, unless the user explicitly opts out and acknowledges responsibility.
- Refuse swaps of minors, public figures (when no satirical / educational purpose is given), or where the target depicts a context that could mislead viewers about real events.
