# Storyboard Prompt Engineering

> Use when optimizing prompts for AI video storyboard pipelines, implementing dodge layers for content filters, adding continuity locks for retry consistency, creating custom PromptSkill modules, or debugging prompt-related quality issues in multi-pass LangGraph pipelines. Triggers include "dodge layer", "filter bypass", "continuity lock", "prompt modular", "storyboard pipeline", "PromptSkill", "分镜提示词".

- Skill: `2799662352/storyboard-prompt-engineering` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add 2799662352/storyboard-prompt-engineering`
- Raw SKILL.md: https://api.skillmd.com/api/skills/2799662352/storyboard-prompt-engineering/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: 2799662352 (https://skillmd.com/u/2799662352)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/2799662352/storyboard-prompt-engineering

---


# Storyboard Prompt Engineering

Prompt engineering toolkit for 4-pass AI video storyboard pipelines (LangGraph). Covers modular rule composition, filter bypass, and retry consistency.

## When to Use

- Adding/modifying prompt rules for storyboard generation
- Implementing or adjusting dodge layers for video API content filters (Kling/Jimeng/Seedance)
- Fixing retry consistency issues (shots being rewritten unnecessarily)
- Creating custom PromptSkill modules for new genres/styles

## Architecture

```
Pipeline (LangGraph StateGraph)
├── Pass 1: Scene     ← core + style + dodge
├── Pass 2: Character ← core + physics + dodge
├── Pass 3: Shot      ← core + dialogue + physics + dodge + continuity*
├── Pass 4: Verify    ← core + dialogue + dodge
└── Retry (score<10)  ← prepareRetry → continuity activates
```

Post-process: `sanitizer.ts` applies regex replacement + dodge layer injection on final output (covers `desc`, `act`, `motive` in seq).

## Output Schema (StoryboardResponse.seq)

Each shot in `seq` contains:

| Field | Type | Source |
|-------|------|--------|
| `id` | string | Pass 3 (shot generation) |
| `desc` | string | 5-part: 景别\|动作\|台词\|心理→外化\|运镜 |
| `act` | string? | 演出动作（纯动作，不含特效） |
| `fx` | string\|null? | 特效：风/烟/光/粒子 |
| `motive` | string? | 动机：这个动作外化了什么心理 |

`act`/`fx`/`motive` are optional fields populated by the 4-Pass Pipeline's aggregate layer. The single-pass LangChain path only produces `{id, desc}`.

## PromptSkill Quick Reference

```typescript
interface PromptSkill {
  id: string
  rules: string | ((state: PipelineStateSlice) => string)
  appliesTo: PassType[]  // 'scene' | 'character' | 'shot' | 'verify'
  priority: number       // lower = earlier in prompt
}
```

| id | type | appliesTo | priority | content |
|----|------|-----------|----------|---------|
| core | static | all | 0 | lighting, color, lens, snapshot, micro-expression, Z-axis, duration |
| dialogue | static | shot, verify | 10 | character name + dialogue verbatim extraction |
| physics | static | character, shot | 10 | physical desc, motion vectors, quantification |
| style | static | scene | 10 | color palette, light source, shadow depth |
| dodge | static | all | 20 | D1-D8 artistic obfuscation rules |
| continuity | dynamic | shot | 30 | retry reference frame lock (activates only when retryFeedback exists) |

### Priority Ranges

- **0-9**: Core constraints (always first)
- **10-19**: Domain/genre rules (style, physics, dialogue, custom genres)
- **20-29**: Safety/compliance (dodge)
- **30+**: Context-dependent (continuity, injected at runtime)

### Adding a Custom Skill

```typescript
import { BUILTIN_SKILLS, type PromptSkill } from './prompt-skills'

const horrorSkill: PromptSkill = {
  id: 'horror',
  rules: `Horror Rules:
- Shadow depth > 85%, single cold light source
- Sound: low-freq drone 30-50Hz + sudden silence gaps
- fg must have occluder (door frame/fingers/bars) for voyeuristic framing`,
  appliesTo: ['scene', 'shot'],
  priority: 15
}

const service = new StoryboardPipelineService(config, [...BUILTIN_SKILLS, horrorSkill])
```

## Dodge Layer (Dual Defense)

Two independent layers — both required:

**Layer 1 (Prompt-level):** D1-D8 rules in system prompt guide LLM to generate safe text. See `references/dodge-patterns.md`.

**Layer 2 (Post-process):** `sanitizer.ts` runs regex replacement + dodge modifier injection on final output.

CRITICAL CONSTRAINTS:
- Do NOT merge the two layers — they serve different purposes (generation guidance vs output cleanup)
- Do NOT add platform-specific rules without validated evidence of differing filter behavior
- `injectDodgeLayer` appends to `desc` with `|` separator — never insert mid-string

## Continuity Lock

Activates ONLY during retry (when `state.retryFeedback` is non-empty).

### Token Budget

`previousShots` stores `{ id, desc }` only — NOT full `ShotData`.

| Data | Est. tokens | Note |
|------|------------|------|
| 9 shots `{id, desc}` | ~800 | 5-part desc avg 80 tokens |
| Character anchors | ~200 | `[name] anchor` format |
| Lock template | ~100 | Fixed text |
| **Total** | **~1100** | ~13% of 8192 max |

**Do NOT expand PreviousShot to full ShotData** — token budget would jump to ~3000+ and crowd out generation context. The `desc` field contains the 5-part shot specification which is sufficient for continuity reference.

### How It Works

1. `prepareRetry` saves `shots.map(s => ({id, desc}))` as `previousShots`
2. `buildContinuityLock(state)` generates lock rules with character anchors + reference frames
3. Lock rule injected into shot pass system prompt at priority 30 (after all other rules)
4. Rule instructs LLM: unmentioned shots → preserve verbatim

See `references/continuity-lock.md` for implementation details.

## Common Mistakes

| Mistake | Why it's wrong | Correct approach |
|---------|---------------|-----------------|
| Expanding PreviousShot to full ShotData | Token budget ~3000+ crowds generation context | Keep `{id, desc}` only (~1100 tokens) |
| Adding `lockedShotIds` to PipelineState | Over-engineering; retryFeedback already identifies broken shots | Let continuity lock rule handle it |
| Making dodge skill dynamic (function) | Unnecessary complexity; static D1-D8 + sanitizer is sufficient | Keep dodge static, add new skills for special cases |
| Platform-specific replacement rules | No validated evidence of differing filter behavior | Use universal rules until proven insufficient |
| Putting code-level shot enforcement in generateShots | Corrupts LangGraph node purity; side effects in node functions | Keep nodes pure, enforcement belongs in post-process |

