@milenyumai/film-kit 2.3.4 → 2.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/README.md +6 -2
  2. package/build/index.d.ts +1 -1
  3. package/build/lib/cli.js +1 -1
  4. package/build/lib/configure.js +14 -9
  5. package/build/lib/storyboard-reference/adapters/seedance20.d.ts +1 -0
  6. package/build/lib/storyboard-reference/adapters/seedance20.js +27 -11
  7. package/build/lib/storyboard-reference/index.d.ts +1 -1
  8. package/build/lib/storyboard-reference/output-writer.js +6 -0
  9. package/build/lib/storyboard-reference/prompt-bundle-builder.js +89 -21
  10. package/build/lib/storyboard-reference/types.d.ts +35 -1
  11. package/build/lib/storyboard-reference/validators.js +9 -0
  12. package/build/lib/templates.js +1 -1
  13. package/content/skills/storyboard-reference/SKILL.md +13 -8
  14. package/content/workflows/generate-storyboard.md +8 -6
  15. package/package.json +1 -1
  16. package/packages/gpt-image-smart/content/skills/storyboard-reference/SKILL.md +13 -8
  17. package/packages/gpt-image-smart/content/workflows/generate-storyboard.md +24 -6
  18. package/packages/hybrid/content/skills/storyboard-reference/SKILL.md +13 -8
  19. package/packages/hybrid/content/workflows/generate-storyboard.md +24 -6
  20. package/packages/hybrid-smart/content/skills/storyboard-reference/SKILL.md +13 -8
  21. package/packages/hybrid-smart/content/workflows/generate-storyboard.md +24 -6
  22. package/packages/multi/build/lib/configure.js +4 -4
  23. package/packages/multi/build/lib/templates.js +9 -9
  24. package/packages/multi/content/skills/storyboard-reference/SKILL.md +13 -8
  25. package/packages/multi/content/workflows/generate-storyboard.md +24 -6
  26. package/packages/studio/content/skills/storyboard-reference/SKILL.md +13 -8
  27. package/packages/studio/content/workflows/generate-storyboard.md +24 -6
package/README.md CHANGED
@@ -183,6 +183,7 @@ npx @milenyumai/film-kit generate-storyboard \
183
183
  Outputs:
184
184
 
185
185
  - `outputs/storyboard-reference-plan.json`
186
+ - `outputs/storyboard-prompt.md`
186
187
  - `outputs/reference-prep/CHARACTER-SHEET-*.md`
187
188
  - `outputs/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md`
188
189
  - `outputs/prompt-bundles/SHOTNN.bundle.json`
@@ -196,8 +197,11 @@ Rules:
196
197
  - `@character1` is used once to create a 16:9 character sheet prompt with front, back, side, three-quarter, and face close-up views.
197
198
  - GPT Image 2 still prompts use `REFERENCE LOCK`, `Keep same`, `Change only`, and `Avoid` sections so character identity, wardrobe, props, and materials stay immutable unless explicitly changed.
198
199
  - Each `SHOTNN.md` includes a professional `GPT IMAGE 2 STORYBOARD PROMPT`; the generated shot storyboard controls composition, blocking, camera, timing, and editorial phase order only.
199
- - Storyboard prompts use production-board grammar: rough black-and-white pencil panels, strong silhouettes, visible body/camera momentum, and optional color-coded planning annotations. Seedance is instructed to follow the panel order while ignoring arrows, notes, labels, and timestamps in the rendered video.
200
+ - If no external storyboard image exists, Film-Kit still generates the GPT Image 2 storyboard bootstrap prompt and writes it to both `outputs/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md` and the convenience alias `outputs/storyboard-prompt.md`.
201
+ - Storyboard prompts default to a 12-panel 16:9 production-board sheet: white paper, rough black-and-white pencil drawings, strong silhouettes, visible body/camera momentum, cinematic camera variety, and color-coded planning annotations only. Hard negatives block photorealistic stills, full-color rendered panels, concept-art strips, CGI, anime, and polished illustration.
202
+ - Seedance treats the generated storyboard token as the complete visual/action/camera/choreography source, follows all beats left-to-right/top-to-bottom, and ignores arrows, labels, notes, page headers, timestamps, panel borders, and other annotations in the rendered video.
200
203
  - Seedance provider-facing tokens map generated character sheets first (`@Image1`, `@Image2`, ...) and the generated shot storyboard next. Legacy lowercase aliases remain documented in runtime text.
204
+ - `SHOTNN.bundle.json` includes `storyboard_creation` metadata with provider, prompt path, alias path, style contract, default panel count, reading order, panel count, forbidden visual modes, Seedance token, annotation policy, and prompt text.
201
205
  - Speaking shots must bind `Audio Plan.activeSpeakerKey` back to project-level `voiceCast`; broken voice bindings fail QA.
202
206
  - Public-figure, celebrity, likeness, logo, trademark, or brand references in the brief, dialogue metadata, or reference metadata are blocked unless safely anonymized first.
203
207
  - Phase budget: 4-6s uses 1-2 phases, 7-10s uses 2-3 phases, and 11-15s uses 3-4 phases.
@@ -216,7 +220,7 @@ CLI flags for direct storyboard bundle generation:
216
220
  | `--models` | Comma-separated target models: `veo31`, `seedance-2.0`, `kling-3.0` |
217
221
  | `--duration` | Duration in seconds per generated shot. Seedance provider range is 4-15 seconds |
218
222
  | `--aspect` | `16:9`, `9:16`, or `1:1` |
219
- | `--storyboard-panel-count-hint` | Optional total panel/phase hint. 5+ phases are split when overload splitting is enabled |
223
+ | `--storyboard-panel-count-hint` | Optional GPT Image 2 storyboard sheet panel count, `1-12`. Default: `12`. This does not by itself split SHOT files |
220
224
  | `--max-storyboard-phases` | Upper bound per shot. Default: `4` |
221
225
 
222
226
  ## CLI
package/build/index.d.ts CHANGED
@@ -4,4 +4,4 @@ export { buildStoryboardReferencePromptBundles, normalizeVideoPromptRequest, ren
4
4
  export { assertModelAllowed, getModel, getModelAdapterKey, getModelDisplayName, getReplacementModel, isActiveModelId, isDeprecatedModelId, isImageModelId, isKnownModelId, isModelSupportedByPreset, isRemovedModelId, isVideoModelId, listActiveModels, listActiveVideoModelIds, listImageModels, listModels, listModelsForPreset, listModelsForReferenceMode, listRunnableVideoModelIds, listRunnableVideoModels, listVideoModels, requireModel, validateModelAllowed } from "./lib/model-registry/index.js";
5
5
  export type { AgentConfigOptions, ConfigureFilmKitResult, ConfigureResult, FilmKitConfigFile, FilmKitConfigOptions, FilmKitPreset, GptImageFormat, GptImageQuality, GptImageSize, HybridAspectRatio, KlingPreset, NanoBananaImageSize, ReferenceMode, StoryboardReferenceConfig, SupportedModel, SupportedPlatform } from "./lib/types.js";
6
6
  export type { ActiveModelId, AudioModelId, DeprecatedModelId, ImageModelId, KnownModelId, ModelAdapterKey, ModelAllowedContext, ModelAllowedResult, ModelCapabilities, ModelLifecycleStatus, ModelModality, ModelRegistryEntry, MultimodalModelId, RemovedModelId, VideoModelId } from "./lib/model-registry/index.js";
7
- export type { CharacterReferenceSheetPrompt, ModelPromptOutput, ModelRouteMetadata, PromptBundle, ProviderAssetMappingEntry, ProviderFileLimitReport, ProviderReferenceTokenPolicy, ReferenceAsset, ReferenceAssetRequirement, SeedanceContinuityMode, ShotHandoffNote, StoryboardImagePrompt, StoryboardPhaseBudget, StoryboardReferenceBuildResult, StoryboardReferencePolicy, StoryboardReferenceWriteResult, VideoPromptRequest } from "./lib/storyboard-reference/index.js";
7
+ export type { CharacterReferenceSheetPrompt, ModelPromptOutput, ModelRouteMetadata, PromptBundle, ProviderAssetMappingEntry, ProviderFileLimitReport, ProviderReferenceTokenPolicy, ReferenceAsset, ReferenceAssetRequirement, SeedanceContinuityMode, ShotHandoffNote, StoryboardCreationMetadata, StoryboardImagePrompt, StoryboardPhaseBudget, StoryboardReferenceBuildResult, StoryboardReferencePolicy, StoryboardReferenceWriteResult, VideoPromptRequest } from "./lib/storyboard-reference/index.js";
package/build/lib/cli.js CHANGED
@@ -542,7 +542,7 @@ generate-storyboard flags:
542
542
  --dialogue Repeatable "Speaker: exact line" value
543
543
  --audio-intent SFX/ambience direction
544
544
  --style-intent Visual style direction
545
- --storyboard-panel-count-hint Panel/phase count hint; 5+ panels split into multiple SHOTNN files
545
+ --storyboard-panel-count-hint GPT Image 2 storyboard sheet panel count, 1-12; does not split SHOT files by itself
546
546
  --max-storyboard-phases Upper bound per SHOTNN storyboard phase count
547
547
 
548
548
  Install:
@@ -160,6 +160,7 @@ description: Generate storyboard-reference prompt bundles from character referen
160
160
  \`\`\`text
161
161
  ${vars.outputDir}/
162
162
  ├── storyboard-reference-plan.json
163
+ ├── storyboard-prompt.md
163
164
  ├── reference-prep/
164
165
  │ └── CHARACTER-SHEET-*.md
165
166
  ├── storyboard-prompts/
@@ -187,18 +188,21 @@ ${vars.outputDir}/
187
188
  - \`maxStoryboardPhases: ${vars.maxStoryboardPhases}\`
188
189
  - \`voiceCast\` when dialogue or narration exists
189
190
  - \`visual_world\` for camera, lens, lighting, scale, reflection, physics, screen direction, and continuity anchors
190
- 4. Split the scenario into shots by dramatic beat. Use this phase budget:
191
+ 4. Split the scenario into shots by dramatic beat. Use this video phase budget:
191
192
  - 4-6 seconds: 1-2 phases
192
193
  - 7-10 seconds: 2-3 phases
193
194
  - 11-15 seconds: 3-4 phases
194
- - 5+ distinct phases: split into separate \`SHOTNN.md\` files
195
+ - 5+ distinct real video phases, scene changes, or location/action blocks: split into separate \`SHOTNN.md\` files
196
+ - GPT Image 2 storyboard sheets may use 1-12 panels; 5-12 storyboard sheet panels alone do not force a split
195
197
  5. For each shot, write a GPT Image 2 storyboard prompt:
196
198
  - use character sheets as the only identity source
197
199
  - use optional storyboard guides only for staging and timing
200
+ - use raw black-and-white rough pencil storyboard panels, strong silhouettes, visible motion, cinematic camera variety, and color-coded planning annotations
198
201
  - include previous-shot handoff and next-shot handoff
199
202
  - preserve shared \`visual_world\`, lighting, screen direction, and action rhythm
200
203
  6. Build model-ready video prompt bundles:
201
204
  - Seedance: character sheet tokens first, generated shot storyboard token next
205
+ - Seedance: follow storyboard panels left-to-right/top-to-bottom as visual/action/camera source, but never render arrows, labels, annotations, timestamps, or panel borders
202
206
  - Veo: visual planning prompt with full audio direction
203
207
  - Kling: block-structured storyboard route, not a mandatory Start+End frame route
204
208
  7. Keep coverage inside the same \`SHOTNN.md\`; coverage uses storyboard planning prompts and does not request separate start/end still prompts.
@@ -351,13 +355,14 @@ description: Finalize storyboard-reference prompt packages after storyboard QA p
351
355
  ## Validate Files
352
356
 
353
357
  1. \`${vars.outputDir}/storyboard-reference-plan.json\` exists.
354
- 2. \`${vars.outputDir}/reference-prep/\` contains character sheet prompt files.
355
- 3. \`${vars.outputDir}/storyboard-prompts/\` contains per-shot GPT Image 2 storyboard prompts.
356
- 4. \`${vars.outputDir}/prompt-bundles/\` contains model prompt bundles.
357
- 5. Every \`${vars.outputDir}/shots/SHOTNN.md\` contains the required storyboard-reference sections.
358
- 6. Coverage stays in the same \`SHOTNN.md\`.
359
- 7. No generated shot contains forbidden start/end frame sections or exact first-frame reuse instructions.
360
- 8. \`storyboard_reference_status\` and \`storyboard_handoff_status\` are pass.
358
+ 2. \`${vars.outputDir}/storyboard-prompt.md\` exists as the storyboard bootstrap alias.
359
+ 3. \`${vars.outputDir}/reference-prep/\` contains character sheet prompt files.
360
+ 4. \`${vars.outputDir}/storyboard-prompts/\` contains per-shot GPT Image 2 storyboard prompts.
361
+ 5. \`${vars.outputDir}/prompt-bundles/\` contains model prompt bundles with \`storyboard_creation\` metadata.
362
+ 6. Every \`${vars.outputDir}/shots/SHOTNN.md\` contains the required storyboard-reference sections.
363
+ 7. Coverage stays in the same \`SHOTNN.md\`.
364
+ 8. No generated shot contains forbidden start/end frame sections or exact first-frame reuse instructions.
365
+ 9. \`storyboard_reference_status\` and \`storyboard_handoff_status\` are pass.
361
366
 
362
367
  ## Final Summary
363
368
 
@@ -10,6 +10,7 @@ export declare class Seedance20PromptAdapter extends BaseVideoModelPromptAdapter
10
10
  private getMappingEntries;
11
11
  private formatCharacterRoleLine;
12
12
  private formatStoryboardRoleLine;
13
+ private hasDanceOrSingingIntent;
13
14
  buildPrompt(input: AdapterInput): ModelPromptOutput;
14
15
  validate(output: ModelPromptOutput): ModelPromptQa;
15
16
  }
@@ -40,24 +40,37 @@ export class Seedance20PromptAdapter extends BaseVideoModelPromptAdapter {
40
40
  const storyboardEntry = this.getMappingEntries(input, "storyboard_plan")[0];
41
41
  const token = storyboardEntry?.token ?? "@Image2";
42
42
  const alias = storyboardEntry?.legacyAlias;
43
- return `Use ${token} as the shot storyboard reference for composition, blocking, camera direction, timing, action rhythm, and phase order only. Do not copy storyboard text, labels, panel borders, watermarks, logos, or alternate character design from ${token}.${alias ? ` Legacy alias: ${alias}.` : ""}`;
43
+ return `Use ${token} as the shot storyboard reference and generated storyboard reference image: the complete visual/action/camera/choreography source for beat order, composition, blocking, camera direction, timing, action rhythm, framing variety, and final pose only. Do not copy storyboard text, labels, notes, arrows, panel borders, page headers, watermarks, logos, or alternate character design from ${token}.${alias ? ` Legacy alias: ${alias}.` : ""}`;
44
+ }
45
+ hasDanceOrSingingIntent(input) {
46
+ const combined = [
47
+ input.request.brief,
48
+ input.request.audioIntent,
49
+ input.request.styleIntent,
50
+ ...input.request.dialogue.map(line => `${line.speaker}: ${line.text}`)
51
+ ].join(" ").toLowerCase();
52
+ return /dance|dancing|choreograph|sing|singing|song|vocal|sarki|sark|soyl|dans/.test(combined);
44
53
  }
45
54
  buildPrompt(input) {
46
55
  const audioPlan = buildAudioPlan(input);
47
56
  const storyboardEntry = this.getMappingEntries(input, "storyboard_plan")[0];
48
57
  const storyboardToken = storyboardEntry?.token ?? "@Image2";
49
58
  const continuityInstruction = input.continuityMode === "continuous-shot"
50
- ? "No scene cuts throughout, one continuous shot."
51
- : `Follow the generated storyboard panels in ${storyboardToken} left-to-right, top-to-bottom as the exact visual beat order. Do not reinterpret actions, poses, camera angles, emotional progression, frame variety, or the final pose. Compress the planned sequence into the full duration as concise motion snapshots; use only storyboard-motivated cuts, match cuts, whip transitions, or camera moves, and do not add unplanned cuts, extra scene jumps, or new locations.`;
59
+ ? `Use the generated storyboard reference ${storyboardToken} as the complete visual/action/camera/choreography source for this ${input.request.durationSeconds}-second video. Follow all ${input.storyboardImagePrompt.panelCount} beats sequentially from left-to-right, top-to-bottom as the exact visual beat order within one uninterrupted camera move. Do not reinterpret pose, action, camera angle, emotional progression, framing variety, movement logic, shot order, or final pose. Compress the full ${input.storyboardImagePrompt.panelCount}-beat sequence into the requested duration as fast readable motion snapshots, not full-length actions. No scene cuts throughout, one continuous shot.`
60
+ : `Use the generated storyboard reference ${storyboardToken} as the complete visual/action/camera/choreography source for this ${input.request.durationSeconds}-second video. Follow all ${input.storyboardImagePrompt.panelCount} beats sequentially from left-to-right, top-to-bottom as the exact visual beat order. Do not reinterpret pose, action, camera angle, emotional progression, framing variety, movement logic, shot order, or final pose. Compress the full ${input.storyboardImagePrompt.panelCount}-beat sequence into the requested duration as fast readable motion snapshots, not full-length actions. Use urgent rhythm, storyboard-motivated cuts, quick cuts, match cuts, whip transitions, or motivated camera moves only when the storyboard supports them. Do not add unplanned cuts, extra scene jumps, duplicate performers, or new locations.`;
52
61
  const characterEntries = this.getMappingEntries(input, "character_identity");
53
62
  const characterTokenText = characterEntries.map(entry => entry.token).join(", ") || "@Image1";
63
+ const performanceEmphasis = this.hasDanceOrSingingIntent(input)
64
+ ? "\nFor singing or dance briefs: continuous live singing must show visible breath, synchronized mouth movement, body strain, fabric motion, grounded footwork, floor contact, and phrase-level physical effort across the full movement."
65
+ : "";
54
66
  const promptText = `${this.formatCharacterRoleLine(input)}
55
67
  ${this.formatStoryboardRoleLine(input)}
56
68
 
57
69
  [REFERENCE ROLES]
58
70
  - Identity reference: ${characterTokenText} locks face, hair, body proportions, wardrobe, accessories, visible props, and material continuity.
59
- - Camera reference: ${storyboardToken} controls composition, camera direction, framing, screen direction, shot order, and lens rhythm only.
60
- - Action reference: ${storyboardToken} controls blocking, pose logic, timing, action rhythm, phase order, and emotional progression only.
71
+ - Storyboard reference image: ${storyboardToken} is the complete visual/action/camera/choreography source.
72
+ - Camera reference: ${storyboardToken} controls composition, camera direction, framing, screen direction, shot order, framing variety, and lens rhythm only.
73
+ - Action reference: ${storyboardToken} controls blocking, pose logic, timing, action rhythm, phase order, choreography, and emotional progression only.
61
74
  - Audio reference: use the Audio Plan text below for dialogue, SFX, ambience, and music intent; do not infer audio from storyboard annotations unless explicitly requested.
62
75
 
63
76
  ${continuityInstruction}
@@ -69,13 +82,13 @@ ${input.request.brief}
69
82
  ${formatPhaseLines(input.interpretation.phases)}
70
83
 
71
84
  [GPT IMAGE 2 STORYBOARD SOURCE]
72
- Use the generated storyboard image from ${input.storyboardImagePrompt.outputPath} as ${storyboardToken}. It has ${input.storyboardImagePrompt.panelCount} panel(s), follows the shot handoff, and is not an identity source. Treat colored arrows, panel labels, and lens notes as planning annotations only; never render arrows, notes, labels, timestamps, or storyboard text into the video.
85
+ Use the generated storyboard image from ${input.storyboardImagePrompt.outputPath} as ${storyboardToken}. It has ${input.storyboardImagePrompt.panelCount} panel(s), follows the shot handoff, and is not an identity source. Treat colored arrows, panel labels, lens notes, framing marks, and page headers as planning annotations only; never render storyboard annotations, arrows, labels, notes, timestamps, page headers, panel borders, or storyboard text into the video.
73
86
 
74
87
  [CAMERA]
75
88
  ${input.interpretation.cameraPlan.framing}, ${input.interpretation.cameraPlan.movement}, ${input.interpretation.cameraPlan.lens}, ${input.interpretation.cameraPlan.stabilization}. Preserve ${input.interpretation.cameraPlan.screenDirection}.
76
89
 
77
90
  [PERFORMANCE]
78
- Visible acting stays concrete and restrained: gaze, breathing, posture, hand behavior, and facial tension evolve from the brief without changing identity.
91
+ Keep the same performer identity from ${characterTokenText}; do not duplicate the character. Visible performance must include breath, mouth movement when dialogue or singing is present, body strain, fabric motion, floor or prop contact, and emotional escalation while preserving exact identity. Acting stays concrete and physically grounded: gaze, breathing, posture, hand behavior, and facial tension evolve from the brief without changing wardrobe or body design.${performanceEmphasis}
79
92
 
80
93
  [AUDIO]
81
94
  Dialogue: ${buildDialogueTranscript(input)}.
@@ -84,9 +97,9 @@ Ambience: ${audioPlan.ambience.join(", ")}.
84
97
  Music: NONE.
85
98
 
86
99
  [CONTINUITY]
87
- Identity reference stays locked to ${characterTokenText}. Storyboard ${storyboardToken} controls staging, shot order, pose logic, camera variety, emotional progression, and visual rhythm only. Character design, wardrobe, accessories, and visible props cannot be inherited from the storyboard. Storyboard text, panel borders, arrows, colored marks, lens notes, watermark, logo, and alternate character design are never identity sources and must not appear in the rendered video.
100
+ Identity reference stays locked to ${characterTokenText}. Storyboard ${storyboardToken} controls staging, shot order, pose logic, camera variety, framing variety, emotional progression, choreography, final pose, and visual rhythm only. Character design, wardrobe, accessories, and visible props cannot be inherited from the storyboard. Storyboard text, panel borders, arrows, colored marks, lens notes, page headers, watermark, logo, and alternate character design are never identity sources and must not appear in the rendered video.
88
101
 
89
- Avoid: identity drift, face drift, outfit drift, storyboard text, panel borders, colored arrows, annotation marks, lens notes, timestamps, watermark, logo, distorted hands, rubbery motion, flicker, unnatural camera jumps.`;
102
+ Avoid: identity drift, face drift, outfit drift, duplicated performer, storyboard text, annotations, panel borders, colored arrows, annotation marks, lens notes, labels, notes, page headers, timestamps, watermark, logo, distorted hands, rubbery motion, flicker, unnatural camera jumps. No text, no annotations, no labels, no notes, no timestamps, no page headers, no watermark.`;
90
103
  const output = {
91
104
  model: this.model,
92
105
  displayName: getDisplayName(this.model),
@@ -123,13 +136,16 @@ Avoid: identity drift, face drift, outfit drift, storyboard text, panel borders,
123
136
  usesStoryboardToken: output.promptText.includes(storyboardToken) && /shot storyboard reference/i.test(output.promptText),
124
137
  followsStoryboardOrder: continuityMode === "continuous-shot"
125
138
  ? hasNoCutsRule
139
+ && /Follow all \d+ beats sequentially from left-to-right, top-to-bottom/i.test(output.promptText)
140
+ && /Do not reinterpret pose, action, camera angle, emotional progression/i.test(output.promptText)
126
141
  : /left-to-right, top-to-bottom/i.test(output.promptText)
127
- && /Do not reinterpret actions, poses, camera angles, emotional progression/i.test(output.promptText),
142
+ && /Do not reinterpret pose, action, camera angle, emotional progression/i.test(output.promptText),
128
143
  separatesReferenceRoles: /Identity reference:/i.test(output.promptText)
144
+ && /Storyboard reference image:/i.test(output.promptText)
129
145
  && /Camera reference:/i.test(output.promptText)
130
146
  && /Action reference:/i.test(output.promptText)
131
147
  && /Audio reference:/i.test(output.promptText),
132
- blocksStoryboardIdentitySources: /Storyboard text, panel borders, arrows, colored marks, lens notes, watermark, logo, and alternate character design are never identity sources/i.test(output.promptText),
148
+ blocksStoryboardIdentitySources: /Storyboard text, panel borders, arrows, colored marks, lens notes, page headers, watermark, logo, and alternate character design are never identity sources/i.test(output.promptText),
133
149
  continuityMode: continuityMode === "continuous-shot"
134
150
  ? hasNoCutsRule
135
151
  : !hasNoCutsRule && /storyboard-motivated cuts/i.test(output.promptText),
@@ -4,4 +4,4 @@ export { resolveAssetRoles } from "./asset-role-resolver.js";
4
4
  export { interpretStoryboard } from "./storyboard-interpreter.js";
5
5
  export { renderShotMarkdown, writeStoryboardReferenceOutputs } from "./output-writer.js";
6
6
  export { assertSafeStoryboardReferenceRequest, assertStoryboardReferenceBuildPass, validateModelPromptOutput, validatePromptBundle, validateResolvedAssetRoles } from "./validators.js";
7
- export type { AdapterInput, AudioPlan, CameraPlan, CharacterReferenceSheetPrompt, ContinuityAnchors, DialogueLine, ModelPromptOutput, ModelPromptQa, ModelRouteMetadata, NormalizedVideoPromptRequest, PromptBundle, PromptBundleQa, ProviderAssetMappingEntry, ProviderFileLimitReport, ProviderReferenceTokenPolicy, ReferenceAsset, ReferenceAssetRequirement, ReferenceAssetRole, ReferenceLockStrength, ResolvedAssetRoles, SeedanceContinuityMode, ShotHandoffNote, StoryboardImagePrompt, StoryboardInterpretation, StoryboardPhase, StoryboardPhaseBudget, StoryboardReferenceBuildResult, StoryboardReferencePlan, StoryboardReferencePolicy, StoryboardReferenceWriteResult, VideoModelPromptAdapter, VideoPromptRequest, VisualWorld, VoiceCastEntry } from "./types.js";
7
+ export type { AdapterInput, AudioPlan, CameraPlan, CharacterReferenceSheetPrompt, ContinuityAnchors, DialogueLine, ModelPromptOutput, ModelPromptQa, ModelRouteMetadata, NormalizedVideoPromptRequest, PromptBundle, PromptBundleQa, ProviderAssetMappingEntry, ProviderFileLimitReport, ProviderReferenceTokenPolicy, ReferenceAsset, ReferenceAssetRequirement, ReferenceAssetRole, ReferenceLockStrength, ResolvedAssetRoles, SeedanceContinuityMode, ShotHandoffNote, StoryboardCreationMetadata, StoryboardImagePrompt, StoryboardInterpretation, StoryboardPhase, StoryboardPhaseBudget, StoryboardReferenceBuildResult, StoryboardReferencePlan, StoryboardReferencePolicy, StoryboardReferenceWriteResult, VideoModelPromptAdapter, VideoPromptRequest, VisualWorld, VoiceCastEntry } from "./types.js";
@@ -169,6 +169,9 @@ ${bundle.storyboardImagePrompt.promptText}
169
169
  \`\`\`
170
170
  `;
171
171
  }
172
+ function renderStoryboardPromptAlias(result) {
173
+ return result.bundles.map(renderStoryboardPromptFile).join("\n---\n\n");
174
+ }
172
175
  function renderQaReport(result) {
173
176
  const models = result.request.targetModels.join(", ");
174
177
  const rows = result.bundles
@@ -219,6 +222,7 @@ export async function writeStoryboardReferenceOutputs(result, rootDir = process.
219
222
  const written = [];
220
223
  const planPath = join(outputRoot, "storyboard-reference-plan.json");
221
224
  const projectInfoPath = join(outputRoot, "project-info.md");
225
+ const storyboardPromptAliasPath = join(outputRoot, "storyboard-prompt.md");
222
226
  const qaPath = join(outputRoot, "reports", "STORYBOARD-REFERENCE-QA.md");
223
227
  await writeText(planPath, `${JSON.stringify(result.plan, null, 2)}\n`);
224
228
  written.push(planPath);
@@ -234,6 +238,8 @@ export async function writeStoryboardReferenceOutputs(result, rootDir = process.
234
238
  - Safety context: ${result.request.safetyContext}
235
239
  `);
236
240
  written.push(projectInfoPath);
241
+ await writeText(storyboardPromptAliasPath, renderStoryboardPromptAlias(result));
242
+ written.push(storyboardPromptAliasPath);
237
243
  for (const prompt of result.characterReferenceSheetPrompts) {
238
244
  const promptPath = resolve(rootDir, prompt.outputPath);
239
245
  await writeText(promptPath, renderCharacterSheetPrompt(prompt));
@@ -42,10 +42,17 @@ function resolvePromptAdapter(model) {
42
42
  }
43
43
  return adapter;
44
44
  }
45
- function getStoryboardPanelCount(request, phaseBudget) {
46
- return request.storyboardPanelCountHint
47
- ?? request.shotCountHint
48
- ?? phaseBudget.recommendedMaxPhases;
45
+ const MAX_STORYBOARD_SHEET_PANELS = 12;
46
+ const DEFAULT_STORYBOARD_SHEET_PANELS = 12;
47
+ function getStoryboardSheetPanelCount(request) {
48
+ const panelCount = request.storyboardPanelCountHint ?? DEFAULT_STORYBOARD_SHEET_PANELS;
49
+ if (panelCount > MAX_STORYBOARD_SHEET_PANELS) {
50
+ throw new Error(`Invalid storyboardPanelCountHint. Expected 1-${MAX_STORYBOARD_SHEET_PANELS} panels for one GPT Image 2 storyboard sheet.`);
51
+ }
52
+ return panelCount;
53
+ }
54
+ function getVideoPhaseCount(request, phaseBudget) {
55
+ return request.shotCountHint ?? phaseBudget.recommendedMaxPhases;
49
56
  }
50
57
  function buildShotId(index) {
51
58
  return `SHOT${String(index + 1).padStart(2, "0")}`;
@@ -172,37 +179,46 @@ function buildStoryboardImagePrompt(input) {
172
179
  ? `Use external storyboard guide tokens ${assets.storyboards.map(storyboard => storyboard.token).join(", ")} only for composition, blocking, camera direction, timing, and action rhythm.`
173
180
  : "No external storyboard guide is required; infer the board from the screenplay brief, continuity notes, and visual world.";
174
181
  const phaseDirection = interpretation.phases
175
- .map(phase => `Panel ${phase.index}: ${phase.job}; ${phase.subjectAction}; camera behavior: ${phase.cameraBehavior}; background behavior: ${phase.backgroundBehavior}.`)
182
+ .map(phase => `Phase ${phase.index}: ${phase.job}; ${phase.subjectAction}; camera behavior: ${phase.cameraBehavior}; background behavior: ${phase.backgroundBehavior}.`)
176
183
  .join(" ");
184
+ const panelLabel = input.storyboardSheetPanelCount === 1
185
+ ? "1 cinematic panel"
186
+ : `${input.storyboardSheetPanelCount} cinematic panels`;
177
187
  const continuityStyle = interpretation.phases.length <= 1
178
- ? "Because this is a single uninterrupted beat, show one decisive action moment with a clear entry pose, motion direction, and final body intention inside the same panel."
179
- : "Read panels left-to-right, top-to-bottom as a planned visual beat sequence. Each panel must show a distinct body pose, camera size/angle, movement logic, and emotional escalation, not decorative micro-poses.";
188
+ ? `Because this is a single uninterrupted beat, still create ${panelLabel} as sequential motion snapshots of one continuous camera move. Each panel must clarify entry pose, motion direction, body mechanics, camera shift, and final body intention without implying separate scenes.`
189
+ : `Read panels left-to-right, top-to-bottom as a planned visual beat sequence. Create ${input.storyboardSheetPanelCount} distinct beat snapshot${input.storyboardSheetPanelCount === 1 ? "" : "s"} distributed across the video phases. Each panel must show a distinct body pose, camera size/angle, movement logic, and emotional escalation, not decorative micro-poses.`;
180
190
  return {
181
191
  shotId,
182
192
  outputPath: `${request.outputDir}/storyboard-prompts/${shotId}-GPT-IMAGE-2-STORYBOARD.md`,
183
193
  provider: "gpt-image-2",
184
194
  aspectRatio: "16:9",
185
- panelCount: interpretation.panelCount,
186
- style: "professional-production-storyboard",
195
+ panelCount: input.storyboardSheetPanelCount,
196
+ style: "raw-pencil-production-storyboard",
187
197
  characterSheetIds,
188
198
  externalStoryboardGuideIds,
189
199
  previousShotHandoff: input.previousShotHandoff,
190
200
  nextShotHandoff: input.nextShotHandoff,
191
- promptText: `REFERENCE LOCK: Use the generated character sheet reference${characterReferenceSheetPrompts.length === 1 ? "" : "s"} (${sheetRefs}) as the only source for character identity, face, hair, body proportions, wardrobe, accessories, material behavior, and visible props.
201
+ promptText: `HARD NEGATIVE STORYBOARD STYLE LOCK:
202
+ Do not create photorealistic cinematic stills.
203
+ Do not create full-color rendered panels.
204
+ Do not create concept art, movie frames, underwater/color-grade panels, 3D render, anime, CGI, or polished illustration.
205
+ Only annotation arrows/marks may use color; all storyboard artwork remains black pencil on white paper.
206
+
207
+ REFERENCE LOCK: Use the generated character sheet reference${characterReferenceSheetPrompts.length === 1 ? "" : "s"} (${sheetRefs}) as the only source for character identity, face, hair, skin texture, body proportions, wardrobe, accessories, material behavior, and visible props.
192
208
 
193
209
  Keep same: every character identity detail from the character sheet${characterReferenceSheetPrompts.length === 1 ? "" : "s"}, the declared visual world, screen direction, environmental continuity, lighting direction, prop continuity, and shot handoff logic. Storyboard text, arrows, labels, panel borders, watermarks, logos, and alternate character designs are never identity sources.
194
210
 
195
- Change only: create a professional 16:9 production storyboard page for ${shotId} with exactly ${interpretation.panelCount} cinematic panel${interpretation.panelCount === 1 ? "" : "s"}. The storyboard controls composition, blocking, camera direction, timing, phase order, action rhythm, and emotional progression only. ${externalGuideText}
211
+ Change only: Create a raw ${shotId} storyboard focused on intense physical movement and clear cinematic action from this scene: ${request.brief}. White paper production layout. 16:9 storyboard sheet, ${panelLabel}. Use exactly ${panelLabel}. The storyboard controls composition, blocking, camera direction, timing, phase order, action rhythm, and emotional progression only. ${externalGuideText}
196
212
 
197
- Storyboard drawing style: raw contemporary film storyboard, black-and-white rough pencil linework for the artwork only, minimal detail, rapid gesture energy, simple anatomy construction, strong silhouette readability, unfinished choreography-previsualization feel, not polished concept art or final render.
213
+ Storyboard drawing style: raw contemporary production storyboard with black-and-white rough pencil linework. Actual storyboard drawings must be black and white only. Use rough pencil lines, minimal detail, fast gesture drawing energy, simple anatomy construction, strong silhouette readability, lightweight unfinished choreography previs, not polished concept art or final render.
198
214
 
199
215
  Panel direction: ${continuityStyle} The scene brief is: ${request.brief} Previous handoff: ${input.previousShotHandoff}. Next handoff: ${input.nextShotHandoff}. Planned panel actions: ${phaseDirection}
200
216
 
201
- Camera and staging: show ${interpretation.cameraPlan.framing}, ${interpretation.cameraPlan.movement}, ${interpretation.cameraPlan.lens}; preserve ${interpretation.cameraPlan.screenDirection}. Use cinematic camera variety only when motivated by the beat: handheld energy, push-in, orbit, overhead, low angle, side silhouette, insert, aggressive close-up, long-lens compression, or extreme negative space. Maintain the same environment, lighting, atmosphere, foreground, midground, and background continuity: ${interpretation.visualWorld.environment}; ${interpretation.visualWorld.lighting}; ${interpretation.visualWorld.foreground}; ${interpretation.visualWorld.midground}; ${interpretation.visualWorld.background}; ${interpretation.visualWorld.atmosphere}.
217
+ Camera and staging: show ${interpretation.cameraPlan.framing}, ${interpretation.cameraPlan.movement}, ${interpretation.cameraPlan.lens}; preserve ${interpretation.cameraPlan.screenDirection}. Use cinematic arthouse camerawork with handheld energy, whip pans, orbit movement, overhead shots, low angles, side silhouettes, aggressive close-ups, long lens compression, inserts, and extreme negative space whenever motivated by the beat. Maintain the same environment, lighting, atmosphere, foreground, midground, and background continuity: ${interpretation.visualWorld.environment}; ${interpretation.visualWorld.lighting}; ${interpretation.visualWorld.foreground}; ${interpretation.visualWorld.midground}; ${interpretation.visualWorld.background}; ${interpretation.visualWorld.atmosphere}.
202
218
 
203
219
  Annotation color system: red arrows for body movement, blue arrows for camera movement, green marks for framing/composition, orange marks for lighting direction, purple marks for vocal or emotional emphasis when relevant, black text only for very short lens notes and panel labels. No timestamps.
204
220
 
205
- Every panel must contain visible momentum or clear behavioral change: gaze shift, breath, weight transfer, contact with ground/prop, fabric motion, hand tension, or a readable pose transition. Keep the location minimal and readable.
221
+ Every panel must contain visible momentum. Every panel must contain visible motion, strong body momentum, or clear behavioral change: gaze shift, breath, weight transfer, contact with ground/prop, fabric motion, hand tension, floor contact, hair or clothing motion, or a readable pose transition. Avoid static standing poses unless explicitly required by the beat. Keep the location minimal and readable. End with one overwhelming final readable movement pose or composition that preserves the shot's emotional endpoint.
206
222
 
207
223
  Avoid: identity drift, face drift, hair drift, wardrobe drift, prop drift, material drift, alternate character design, static standing poses unless explicitly required by the beat, timestamps, long text notes, storyboard text becoming scene text, new characters, new locations, logos, watermarks, decorative borders, broken perspective, impossible contact or weight, inconsistent screen direction, inconsistent light direction, photorealistic final-render polish, cartoon style, anime style, CGI look, unsafe public-figure likeness, trademarked branding.`
208
224
  };
@@ -291,6 +307,54 @@ function buildProviderReferenceTokens(providerAssetMapping) {
291
307
  audioReference: "@audio1"
292
308
  };
293
309
  }
310
+ function buildStoryboardCreationMetadata(request, storyboardImagePrompt, providerAssetMapping) {
311
+ const storyboardEntry = Object.values(providerAssetMapping)
312
+ .find(entry => entry.role === "storyboard_plan");
313
+ return {
314
+ provider: "gpt-image-2",
315
+ prompt_path: storyboardImagePrompt.outputPath,
316
+ alias_path: `${request.outputDir}/storyboard-prompt.md`,
317
+ source_mode: storyboardImagePrompt.externalStoryboardGuideIds.length > 0
318
+ ? "generated-with-external-guide"
319
+ : "generated",
320
+ panel_count: storyboardImagePrompt.panelCount,
321
+ default_panel_count: DEFAULT_STORYBOARD_SHEET_PANELS,
322
+ style_contract: "raw-pencil-production-storyboard",
323
+ forbidden_visual_modes: [
324
+ "photorealistic stills",
325
+ "full-color panels",
326
+ "concept-art strip",
327
+ "CGI render"
328
+ ],
329
+ annotation_colors_allowed: true,
330
+ reading_order: "left-to-right, top-to-bottom",
331
+ character_sheet_ids: storyboardImagePrompt.characterSheetIds,
332
+ external_storyboard_guide_ids: storyboardImagePrompt.externalStoryboardGuideIds,
333
+ seedance_token: storyboardEntry?.token ?? "@Image2",
334
+ annotation_policy: {
335
+ rendered_in_video: false,
336
+ color_system: {
337
+ red: "body movement",
338
+ blue: "camera movement",
339
+ green: "framing / composition",
340
+ orange: "lighting direction",
341
+ purple: "vocal / emotional emphasis",
342
+ black: "short lens notes and panel labels"
343
+ },
344
+ forbidden_in_video: [
345
+ "arrows",
346
+ "annotation marks",
347
+ "lens notes",
348
+ "panel labels",
349
+ "timestamps",
350
+ "panel borders",
351
+ "watermark",
352
+ "logo"
353
+ ]
354
+ },
355
+ prompt_text: storyboardImagePrompt.promptText
356
+ };
357
+ }
294
358
  function buildStoryboardReferencePolicy(request, phaseBudget, providerFileLimits, bundles, providerReferenceTokens, maxPhases, splitRequired) {
295
359
  const continuityModes = Array.from(new Set(bundles.map(bundle => bundle.continuityMode)));
296
360
  return {
@@ -325,9 +389,9 @@ function buildStoryboardReferencePolicy(request, phaseBudget, providerFileLimits
325
389
  provider: "gpt-image-2",
326
390
  generated_per_shot: true,
327
391
  aspect_ratio: "16:9",
328
- max_panels_per_shot: maxPhases,
392
+ max_panels_per_shot: MAX_STORYBOARD_SHEET_PANELS,
329
393
  panel_budget: phaseBudget.policy,
330
- professional_prompt_target_words: "160-240 words per shot storyboard prompt"
394
+ professional_prompt_target_words: "240-420 words per shot storyboard prompt"
331
395
  },
332
396
  role_separation: {
333
397
  character_identity: `${providerReferenceTokens.characterIdentities.join(", ")} control identity, face, hair, body proportions, wardrobe, accessories, and visible props.`,
@@ -376,15 +440,16 @@ export function buildStoryboardReferencePromptBundles(input) {
376
440
  const voiceCast = buildVoiceCast(request);
377
441
  const phaseBudget = buildStoryboardPhaseBudget(request.durationSeconds, request.storyboardReferenceMode.maxStoryboardPhases);
378
442
  const providerFileLimits = buildProviderFileLimitReport(request, characterReferenceSheetPrompts.length + 1);
379
- const panelCount = getStoryboardPanelCount(request, phaseBudget);
443
+ const storyboardSheetPanelCount = getStoryboardSheetPanelCount(request);
444
+ const videoPhaseCount = getVideoPhaseCount(request, phaseBudget);
380
445
  const maxPhases = phaseBudget.effectiveMaxStoryboardPhases;
381
- const splitRequired = panelCount > maxPhases;
446
+ const splitRequired = videoPhaseCount > maxPhases;
382
447
  if (splitRequired && !request.storyboardReferenceMode.splitStoryboardOverload) {
383
- throw new Error(`Storyboard has ${panelCount} phases, which exceeds maxStoryboardPhases=${maxPhases}. Enable splitStoryboardOverload or split the storyboard manually.`);
448
+ throw new Error(`Storyboard has ${videoPhaseCount} video phases, which exceeds maxStoryboardPhases=${maxPhases}. Enable splitStoryboardOverload or split the storyboard manually.`);
384
449
  }
385
450
  const phaseCounts = splitRequired && request.storyboardReferenceMode.splitStoryboardOverload
386
- ? getSplitPhaseCounts(panelCount, maxPhases)
387
- : [Math.min(panelCount, maxPhases)];
451
+ ? getSplitPhaseCounts(videoPhaseCount, maxPhases)
452
+ : [Math.min(videoPhaseCount, maxPhases)];
388
453
  const generatedAt = new Date().toISOString();
389
454
  const bundles = [];
390
455
  let previousShotHandoff = "Project opening: start from the screenplay's first visual beat.";
@@ -402,11 +467,13 @@ export function buildStoryboardReferencePromptBundles(input) {
402
467
  assets,
403
468
  shotId,
404
469
  interpretation,
470
+ storyboardSheetPanelCount,
405
471
  characterReferenceSheetPrompts,
406
472
  previousShotHandoff,
407
473
  nextShotHandoff: handoffNote.exitHandoff
408
474
  });
409
475
  const providerAssetMapping = buildProviderAssetMapping(assets, characterReferenceSheetPrompts, storyboardImagePrompt);
476
+ const storyboard_creation = buildStoryboardCreationMetadata(request, storyboardImagePrompt, providerAssetMapping);
410
477
  const referenceAssetRequirements = buildReferenceAssetRequirements(providerAssetMapping);
411
478
  const modelPrompts = buildModelPrompts(request, {
412
479
  assets,
@@ -431,6 +498,7 @@ export function buildStoryboardReferencePromptBundles(input) {
431
498
  providerFileLimits,
432
499
  handoffNote,
433
500
  storyboardImagePrompt,
501
+ storyboard_creation,
434
502
  referenceAssetRequirements,
435
503
  providerAssetMapping,
436
504
  qa: { verdict: "pass", checks: {}, issues: [], splitRequired },
@@ -128,13 +128,46 @@ export interface StoryboardImagePrompt {
128
128
  provider: "gpt-image-2";
129
129
  aspectRatio: "16:9";
130
130
  panelCount: number;
131
- style: "professional-production-storyboard";
131
+ style: "raw-pencil-production-storyboard";
132
132
  characterSheetIds: string[];
133
133
  externalStoryboardGuideIds: string[];
134
134
  previousShotHandoff: string;
135
135
  nextShotHandoff: string;
136
136
  promptText: string;
137
137
  }
138
+ export interface StoryboardCreationMetadata {
139
+ provider: "gpt-image-2";
140
+ prompt_path: string;
141
+ alias_path: string;
142
+ source_mode: "generated" | "generated-with-external-guide";
143
+ panel_count: number;
144
+ default_panel_count: 12;
145
+ style_contract: "raw-pencil-production-storyboard";
146
+ forbidden_visual_modes: [
147
+ "photorealistic stills",
148
+ "full-color panels",
149
+ "concept-art strip",
150
+ "CGI render"
151
+ ];
152
+ annotation_colors_allowed: true;
153
+ reading_order: "left-to-right, top-to-bottom";
154
+ character_sheet_ids: string[];
155
+ external_storyboard_guide_ids: string[];
156
+ seedance_token: string;
157
+ annotation_policy: {
158
+ rendered_in_video: false;
159
+ color_system: {
160
+ red: "body movement";
161
+ blue: "camera movement";
162
+ green: "framing / composition";
163
+ orange: "lighting direction";
164
+ purple: "vocal / emotional emphasis";
165
+ black: "short lens notes and panel labels";
166
+ };
167
+ forbidden_in_video: string[];
168
+ };
169
+ prompt_text: string;
170
+ }
138
171
  export type ProviderAssetMappingRole = "character_identity" | "storyboard_plan" | "style_reference" | "camera_reference" | "action_reference" | "prop_reference";
139
172
  export interface ProviderAssetMappingEntry {
140
173
  token: string;
@@ -254,6 +287,7 @@ export interface PromptBundle {
254
287
  providerFileLimits: ProviderFileLimitReport;
255
288
  handoffNote: ShotHandoffNote;
256
289
  storyboardImagePrompt: StoryboardImagePrompt;
290
+ storyboard_creation: StoryboardCreationMetadata;
257
291
  referenceAssetRequirements: ReferenceAssetRequirement[];
258
292
  providerAssetMapping: Record<string, ProviderAssetMappingEntry>;
259
293
  qa: PromptBundleQa;
@@ -113,6 +113,15 @@ export function validatePromptBundle(bundle, assets, voiceCast = []) {
113
113
  hasCharacterReference: assets.characters.length >= 1,
114
114
  hasStoryboardReference: assets.storyboards.length >= 1 || Boolean(bundle.storyboardImagePrompt),
115
115
  hasStoryboardImagePrompt: Boolean(bundle.storyboardImagePrompt?.promptText.trim()),
116
+ hasStoryboardCreationMetadata: Boolean(bundle.storyboard_creation?.prompt_text.trim())
117
+ && bundle.storyboard_creation?.prompt_text === bundle.storyboardImagePrompt.promptText
118
+ && bundle.storyboard_creation?.prompt_path === bundle.storyboardImagePrompt.outputPath
119
+ && bundle.storyboard_creation?.panel_count === bundle.storyboardImagePrompt.panelCount
120
+ && bundle.storyboard_creation?.default_panel_count === 12
121
+ && bundle.storyboard_creation?.style_contract === "raw-pencil-production-storyboard"
122
+ && bundle.storyboard_creation?.forbidden_visual_modes.includes("photorealistic stills")
123
+ && bundle.storyboard_creation?.annotation_colors_allowed === true
124
+ && bundle.storyboard_creation?.annotation_policy.rendered_in_video === false,
116
125
  storyboardPromptHasReferenceLockStructure: hasGptImageStillPromptContract(bundle.storyboardImagePrompt?.promptText ?? ""),
117
126
  hasAvoidLineEverywhere: Object.values(bundle.modelPrompts).every(output => Boolean(output) && hasAvoidOrNegativePrompt(output.promptText)),
118
127
  storyboardPromptHasAvoidLine: hasAvoidOrNegativePrompt(bundle.storyboardImagePrompt?.promptText ?? ""),
@@ -35,7 +35,7 @@ function buildStoryboardPlatformGuard(config) {
35
35
  - Do not generate main-shot \`ILK FRAME\`, \`İLK FRAME\`, or \`SON FRAME\` sections.
36
36
  - Do not use exact first-frame reuse instructions, \`SHOTNN_START\`, \`SHOTNN_END\`, or mandatory Start+End transition fields.
37
37
  - If no character reference is available through the user, an in-context image, \`--character-ref\`, or \`refs/character.png\`, stop and request one.
38
- - Required storyboard outputs: \`${config.outputDir}/storyboard-reference-plan.json\`, \`${config.outputDir}/reference-prep/\`, \`${config.outputDir}/storyboard-prompts/\`, \`${config.outputDir}/prompt-bundles/\`, \`${config.outputDir}/shots/SHOTNN.md\`, and \`${config.outputDir}/reports/STORYBOARD-REFERENCE-QA.md\`.
38
+ - Required storyboard outputs: \`${config.outputDir}/storyboard-reference-plan.json\`, \`${config.outputDir}/storyboard-prompt.md\`, \`${config.outputDir}/reference-prep/\`, \`${config.outputDir}/storyboard-prompts/\`, \`${config.outputDir}/prompt-bundles/\`, \`${config.outputDir}/shots/SHOTNN.md\`, and \`${config.outputDir}/reports/STORYBOARD-REFERENCE-QA.md\`.
39
39
  `;
40
40
  }
41
41
  function buildSeedanceProfile(active, storyboardReferenceActive = false, maxStoryboardPhases = 4) {
@@ -13,7 +13,7 @@ Use this skill when the user provides:
13
13
  - a video brief or scenario text
14
14
  - optional external storyboard guide images
15
15
 
16
- The output is a production workflow, not only a video prompt. First create one reusable GPT Image 2 character sheet prompt per reference character. Then create one GPT Image 2 storyboard prompt per `SHOTNN.md`. The generated shot storyboard is the staging reference for the final video model prompt.
16
+ The output is a production workflow, not only a video prompt. First create one reusable GPT Image 2 character sheet prompt per reference character. Then create one GPT Image 2 storyboard prompt per `SHOTNN.md`. If no external storyboard image is supplied, this generated prompt is the mandatory storyboard bootstrap step. The generated shot storyboard is the staging reference for the final video model prompt.
17
17
 
18
18
  ## Reference Prep
19
19
 
@@ -36,11 +36,13 @@ For each shot, generate a professional GPT Image 2 storyboard prompt:
36
36
 
37
37
  - provider: `gpt-image-2`
38
38
  - aspect ratio: `16:9`
39
- - panel budget: 4-6s = 1-2 panels, 7-10s = 2-3 panels, 11-15s = 3-4 panels
40
- - hard cap: max 4 panels/phases per shot unless the configured project cap is lower
41
- - split policy: 5+ distinct phases must become separate chained `SHOTNN.md` files
39
+ - storyboard sheet panel budget: default is 12 cinematic panels in one GPT Image 2 storyboard sheet; an explicit storyboard panel hint may request 1-12 panels
40
+ - video phase budget: 4-6s = 1-2 phases, 7-10s = 2-3 phases, 11-15s = 3-4 phases
41
+ - hard cap: max 4 video phases per shot unless the configured project cap is lower
42
+ - split policy: 5+ distinct real video phases, scene changes, or location/action blocks must become separate chained `SHOTNN.md` files; 5-12 storyboard sheet panels alone do not force a split
42
43
  - target detail: dense professional storyboard direction, concrete blocking and camera language, no decorative prose
43
- - storyboard art grammar: black-and-white rough pencil drawings, minimal detail, rapid gesture energy, simple anatomy construction, strong silhouette readability, unfinished previsualization feel
44
+ - storyboard art grammar: white paper 16:9 production storyboard sheet, actual drawings black and white only, rough pencil lines, minimal detail, fast gesture drawing energy, simple anatomy construction, strong silhouette readability, unfinished previsualization feel
45
+ - hard negative style lock: do not create photorealistic cinematic stills, full-color rendered panels, concept art, movie frames, underwater/color-grade panels, 3D render, anime, CGI, or polished illustration
44
46
  - annotation grammar: red arrows = body movement, blue arrows = camera movement, green marks = framing/composition, orange marks = lighting direction, purple marks = vocal/emotional emphasis, black text = very short lens notes and panel labels
45
47
  - continuity: include previous shot handoff, next shot handoff, shared `visual_world`, screen direction, lighting, and action rhythm
46
48
 
@@ -75,9 +77,10 @@ Seedance 2.0:
75
77
  - Map character sheet images to `@Image1`, `@Image2`, ... with legacy aliases `@image1`, `@image2`, ...
76
78
  - Map the generated shot storyboard to the next image token, for example one character means `@Image2`, two characters means `@Image3`.
77
79
  - Character image tokens control identity, face, body proportions, wardrobe, accessories, and visible props.
78
- - The storyboard token controls composition, blocking, camera direction, timing, action rhythm, and phase order only.
79
- - Follow generated storyboard panels left-to-right, top-to-bottom. Do not reinterpret the action, pose logic, camera angle, emotional progression, frame variety, or final pose.
80
- - Treat storyboard arrows, labels, lens notes, and colored marks as planning annotations only; never render them into the video.
80
+ - The storyboard token is the complete visual/action/camera/choreography source and controls composition, blocking, camera direction, timing, action rhythm, framing variety, final pose, and phase order only.
81
+ - Follow all storyboard beats left-to-right, top-to-bottom. Do not reinterpret pose, action, camera angle, emotional progression, framing variety, movement logic, shot order, or final pose.
82
+ - Compress the full 12-beat default storyboard sheet into the requested duration as readable motion snapshots while preserving the duration-aware video phase budget.
83
+ - Treat storyboard arrows, labels, notes, lens notes, page headers, panel borders, and colored marks as planning annotations only; never render them into the video.
81
84
  - Use explicit timeline phases when the storyboard has multiple beats.
82
85
  - Use `No scene cuts throughout, one continuous shot` only for a true single uninterrupted camera move.
83
86
  - For multi-phase storyboard prompts, use only the planned phase transitions and do not add unplanned cuts.
@@ -108,6 +111,7 @@ Each shot file contains:
108
111
  - provider reference tokens
109
112
  - GPT Image 2 storyboard prompt
110
113
  - storyboard interpretation
114
+ - storyboard_creation metadata in `SHOTNN.bundle.json`
111
115
  - audio plan
112
116
  - prompt bundle for requested models
113
117
  - QA verdict
@@ -116,6 +120,7 @@ Generated files:
116
120
 
117
121
  ```text
118
122
  $OUTPUT_DIR/storyboard-reference-plan.json
123
+ $OUTPUT_DIR/storyboard-prompt.md
119
124
  $OUTPUT_DIR/reference-prep/CHARACTER-SHEET-*.md
120
125
  $OUTPUT_DIR/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md
121
126
  $OUTPUT_DIR/prompt-bundles/SHOTNN.bundle.json