# Multi-Shot Cinematic Prompt Framework (cinematic-15s preset)

> The values below (15s total, 2–5s shots, ≤1500 chars, the Style and Audio
> lines) are the **`cinematic-15s` preset** — the default. They are
> parametrizable per provider/project via `vclaw video multi-shot`
> (`--total-seconds`, `--max-chars`, `--style-line`, `--audio-line`). The hard
> rules are enforced by `runMultiShotChecks`; author prose with the
> `multi-shot-prompt` skill or `vclaw video multi-shot --auto`.

> **Director layer.** To lock a project-wide visual grammar ABOVE these prompts —
> master color system, lighting grammar, per-character camera framing, forbidden
> movements, and the one rule the camera must never break — author a Project
> Blueprint with the `ai-director` skill (`references/video/ai-director-blueprint.md`,
> `references/video/camera-bible.md`). Once persisted via
> `vclaw video director-blueprint`, every `filmmaking-prompts` packet inherits it.

---

## Overview

This framework turns a reference image and a scene brief into a ready-to-paste
timecoded multi-shot cinematic video prompt — a sequence of shots with precise
camera direction, designed for AI video generators (Seedance, Veo, Runway,
Kling, Sora, and similar tools).

**Hard rule: the final prompt must stay under the resolved preset's `maxChars`.**
For the default `cinematic-15s` preset that is 1,500 characters. The format is
deliberately compressed to fit within provider prompt-length limits. The Style
and Audio lines account for ~280 chars — plan the shot descriptions around the
remaining budget.

---

## Presets

| Preset | totalSeconds | shot range | shot count | maxChars | When to pick |
|---|---|---|---|---|---|
| `cinematic-15s` *(default)* | 15 s | 2–5 s | 3–7 | 1500 | Hand-authored cinematic clip not bound to one provider's clip duration |
| `seedance-10s` | 10 s | 2–5 s | 2–5 | 1500 | Target Seedance 2.0 clips |
| `veo-8s` | 8 s | 2–4 s | 2–4 | 1500 | Target Veo 3.x clips (standard 8 s output) |
| `runway-10s` | 10 s | 2–5 s | 2–5 | 1000 | Target Runway clips (durations enum'd to `5\|8\|10\|15`) |
| `music-video-15s` | 15 s | 1–4 s | 4–12 | 1500 | Fast performance cutting |
| `social-hook-8s` | 8 s | 1–3 s | 3–8 | 1000 | Vertical pattern-interrupt opener |

The **first four** share the same Nolan styleLine and diegetic audioLine — only
the hard provider constraints differ. The last two do not: `music-video-15s`
carries a music-driven audioLine by design (which is why the diegetic-audio
check never nags a prompt for using it verbatim). Override the lines with
`--style-line` / `--audio-line` on the CLI if you want a different look.

Both high-shot-count presets are also the ones that force the trim ladder: at
full beat prose, `music-video-15s` and `social-hook-8s` overflow their character
budgets, so `--format timecoded` compresses each shot line until it fits.

For machine-readable discovery, use:

```
vclaw video multi-shot --presets
vclaw schema --json
```

The schema dump embeds the same preset registry and stable repair guidance for
multi-shot validation issue codes.

For existing videoclaw projects, hydrate the prompt request from a storyboard
scene instead of retyping context:

```
vclaw video multi-shot --plan --from-storyboard \
  --project <slug> --scene <sceneIndex> --route seedance-direct

vclaw video multi-shot --auto --image ref.png --from-storyboard \
  --project <slug> --scene <sceneIndex> --provider veo
```

This reads the project brief and storyboard artifact, carries scene characters
into the request, uses the scene description as the default action, and records
`source` metadata on generated `multi-shot-prompt` artifacts.

---

## 5-Step Workflow

### Step 1 — Analyze the reference image

Study the uploaded image and extract a compact visual description of the subject
— enough that another model could recreate the character or object without seeing
the source. Cover:

- **Identifying features** — hair, facial hair, skin tone, age range, build,
  distinguishing marks
- **Clothing and accessories** — garments, colors, textures, layering, hats,
  glasses, held objects
- **Overall vibe** — mood, posture energy, stylistic era

Be concrete but tight. This description will be woven into shot descriptions and
counts against the 1,500-char budget. Aim for 60–120 characters of subject
description spread across the shots — not dumped in one place.

If no image has been uploaded, ask the user to upload one. The reference image is
the visual anchor for the entire sequence.

### Step 2 — Gather the scene brief

Collect four pieces of information. Ask for all four in a single message unless
the user already provided them:

1. **Character** — who is the subject? (default: infer from reference image)
2. **Action** — what is the subject doing? (required — no default; the action
   drives the edit)
3. **Location** — where is this set? (required — always ask explicitly if not
   provided; populates the Location metadata line)
4. **Time of day** — e.g. golden hour, overcast midday, blue hour, night
   (default: infer from image mood or use "natural daylight")

If the user provides these inline with their request, skip the questions and
proceed directly.

### Step 3 — Design the shot sequence

Build a sequence of shots that totals **exactly 15 seconds** (`cinematic-15s`
preset), following these constraints:

- Each shot is a **minimum of 2 seconds** and a **maximum of 5 seconds**
- Choose the shot count freely — anywhere from **3 shots** (longer,
  contemplative beats) to **7 shots** (fast, punchy cutting)
- **Vary the shot count** each time so results feel fresh — do not default to
  the same structure repeatedly
- Each shot opens with a **timecode stamp** in the format `[MM:SS - MM:SS]`
  (e.g. `[00:00 - 00:04]` for a 4-second opening shot)

The shot count should serve the action. A slow, atmospheric scene wants fewer,
longer shots. A high-energy action beat wants more, shorter shots. A reveal or
transformation might use graduated acceleration — long establishing shot cutting
to rapid close-ups.

For **each shot**, specify all four technical parameters:

| Parameter | Options |
|---|---|
| **Shot size** | wide, medium, medium close-up, close-up, macro |
| **Lens** | 24mm (environment/scale), 35mm, 50mm, 85mm (intimacy/compression) |
| **Camera angle** | low angle, high angle, eye-level, over-the-shoulder, Dutch angle |
| **Camera movement** | push in, pull out, track, orbit, pan, tilt, handheld, static |

**Vary all four parameters across the sequence.** Do not repeat the same shot
size, lens, angle, or movement in consecutive shots. The sequence should feel
edited by someone who understands visual rhythm — each cut should shift the
viewer's perspective meaningfully.

To scaffold a non-repeating camera grid automatically:

```
vclaw video multi-shot --plan --shots <3-7>
```

### Step 4 — Write the prompt

Output the sequence as **separate paragraphs inside a single fenced code block**
— one paragraph per shot, separated by a blank line. Each paragraph begins with
its timecode stamp followed by the shot description. No lists, no markdown
formatting, no headers, no numbered shots. Each shot reads as continuous
cinematic direction within its paragraph.

Weave the subject description from Step 1 naturally into the shots — mention
identifying details where visible (e.g. reference clothing in a wide shot,
facial features in a close-up) rather than front-loading a description block.

**Always end the prompt with three metadata lines** after a blank line following
the final shot. The three lines sit together as a block with no blank lines
between them:

1. **Location:** — location and time of day from the scene brief (e.g.
   `Location: Narrow Tokyo alley, night.`)
2. **Style:** — `cinematic-15s` preset fixed line:
   `Style: Cool shadows, natural skin tones. IMAX-scale composition, deep focus, practical lighting. High contrast, grounded realism. In the style of a Christopher Nolan movie.`
3. **Audio:** — `cinematic-15s` preset fixed line:
   `Audio: Diegetic sound only — natural ambience, environmental foley, and subject-driven sound.`

These three lines are non-negotiable and count against the character budget.
The Style and Audio lines are fixed at ~280 chars — plan around the remaining
~1,170 chars for shots. Override them per-project with `--style-line` and
`--audio-line`.

**Asset tags.** Reference saved characters with `@Name` inside a shot, e.g.
`Tight on @Youri, jaw set, eyes locked off-frame.` videoclaw substitutes the
character's visual descriptor and locks identity by wiring the saved reference —
you do not write the proper name or the raw URL yourself. (`@imageN` stays the
positional reference-slot binding and is left untouched.)

**Emotion → physical cues.** Models perform *physical cues* far better than named
emotions. Don't write "she looks scared" — write the body: "eyes wide, jaw slack,
breath shallow and quick." With `--dialogue`, annotate a speaker's emotion with a
trailing `[emotion]` (`"Mara: It is fine. [scared]"`) and add `--emotion-cues` to
auto-rewrite it into the physical-cue descriptor. **Extremes** (panic, terror,
rage) are the exception — leave those *named* so the model pushes the
performance; `--emotion-cues` deliberately passes them through.

### Step 5 — Count and deliver

**Count the final prompt.** If it exceeds 1,500 characters, apply the trim
priority in this order:

1. **Compress adjectives and adverbs** — cut atmospheric padding first.
   "Warm golden light spills across" → "golden light across."
2. **Merge shot descriptions** — if two consecutive shots share a location
   element, state it once.
3. **Shorten subject references** — after the first shot establishes the
   character, subsequent shots can use shorter identifiers ("he", "she",
   "they", "the figure").
4. **Simplify camera specs** — drop the lens mm if the shot size already
   implies it (a macro shot is obviously a long lens). Only do this as a last
   resort — the lens spec adds real value.
5. **Never cut**: the timecode stamps, the shot size/angle/movement specs, or
   the Location/Style/Audio metadata block.

Output the prompt in a **single fenced code block** with no commentary inside
it. Below the code block, add a brief note (2–3 sentences) covering the shot
structure chosen and one tweak to try if the first generation doesn't land.

To validate a finished prompt against the `cinematic-15s` preset rules:

```
vclaw video multi-shot --validate --file <path> --explain-issues
```

Exit 0 = clean. Issues are returned as structured JSON with `code`, `severity`,
and `message` fields. With `--explain-issues`, the JSON also includes stable
`summary` / `suggestedFix` guidance for each unique issue code.

For conservative deterministic repair:

```
vclaw video multi-shot --fix --file <path> --location "Tokyo alley" --time "night"
```

The fix path normalizes spacing and can append missing Location/Style/Audio
metadata. It intentionally does not rewrite shot prose or timecodes.

---

## Worked Example — Tokyo Alley

**Brief:** A bearded man in a backwards cap and oversized white tee, walking
through a neon-lit Tokyo alley at night.

```
[00:00 - 00:04] Wide, 24mm, low angle, tracking — a bearded man in backwards cap and white tee walks toward camera through a Tokyo alley, neon reflecting off wet asphalt.

[00:04 - 00:07] Medium, 50mm, eye-level, handheld — he moves between food stalls, warm light on his face, steam from a ramen counter beside him.

[00:07 - 00:09] Close-up, 85mm, high angle, static — his hand brushes a paper lantern, fingers lit red and gold.

[00:09 - 00:12] Wide, 35mm, Dutch angle, push in — he emerges into a broader street, neon skyline opening behind him.

[00:12 - 00:15] Medium close-up, 50mm, low angle, pull out — he stops, looks up at a flickering sign, light across his face.

Location: Narrow Tokyo alley, night.
Style: Cool shadows, natural skin tones. IMAX-scale composition, deep focus, practical lighting. High contrast, grounded realism. In the style of a Christopher Nolan movie.
Audio: Diegetic sound only — natural ambience, environmental foley, and subject-driven sound.
```

5 shots, graduated pacing — starts wide to establish the world, tightens to a
tactile close-up at the midpoint, then opens back up for the reveal. If the neon
reflections overpower the subject, try adding "subject isolated in shallow depth
of field" after the lens spec on the medium shots.

**Validation:**

```
vclaw video multi-shot --validate --file tokyo-alley.txt
# → { "valid": true, "charCount": 952, "issues": [] }
```

---

## Variation Guidance

**No action specified.** Default to movement through the space — walking,
exploring, arriving. Movement gives the edit something to cut around. Ask if
unsure, but don't block on it.

**Multiple characters.** Distribute character introductions across shots rather
than cramming everyone into shot one. Use over-the-shoulder angles to establish
spatial relationships between characters.

**Slow / contemplative scenes.** Lean toward 3–4 longer shots (4–5 seconds
each). Favor static or slow push-in movements. Use wider lenses and more
negative space.

**Fast / high-energy scenes.** Lean toward 6–7 shorter shots (2–3 seconds
each). Favor handheld, tracking, and quick pans. Use tighter shot sizes and more
aggressive angles (low, Dutch).

**Interior vs exterior.** Interiors benefit from tighter lenses (50mm, 85mm)
and closer shot sizes — there's less environment to establish. Exteriors can
open with wider lenses (24mm, 35mm) to sell the space before cutting in.

**Abstract or surreal scenes.** The framework still applies — surreal content
benefits from grounded camera language. Use Dutch angles and macro shots more
freely, but keep the technical specs precise. Dreamlike ≠ vague.

**Parametrizing the preset.** The `cinematic-15s` values are defaults.
Override them for a specific provider or project:

```
# 10-second sequence with a tighter character budget
vclaw video multi-shot --plan --total-seconds 10 --max-chars 1200

# Custom style for a different visual register
vclaw video multi-shot --auto --image ref.png --location "Paris rooftop" \
  --time "blue hour" \
  --style-line "Warm analogue grain, shallow depth of field. In the style of Wong Kar-wai." \
  --audio-line "Diegetic sound only — street noise and distant traffic."
```

**Reproducibility.** Every `--plan` emits the `seed` it was generated from
(picked automatically when `--seed` is omitted). Pass that value back as
`--seed N` to regenerate the byte-identical shot sequence — so a saved plan on
disk reproduces exactly, which is what makes the preview "exactly what you're
going to get".

---

## Anti-patterns (production-learned)

These are prompt-side mistakes that pass the structural validator but
produce unwanted output. The validator can't catch them — they're
authoring failures the video model interprets too literally.

### Negative direction doesn't work

The video models (Runway, Seedance, Veo) treat negation as ambiguous and
often honor the negated token anyway. **Do not write:**

- ❌ `"no slow-motion"` → model still applies slow-mo
- ❌ `"avoid handheld"` → may still come back handheld
- ❌ `"not in slow motion"` → still slow

**Use positive direction instead:**

- ✅ `"natural real-time pace, decisive movement"`
- ✅ `"locked-off camera, no rig motion"`
- ✅ `"crisp tempo, action-forward"`

Combining works too: `"natural real-time pace, decisive movement, no slow-motion"`
(positive first, negation second).

### Slow-motion creep

If you do NOT want slow motion, scan the prompt for every instance of
`slow-mo`, `slow motion`, `slow-motion`. Including these tokens — even
inside the Style line — biases the output toward slow motion. The
default `cinematic-15s` `styleLine` is deliberately slow-motion-free
("Cool shadows, natural skin tones. IMAX-scale composition, deep focus,
practical lighting. High contrast, grounded realism. In the style of a
Christopher Nolan movie."), so the drift comes from shot descriptions or
a custom `--style-line`, not the default. Don't add slow-motion tokens
unless you want the effect; use positive tempo phrasing instead.

### Vague camera direction

`"camera moves"` and `"dynamic shot"` and `"cinematic angle"` are
under-specified — the model picks something average. **Use the
framework's vocabulary**: a specific `shotSize`, a specific `lens`
(24mm / 35mm / 50mm / 85mm), a specific `angle`, a specific
`movement` (push-in / pull-out / dolly / handheld / locked-off / tilt /
pan / track). The validator's repeated-parameter check enforces variety
across shots; under-specification defeats it.

### Over-stuffed shot lines

Going much past ~120 chars per shot bleeds the budget and the model
starts ignoring later words. If a shot needs more detail than that, it
probably wants to be two shots.

### "Cinematic" without anchor

`"cinematic lighting, cinematic composition, cinematic mood"` — three
words doing no work. Anchor instead: `"IMAX-scale composition, deep
focus, practical lighting, high contrast"` (the default cinematic-15s
styleLine does this).

### Forgetting the metadata block

A common drift in `--auto` Gemini output: the model writes shots fine,
then drops the `Location:` / `Style:` / `Audio:` line labels at the end.
The validator catches this as `multi-shot-missing-metadata`. Re-add the
three labels exactly.

### Real-person content filter rejects photoreal references

Provider content filters (notably xskill / ARK Seedance — "may contain
real person") reject **photorealistic human faces** supplied as
`reference_images`. This silently kills the whole submission, not just
one image. Production-learned escape hatches, in order of preference:

- **Make reference art faceless.** Backlit silhouettes, figures shot from
  behind, or at distance — no clear frontal facial features — pass the
  filter. This is why per-scene storyboard grids destined for
  `reference_images` should be rendered in a silhouette / no-face register
  (see the `--no-faces` flag on `filmmaking-prompts`).
- **Prefer a single `image_url` (first-frame role) over the
  `reference_images` array.** The first-frame slot is materially more
  lenient than the multi-reference array for the same image.
- **Back-view / distance / hood** beats front-facing for any shot that
  must include a recognizable cast member.

A photoreal six-panel character sheet will almost always be rejected as a
`reference_image`; keep those as the *identity source* for image
generation, not as a video-provider reference.

### Grid leakage — the model animates the storyboard layout

When a 3×3 storyboard grid is passed as a `reference_image`, the video
model will happily **reproduce the grid itself** — the output becomes a
moving 9-panel split-screen instead of a single full-frame shot. "Read
the panels as sequential shots, not as one image" is **not enough**; the
model treats the collage as the composition to render.

Use explicit positive direction for single-frame output:

- ✅ `"Output a single full-frame cinematic shot that fills the entire frame edge to edge."`
- ✅ `"The storyboard grid is reference ONLY — perform its panels as consecutive moments over time."`
- ✅ `"No 3x3 grid, no split-screen, no panel borders, no collage, no multi-panel montage."`

The generated Seedance packets in `filmmaking-prompts.ts` now embed this
guard for both grid-bearing variants; preserve it if you touch
`seedancePromptText`.

### Plastic / AI skin and negative tempo direction

- **Plastic / AI skin.** A subject-only description with no physics clauses renders the default "AI" look. Add `--realism` on `filmmaking-prompts` (at `--detail rich`) for the `captureRealismBlock` keystone — per-zone specular kill, subsurface scattering, strand hair, contrast-curve, `--haze thin|light|heavy` volumetric depth, and `--wet` moisture (`moistureMatteClause`).
- **Negative tempo direction.** "no slow motion" / "not slow" does NOT work on these models (warned by the `negative-direction` lint). Use positive tempo phrasing; `--genre music-video` pulls in `musicSyncLine` (beat-synced, positive phrasing only).

### A distant landmark is a drifting anchor in any action scene

Image-to-video models hold **no mental map** of a space. A far-off skyline,
mountain range or tower is a bearing the audience can read — so when the camera
cuts or swings during action, the model re-invents it at the wrong angle and the
geography visibly breaks. It is the most conspicuous continuity failure there
is, because the viewer literally watches the world rotate.

Design the location to remove the anchor:

- **Enclose the space** — a courtyard, quad, walled garden, forest glade. With
  no far horizon in frame there is no bearing to get wrong, and distant elements
  become texture rather than tracked objects.
- **Flat even ground with wraparound scenery** (a ring of trees, repeating
  cloister arches) reads plausibly from any angle.
- **A large CENTRAL object helps.** A big tree or statue at the middle of the
  space is a fixed landmark that looks the same from every direction, giving the
  model something consistent to orient around. Central is safe; distant is not.
- Shoot the landmark-heavy hero view — the hilltop over the city — as a
  **separate static establishing beat**, where continuity cannot break because
  nothing moves. Then cut the action into the contained space.

`vclaw video prompt-lint` reports this as `drifting-landmark` (advisory) when a
packet combines a distant landmark with action, and no enclosure cue clears it.

### An unbounded plural invents and duplicates people

An ensemble line like

> `@A and @B, with four more women in silk sarees behind them, walk abreast`

has no identity, no count and no position for the "four more". The model fills
that licence: it duplicates the locked leads side by side, invents cast the
project never registered, and walks figures in from the frame edges **partway
through** the clip — which a single mid-frame QC grab cannot see. Eight clips of
a 37-shot film were discarded to exactly this.

The standing render rules already append *"no duplicates or extra figures"* to
every prompt, and the model **ignored it**. Prohibitions do not bind; a count
does. Three changes together fixed it:

- **State an exact count, positively, up front** — `exactly two women are in
  frame, @A and @B`. Not "only two", not "no others".
- **Describe the background as empty rather than forbidding people** — "the
  corridor beyond them is empty" works where "no extra figures" does not.
- **Tighten the lens.** 16–18mm on a two-hander leaves vacant frame the model
  treats as space to populate; 35mm removes the opportunity.

Ensembles are **two-shots, not crowds**. Route limits force this anyway — Veo
carries at most 3 image references (omni-flash 7), so a six-hander cannot be
identity-locked in one frame regardless of how it is written. Frame two locked
leads and let the cut imply the group.

`vclaw video prompt-lint --storyboard` reports `unbounded-crowd` (error) for
these phrasings, plus `missing-explicit-count` and `wide-multi-subject`
(advisory).

---

## Joey cinematic-adaptation opt-in flags

All flags are opt-in / additive — omitting them keeps output byte-identical to the legacy default. They route through the existing `filmmaking-prompts` and `multi-shot` commands (no new subcommand). See `docs/CLI_REFERENCE.md` → "Joey cinematic opt-in flags" for the full per-flag table.

- `filmmaking-prompts`: `--sheet 8-shot|6-panel` (`characterSheetSixPanelPrompt`), `--realism`/`--wet`/`--haze thin|light|heavy` (`captureRealismBlock` + `volumetricHaze`, at `--detail rich`), `--background mid-gray|white|black` (`backgroundPlate`), `--lighting <id>`/`--grade <id>` (rich cinematography-suffix registers, e.g. `night-fire`/`bleach-bypass`).
- `multi-shot`: `--genre <id>` (`resolveStyleLine`, Nolan fallback).

Operator trigger-word map: mid-gray → `backgroundPlate`; haze → `volumetricHaze`; anti-plastic → `captureRealismBlock`; wet → moisture clause; bleach-bypass / lifted-blacks → lift/gamma grade; no-on-screen-text → Last Frame suppression (10-block Seedance packet).

---

## Validator Issue Codes

`runMultiShotChecks` returns structured issues for the following conditions:

| Code | Meaning |
|---|---|
| `multi-shot-timecode-parse` | No parseable `[MM:SS - MM:SS]` stamps found |
| `multi-shot-timecode-start` | First shot does not start at 00:00 |
| `multi-shot-timecode-gap` | Gap or overlap between consecutive shots |
| `multi-shot-timecode-total` | Sequence total does not match preset `totalSeconds` |
| `multi-shot-shot-duration` | A shot is shorter than `minShotSeconds` or longer than `maxShotSeconds` |
| `multi-shot-shot-count-out-of-range` | Parsed shot count is outside the preset's `[minShots, maxShots]` window (message branches on too-few vs too-many) |
| `multi-shot-overlong` | Prompt exceeds `maxChars` |
| `multi-shot-repeated-parameter` | Consecutive shots repeat a shot size, lens, angle, or movement |
| `multi-shot-missing-metadata` | One or more of Location/Style/Audio lines is absent |
| `multi-shot-nondiegetic-audio` | The Audio line asks for a score / soundtrack / background music (**warning**, never blocking) |

### On `multi-shot-nondiegetic-audio`

Presence of an `Audio:` line was always checked; its content was not, so
`Audio: soaring orchestral score` validated clean. That is the most expensive
kind of prompt bug to find late — each clip arrives carrying its own music, the
tracks collide audibly at every cut, and nothing in the edit can fix it short of
re-rendering. Ask for diegetic sound and lay a single music bed over the
finished cut instead.

The check is deliberately narrow. It targets score/soundtrack/music vocabulary,
not the word "sound", so diegetic music *sources* still pass — a busker, a car
radio, a band playing in the scene. And it never fires when a prompt uses its
preset's own `audioLine` verbatim, so `music-video-15s` is not nagged for
intending a music-driven mix.
