# AI Video Generation — Directional Footage for Scroll Scrub

> **Scope:** frontend-design-system
> **Layer:** 3
> **Keywords:** video generation, seedance, img2vid, endImage, directional footage, loop video, E005 moderation, cost ladder
> **Load When:** producing footage for a scroll-driven page or animating a client render

**Verified against:** seedance MCP (generate_video, generate_loop_video, get_video, list_videos) over Replicate. Last-verified: 2026-08-21.

---

How to generate footage that actually works under scroll control. The single most expensive mistake here is generating a perfect loop for a scrub section, which produces a page that feels frozen while the user scrolls. Covers the loop-versus-directional distinction, how to build directional footage, the face moderation workaround, and the cost ladder.

This is the knowledge layer. The approval gates that stop generation from burning credit belong to the calling workflow, not to this standard.

---

## Section 1: The Distinction That Decides Everything

A **perfect loop** has a last frame identical to its first: the camera and everything in it return to the start. That is exactly right for a video that plays itself on repeat, and exactly wrong for scrubbing. With start and end nearly identical, dragging the scroll appears to change nothing, and the page reads as static while the user scrolls.

Scrubbing needs the opposite: **directional movement**, with the end clearly different from the start. The scroll becomes the control for a camera traveling from one point to another.

| Use | Tool | Start vs end | Why |
|---|---|---|---|
| Hero or section driven by scroll | `generate_video` + `endImage` | **different** (push-in, dolly, reveal) | scroll must feel progression |
| Ambient background that plays itself | `generate_loop_video` | **identical** (loop seal) | seamless repeat |
| Animating a real client render | `generate_video` (img2vid) | per the desired movement | the building comes from the client, AI only animates |

**Directional is the default.** A seamless loop is the special case, reserved for a secondary ambient plane.

---

## Section 2: Building Directional Footage

Give a start image and an end image, and let the model interpolate a camera traveling between them.

1. Pick or generate the **start frame**: the wide shot, the resting state.
2. Pick or generate the **end frame** (`endImage`): the destination of the movement (a detail in close-up, a revealed facade).
3. Call `generate_video { prompt, image: start, endImage: end }`. The prompt describes the camera movement between the two.

**Movements that scrub well:**

- **Push-in / dolly-in**: wide to detail. The most reliable by a wide margin.
- **Reveal**: camera rises or translates, uncovering more of the subject.
- **Pull-back**: detail to context, the inverse of push-in.
- **Slow tilt or pan** anchored on a subject.

**Avoid for scrub:** full orbits and any movement that returns to its origin. They become loops and kill the sense of progress.

---

## Section 3: Faces Trip Moderation

Img2vid with a **human face** repeatedly fails moderation (error E005). The workaround that works is to **crop the face out of frame** before generating.

- Frame from the neck down (garment, hands, fabric) rather than the whole person. For tailoring, craft and manufacturing this usually improves the shot, because the product becomes the subject.
- Hands working (at a cuff, a button, the material) pass reliably and carry the craft story.
- If the client insists on a face, generate the **static image** with it (image generation is more permissive) and reserve video for the face-free shots.

---

## Section 4: The Cost Ladder

Every generation costs money and you rarely nail the movement on the first attempt.

1. **Draft:** fast model, 480p, 4s. Enough to judge framing and movement.
2. **Final:** only after the draft is approved, regenerate at 1080p. Then re-extract frames and swap them into the build **with a cache-bust** (`?v=N`), or the browser serves the old ones. See `frontend/scroll-driven/frame-scrub.md`.

Never open at 1080p.

---

## Section 5: Prompt Skeleton

A directional prompt does not need a loop seal. It needs to be specific about camera, start, end and legibility:

```
SCENE: [subject without a face: material, color, detail]. [environment]. Mood reference: [1-2 real refs]. Palette: [tones].
CAMERA: [directional movement] from the start frame to the end frame. Speed [slow, cinematic].
        Start = [start image], end = [endImage]. Does NOT return to the start.
ACTION ARC: opens on [initial state], camera [pushes / reveals] until [final state or detail].
        No elements that return to their starting position.
LIGHTING: [source, temperature]. Stable from start to finish, no flicker or color shift.
LEGIBILITY: leave a calm, dark region on one side of the frame for the page copy to sit over.
        The subject stays on the side OPPOSITE the copy; if it comes out on the wrong side,
        mirror it at extraction time (hflip).
TECHNICAL: img2vid with image (start) + endImage (end). No audio. No watermark.
        Draft 480p/4s; 1080p only after approval.
```

**Tone:** direct and technical, like director's notes. No hype words ("stunning", "breathtaking"). Describe what happens on screen, not editing software.

---

## Section 6: Async Contract

`generate_video` and `generate_loop_video` return a `request_id` rather than a file. Poll with `get_video { requestId, outputPath? }`, which downloads the `.mp4` once the job reports COMPLETED. `list_videos { limit? }` reads local job history and spends no credits, which also makes it the safe health check for the MCP.

---

## Checklist

- [ ] Directional footage (start differs from end) for anything scroll-driven
- [ ] Seamless loop used only for a self-playing ambient plane
- [ ] Client renders animated, never AI-recreated
- [ ] Faces cropped out of frame before img2vid
- [ ] Movement chosen from the scrub-friendly list, no orbits or returns
- [ ] Prompt reserves a calm region for copy, subject opposite the text
- [ ] Draft at 480p/4s approved before any 1080p render
- [ ] Frames re-extracted with a bumped cache-bust after the final render

## Boundary: Runtime Generation Is Another Standard

This standard is **authoring time**: a human driving the seedance MCP in a session, footage that ends
up committed as a page asset. When the **product itself** generates video at runtime — a .NET worker
creating a paid task, polling an operation, downloading bytes into its own blob store — the standard
is `ai-agents/media-video.md` (Veo via `Google.GenAI`, the HTTP-only providers, cost per second, the
2-day retention), and the surrounding job/review/labelling pipeline is
`ai-agents/media-pipeline.md`.

The face-moderation workaround in Section 3 above is the piece `ai-agents/media-video.md` cites
rather than repeats. The rule that never crosses the boundary is the hard one from
`ai-agents/media-pipeline.md`: **never generate media inside a conversation turn**.

*MORPH-SPEC by Polymorphism Tech*
