Skip to content

Prompt-quality preflight ​

Seven mechanical anti-pattern checks driven by the Seedance 2.0 Handbook. They run inside director-preflight against every storyboard scene's text. They are warnings by default and promote to blocking errors when DIRECTOR_STRICT_PROMPT_QUALITY=1 is set in the environment.

The module (src/video/prompt-quality.ts) is pure: no disk I/O, no global state beyond reading the severity env var at runtime. The checks surface through the existing director-preflight JSON output — there is no new CLI command and no new smoke.

Issue codes ​

CodeWhat it catchesThreshold
prompt-quality-adjective-soupA single clause piling up comma-separated modifiers> ADJECTIVE_SOUP_THRESHOLD (default 4)
prompt-quality-multiple-actionsSerial third-person-present actions in one clause> 1
prompt-quality-multiple-camera-movesMore than one camera-move family per prompt> 1 movement family
prompt-quality-style-word-overloadStacked "cinematic/epic/atmospheric" style words> STYLE_WORDS_THRESHOLD (default 3)
prompt-quality-literary-emotionInner-state language (feels, profound sadness) instead of visible behaviorany match
prompt-quality-overlongPrompt word count above the single-shot budget> OVERLONG_WORDS_THRESHOLD (default 120)
negative-directionA negated motion/tempo clause (no/don't/avoid/without/never + slow-motion/blur/motion/movement/zoom/camera shake) — these models ignore negated directionany match outside the sanctioned-negation allowlist (on-screen text, specular kill, anti-plastic)

Vocabularies live in CAMERA_MOVE_VOCABULARY, SHOT_TYPE_VOCABULARY, and STYLE_VOCABULARY in src/video/prompt-quality.ts and are deliberately short and conservative.

Camera movement is checked separately from shot size. Movement families include push-in, pull-out, tracking, orbit, static / locked-off, crane reveal, pan, tilt, zoom, handheld, and steadicam. Shot-size terms such as wide shot, medium shot, close-up, and establishing shot do not count as movement conflicts, so wide shot, slow push-in is valid while push-in and orbit still raises prompt-quality-multiple-camera-moves.

For Seedance image-to-video work, keep imported still-image guidance separate from motion prompting. The still image should carry composition, identity, wardrobe, props, lighting, and framing. The Seedance prompt should preserve the source image and add one visible action plus one camera move for a short clip.

Dialogue duration fit ​

director-preflight also runs a dialogue timing check from dialogue-fit.ts. It is separate from the seven prompt-quality anti-pattern checks because it uses a duration budget rather than prompt wording alone.

Default behavior:

  1. scenes without durationSeconds use a 15-second target
  2. spoken dialogue is estimated at about 2.5 words per second
  3. DIALOGUE_DURATION_OVERFLOW is emitted when the estimated spoken duration exceeds the scene target
  4. the issue is a warning by default
  5. DIRECTOR_STRICT_DIALOGUE_FIT=1 promotes it to a blocking error

This check catches scripts that look fine as text but cannot be delivered naturally inside the clip duration.

Sample output ​

A scene with adjective soup and a second camera move produces director-preflight JSON like:

json
{
  "pass": true,
  "warnings": [
    {
      "severity": "warn",
      "code": "prompt-quality-adjective-soup",
      "scope": "scene:0",
      "message": "Scene 1: clause has 6 adjectives (threshold: 4): ...",
      "suggestion": "Tighten scene wording before approval; see docs/PROMPT_QUALITY.md."
    }
  ],
  "errors": []
}

Under DIRECTOR_STRICT_PROMPT_QUALITY=1 the same issues appear on errors, pass flips to false, and execute/produce is blocked (director-mode preflight failures gate provider submission).

Promoting to blocking ​

bash
DIRECTOR_STRICT_PROMPT_QUALITY=1 vclaw video director-preflight --project <slug>

Team workflows that want prompt-quality to be a release gate can export the variable in CI so every run treats handbook violations the same as content hazards. Teams still iterating can leave it unset and treat the warnings as review cues.

Integration points ​

  • Emitted by checkPromptQuality in src/video/director-preflight.ts.
  • Surfaces in the existing vclaw video director-preflight JSON payload.
  • Flows into director-preflight's result.warnings / result.errors buckets, so all downstream consumers (tests, CI checks, storyboard.md approval review) see them automatically.

Multi-shot cinematic prompt validation ​

runMultiShotChecks(prompt, preset) enforces the structural rules for multi-shot cinematic prompts. It lives in the same module as runPromptQualityChecks (src/video/prompt-quality.ts) and is invoked via:

bash
vclaw video multi-shot --validate

Unlike the seven anti-pattern checks above, all issues from runMultiShotChecks are always error severity — they are structural requirements of the multi-shot format, not stylistic guidelines, so they cannot be downgraded to warnings by omitting DIRECTOR_STRICT_PROMPT_QUALITY.

Presets ​

Six presets ship today, each declaring its own duration, shot-count window, per-shot duration bounds, and character budget. The default remains cinematic-15s; the others target a specific provider's clip duration:

Presettotalshot rangeshot countmaxChars
cinematic-15s (default)15 s2–5 s3–71500
seedance-10s10 s2–5 s2–51500
veo-8s8 s2–4 s2–41500
runway-10s10 s2–5 s2–51000
music-video-15s15 s1–4 s4–121500
social-hook-8s8 s1–3 s3–81000

Issue codes ​

CodeWhat it catches
multi-shot-timecode-parseA timecode in the prompt cannot be parsed
multi-shot-timecode-startFirst timecode is not 00:00
multi-shot-timecode-gapConsecutive timecodes overlap or leave a gap
multi-shot-timecode-totalTimecodes do not sum to the preset's totalSeconds
multi-shot-shot-durationA shot's duration falls outside the preset's [minShotSeconds, maxShotSeconds]
multi-shot-shot-count-out-of-rangeParsed shot count is outside the preset's [minShots, maxShots] window. Message branches on under vs over
multi-shot-overlongTotal prompt character count exceeds the preset's maxChars
multi-shot-repeated-parameterA consecutive pair of shots shares the same shot size, lens, angle, or camera movement
multi-shot-missing-metadataThe required Location / Style / Audio metadata block is absent

Matching for consecutive-shot-repeat checks is hyphen/space-insensitive, so push in and push-in are treated as the same value.

Canonical vocabularies ​

The shot-parameter vocabularies used for consecutive-repeat detection are defined in src/video/prompt-quality.ts and are now canonical for the entire module:

  • SHOT_SIZE_VOCABULARY — wide, medium, medium close-up, close-up, macro
  • LENS_VOCABULARY — 24mm, 35mm, 50mm, 85mm
  • ANGLE_VOCABULARY — low angle, high angle, eye-level, over-the-shoulder, Dutch angle
  • CAMERA_MOVE_VOCABULARY — movement families shared with runPromptQualityChecks

Smoke ​

bash
npm run smoke:multi-shot

Builds the project, runs vclaw video multi-shot --plan, then validates a fixture at references/video/.fixtures/multi-shot-valid.txt — a no-network plan → validate round-trip.

filmmaking-prompts artifact lint (prompt-lint) ​

Distinct from the storyboard-scene anti-pattern checks above, lintFilmmakingPrompts (src/video/prompt-lint.ts) is a separate, pure validator that runs over a filmmaking-prompts.json artifact (not storyboard scenes). It is exposed as its own command:

bash
vclaw video prompt-lint (--project <slug> | --file <path>) [--register prose|numeric] [--cast <Name:descriptor> ...] [--brand <token> ...]

Per Seedance packet it checks the 13-block order (text-driven packets only), word count (warn outside the 280–600 words/packet window), the required video blocks SUBJECT LOCK / CAPTURE REALISM / CAMERA CAPTURE (text-driven only), the single-full-frame grid guard whenever a storyboard-grid reference is attached (else error — the grid leaks as a moving split-screen), no Kelvin/degree numeric tokens in a prose-register packet, and optional proper-name / brand scrubs when --cast / --brand are passed. It also runs an anti-slop advisory over every packet — empty hype words the model cannot act on (empty evaluators like cinematic/epic, borrowed image-model tokens like 8K/masterpiece, stacked superlatives, feel-suffix vibe words, and quality-insurance negation like no blur) are flagged with the observable production language to use instead. It is advisory (warning severity, so it never flips ok); the toolchain's own emitted guard blocks are ignored and constraint-slot negation (no on-screen text) is allowlisted, so the linter never flags its own wording. The lexicon is adapted from the MIT Emily2040/seedance-2.0 repo. Output is { packets: [{ sceneIndex, issues[] }], ok }, where ok is true iff no error-severity issue is raised on any packet.

Issue codes ​

CodeWhat it catches
seedance-block-order13-block order violated (text-driven packets only)
shot-timing-sumper-shot timecodes do not tile the runtime — a gap is where the model invents a shot, an overlap is where it drops one
over-max-durationpacket runs past the 15s single-prompt ceiling (error) — split by camera vantage or by beat rather than compressing
directive-block-capmore than ~6 directive blocks on top of the structural skeleton; past that they compete and all lose weight
duplicated-factone fact (haze, cadence, text suppression) stated in two blocks — the repeat adds length without specificity
lipsync-closure-map-missinga sung line with no scored lip-seal map; the mouth will flap plausibly and sync to nothing
strobe-eats-closuresa scored closure map behind a full-strength strobe — flash-to-black hides ~half the seals
word-countPacket word count outside the 280–600 window (warning)
missing-required-blockA required video block (SUBJECT LOCK / CAPTURE REALISM / CAMERA CAPTURE) is absent
grid-guard-missingA storyboard-grid reference is attached but the single-full-frame guard is missing (error)
numeric-in-proseKelvin/degree numeric tokens in a prose-register packet
proper-name-leakA proper name survives the cast scrub (only when --cast is passed)
brand-leakA brand token survives the scrub (only when --brand is passed)
slopEmpty hype language flagged (warning) with its observable-language replacement — one aggregated issue per packet; tool-emitted blocks ignored, constraint-slot negation allowlisted
reference-transferA packet's references span ≥2 bleed-relevant domains (identity/continuity/environment/appearance) without a transfer/ignore clause (warning); references bleed, so state what each controls and what must not transfer
allocationOne packet over-allocates the fidelity budget — ≥3 of identity-detail / bold-motion / scene-density / readable-text collide in a single shot (warning); name one primary spend and split the rest into separate shots. Conservative strict cues; standing blocks never self-trigger

Follow-on roadmap ​

  • Per-project threshold overrides (today: hardcoded constants).
  • LLM-backed checks for subtler anti-patterns ("show don't tell", beat structure).
  • Auto-fix suggestions, analogous to DIRECTOR_AUTO_FIX_CONTENT=1 for content hazards.
  • Tie into the Tier-2 prompt-structure schema (item 9 in MASTER_PLAN_ALIGNMENT.md) so each check points at the matching schema section.

Built to be driven by agent hosts like Claude Code, Claude Desktop, or Codex · Source-available, commercial use requires a paid license.