@milenyumai/film-kit 2.3.3 → 2.3.5

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 (44) hide show
  1. package/MODEL_REGISTRY.md +136 -0
  2. package/README.md +26 -2
  3. package/build/index.d.ts +3 -1
  4. package/build/index.js +1 -0
  5. package/build/lib/cli.js +26 -10
  6. package/build/lib/configure.js +16 -17
  7. package/build/lib/defaults.js +10 -0
  8. package/build/lib/film-kit.js +16 -1
  9. package/build/lib/model-registry/index.d.ts +4 -0
  10. package/build/lib/model-registry/index.js +3 -0
  11. package/build/lib/model-registry/registry.d.ts +220 -0
  12. package/build/lib/model-registry/registry.js +191 -0
  13. package/build/lib/model-registry/selectors.d.ts +23 -0
  14. package/build/lib/model-registry/selectors.js +80 -0
  15. package/build/lib/model-registry/types.d.ts +59 -0
  16. package/build/lib/model-registry/types.js +1 -0
  17. package/build/lib/model-registry/validation.d.ts +3 -0
  18. package/build/lib/model-registry/validation.js +42 -0
  19. package/build/lib/storyboard-reference/adapters/base.js +2 -5
  20. package/build/lib/storyboard-reference/adapters/seedance20.js +5 -5
  21. package/build/lib/storyboard-reference/defaults.js +2 -1
  22. package/build/lib/storyboard-reference/index.d.ts +1 -1
  23. package/build/lib/storyboard-reference/output-writer.js +6 -0
  24. package/build/lib/storyboard-reference/prompt-bundle-builder.js +103 -22
  25. package/build/lib/storyboard-reference/request-normalizer.js +6 -4
  26. package/build/lib/storyboard-reference/types.d.ts +25 -0
  27. package/build/lib/storyboard-reference/validators.js +4 -0
  28. package/build/lib/templates.js +1 -1
  29. package/build/lib/types.d.ts +2 -1
  30. package/content/skills/storyboard-reference/SKILL.md +7 -4
  31. package/content/workflows/generate-storyboard.md +7 -6
  32. package/package.json +2 -1
  33. package/packages/gpt-image-smart/content/skills/storyboard-reference/SKILL.md +7 -4
  34. package/packages/gpt-image-smart/content/workflows/generate-storyboard.md +7 -6
  35. package/packages/hybrid/content/skills/storyboard-reference/SKILL.md +7 -4
  36. package/packages/hybrid/content/workflows/generate-storyboard.md +7 -6
  37. package/packages/hybrid-smart/content/skills/storyboard-reference/SKILL.md +7 -4
  38. package/packages/hybrid-smart/content/workflows/generate-storyboard.md +7 -6
  39. package/packages/multi/build/lib/configure.js +4 -4
  40. package/packages/multi/build/lib/templates.js +9 -9
  41. package/packages/multi/content/skills/storyboard-reference/SKILL.md +7 -4
  42. package/packages/multi/content/workflows/generate-storyboard.md +7 -6
  43. package/packages/studio/content/skills/storyboard-reference/SKILL.md +7 -4
  44. package/packages/studio/content/workflows/generate-storyboard.md +7 -6
@@ -47,8 +47,8 @@ export class Seedance20PromptAdapter extends BaseVideoModelPromptAdapter {
47
47
  const storyboardEntry = this.getMappingEntries(input, "storyboard_plan")[0];
48
48
  const storyboardToken = storyboardEntry?.token ?? "@Image2";
49
49
  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.`;
50
+ ? `Use the generated storyboard reference ${storyboardToken} as the complete visual, action, camera, and choreography source for this ${input.request.durationSeconds}-second video. Follow the single storyboard beat exactly. No scene cuts throughout, one continuous shot.`
51
+ : `Use the generated storyboard reference ${storyboardToken} as the complete visual, action, camera, and 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 actions, poses, camera angles, emotional progression, frame variety, movement logic, shot order, or the final pose. Compress the full ${input.storyboardImagePrompt.panelCount}-beat sequence into the full 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
52
  const characterEntries = this.getMappingEntries(input, "character_identity");
53
53
  const characterTokenText = characterEntries.map(entry => entry.token).join(", ") || "@Image1";
54
54
  const promptText = `${this.formatCharacterRoleLine(input)}
@@ -69,13 +69,13 @@ ${input.request.brief}
69
69
  ${formatPhaseLines(input.interpretation.phases)}
70
70
 
71
71
  [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.
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, lens notes, and framing marks as planning annotations only; never render arrows, annotation marks, notes, labels, timestamps, panel borders, or storyboard text into the video.
73
73
 
74
74
  [CAMERA]
75
75
  ${input.interpretation.cameraPlan.framing}, ${input.interpretation.cameraPlan.movement}, ${input.interpretation.cameraPlan.lens}, ${input.interpretation.cameraPlan.stabilization}. Preserve ${input.interpretation.cameraPlan.screenDirection}.
76
76
 
77
77
  [PERFORMANCE]
78
- Visible acting stays concrete and restrained: gaze, breathing, posture, hand behavior, and facial tension evolve from the brief without changing identity.
78
+ 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.
79
79
 
80
80
  [AUDIO]
81
81
  Dialogue: ${buildDialogueTranscript(input)}.
@@ -86,7 +86,7 @@ Music: NONE.
86
86
  [CONTINUITY]
87
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.
88
88
 
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.`;
89
+ Avoid: identity drift, face drift, outfit drift, duplicated performer, storyboard text, annotations, panel borders, colored arrows, annotation marks, lens notes, timestamps, watermark, logo, distorted hands, rubbery motion, flicker, unnatural camera jumps. No text, no annotations, no timestamps, no watermark.`;
90
90
  const output = {
91
91
  model: this.model,
92
92
  displayName: getDisplayName(this.model),
@@ -1,9 +1,10 @@
1
+ import { listActiveVideoModelIds } from "../model-registry/index.js";
1
2
  export const STORYBOARD_REFERENCE_MODE = "storyboard-reference";
2
3
  export const DEFAULT_STORYBOARD_DURATION_SECONDS = 8;
3
4
  export const DEFAULT_STORYBOARD_ASPECT_RATIO = "16:9";
4
5
  export const DEFAULT_STORYBOARD_LANGUAGE = "NONE";
5
6
  export const DEFAULT_STORYBOARD_OUTPUT_DIR = "./outputs";
6
- export const DEFAULT_STORYBOARD_TARGET_MODELS = ["veo31", "seedance-2.0", "kling-3.0"];
7
+ export const DEFAULT_STORYBOARD_TARGET_MODELS = listActiveVideoModelIds();
7
8
  export const DEFAULT_STORYBOARD_REFERENCE_RUNTIME = {
8
9
  enabled: true,
9
10
  maxStoryboardPhases: 4,
@@ -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));
@@ -1,19 +1,57 @@
1
1
  import { resolveAssetRoles } from "./asset-role-resolver.js";
2
+ import { GenericPromptAdapter } from "./adapters/generic.js";
2
3
  import { Kling30PromptAdapter } from "./adapters/kling30.js";
3
4
  import { Seedance20PromptAdapter } from "./adapters/seedance20.js";
4
5
  import { Veo31PromptAdapter } from "./adapters/veo31.js";
6
+ import { getModelAdapterKey, requireModel } from "../model-registry/index.js";
5
7
  import { normalizeVideoPromptRequest } from "./request-normalizer.js";
6
8
  import { buildStoryboardPhaseBudget, inferContinuityMode, interpretStoryboard } from "./storyboard-interpreter.js";
7
9
  import { assertSafeStoryboardReferenceRequest, validateCharacterReferenceSheetPrompts, validateModelPromptOutput, validatePromptBundle } from "./validators.js";
8
10
  const ADAPTERS = {
9
11
  veo31: new Veo31PromptAdapter(),
10
- "seedance-2.0": new Seedance20PromptAdapter(),
11
- "kling-3.0": new Kling30PromptAdapter()
12
+ seedance20: new Seedance20PromptAdapter(),
13
+ kling30: new Kling30PromptAdapter()
12
14
  };
13
- function getStoryboardPanelCount(request, phaseBudget) {
14
- return request.storyboardPanelCountHint
15
- ?? request.shotCountHint
16
- ?? phaseBudget.recommendedMaxPhases;
15
+ function buildGenericCapabilities(model) {
16
+ const registryModel = requireModel(model);
17
+ const capabilities = {
18
+ supportsImageReference: Boolean(registryModel.capabilities.characterReference),
19
+ supportsMultipleImageReferences: Boolean(registryModel.capabilities.multipleImageReferences),
20
+ supportsStoryboardReference: Boolean(registryModel.capabilities.storyboardReference),
21
+ supportsAudio: Boolean(registryModel.capabilities.audioPlan),
22
+ supportsDialogue: Boolean(registryModel.capabilities.dialogue),
23
+ supportsCustomStoryboardPhases: Boolean(registryModel.capabilities.customStoryboardPhases),
24
+ preferredPromptShape: "natural-language"
25
+ };
26
+ if (registryModel.durationRange?.maxSeconds !== undefined) {
27
+ capabilities.maxDurationSeconds = registryModel.durationRange.maxSeconds;
28
+ }
29
+ if (registryModel.capabilities.maxStoryboardPhases !== undefined) {
30
+ capabilities.maxStoryboardPhases = registryModel.capabilities.maxStoryboardPhases;
31
+ }
32
+ return capabilities;
33
+ }
34
+ function resolvePromptAdapter(model) {
35
+ const adapterKey = getModelAdapterKey(model);
36
+ if (adapterKey === "generic") {
37
+ return new GenericPromptAdapter(model, buildGenericCapabilities(model));
38
+ }
39
+ const adapter = ADAPTERS[adapterKey];
40
+ if (!adapter) {
41
+ throw new Error(`Model ${model} does not have a storyboard-reference video adapter.`);
42
+ }
43
+ return adapter;
44
+ }
45
+ const MAX_STORYBOARD_SHEET_PANELS = 12;
46
+ function getStoryboardSheetPanelCount(request, phaseBudget) {
47
+ const panelCount = request.storyboardPanelCountHint ?? phaseBudget.recommendedMaxPhases;
48
+ if (panelCount > MAX_STORYBOARD_SHEET_PANELS) {
49
+ throw new Error(`Invalid storyboardPanelCountHint. Expected 1-${MAX_STORYBOARD_SHEET_PANELS} panels for one GPT Image 2 storyboard sheet.`);
50
+ }
51
+ return panelCount;
52
+ }
53
+ function getVideoPhaseCount(request, phaseBudget) {
54
+ return request.shotCountHint ?? phaseBudget.recommendedMaxPhases;
17
55
  }
18
56
  function buildShotId(index) {
19
57
  return `SHOT${String(index + 1).padStart(2, "0")}`;
@@ -140,37 +178,37 @@ function buildStoryboardImagePrompt(input) {
140
178
  ? `Use external storyboard guide tokens ${assets.storyboards.map(storyboard => storyboard.token).join(", ")} only for composition, blocking, camera direction, timing, and action rhythm.`
141
179
  : "No external storyboard guide is required; infer the board from the screenplay brief, continuity notes, and visual world.";
142
180
  const phaseDirection = interpretation.phases
143
- .map(phase => `Panel ${phase.index}: ${phase.job}; ${phase.subjectAction}; camera behavior: ${phase.cameraBehavior}; background behavior: ${phase.backgroundBehavior}.`)
181
+ .map(phase => `Phase ${phase.index}: ${phase.job}; ${phase.subjectAction}; camera behavior: ${phase.cameraBehavior}; background behavior: ${phase.backgroundBehavior}.`)
144
182
  .join(" ");
145
183
  const continuityStyle = interpretation.phases.length <= 1
146
184
  ? "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."
147
- : "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.";
185
+ : `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.`;
148
186
  return {
149
187
  shotId,
150
188
  outputPath: `${request.outputDir}/storyboard-prompts/${shotId}-GPT-IMAGE-2-STORYBOARD.md`,
151
189
  provider: "gpt-image-2",
152
190
  aspectRatio: "16:9",
153
- panelCount: interpretation.panelCount,
191
+ panelCount: input.storyboardSheetPanelCount,
154
192
  style: "professional-production-storyboard",
155
193
  characterSheetIds,
156
194
  externalStoryboardGuideIds,
157
195
  previousShotHandoff: input.previousShotHandoff,
158
196
  nextShotHandoff: input.nextShotHandoff,
159
- 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.
197
+ promptText: `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.
160
198
 
161
199
  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.
162
200
 
163
- 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}
201
+ Change only: create a raw cinematic storyboard sheet for ${shotId}. 16:9 storyboard sheet, exactly ${input.storyboardSheetPanelCount} cinematic panel${input.storyboardSheetPanelCount === 1 ? "" : "s"}. The storyboard controls composition, blocking, camera direction, timing, phase order, action rhythm, and emotional progression only. ${externalGuideText}
164
202
 
165
- 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.
203
+ Storyboard drawing style: raw contemporary film storyboard with black-and-white rough pencil linework. The actual storyboard drawings must be black-and-white only: 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.
166
204
 
167
205
  Panel direction: ${continuityStyle} The scene brief is: ${request.brief} Previous handoff: ${input.previousShotHandoff}. Next handoff: ${input.nextShotHandoff}. Planned panel actions: ${phaseDirection}
168
206
 
169
- 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}.
207
+ 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}.
170
208
 
171
209
  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.
172
210
 
173
- 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.
211
+ 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.
174
212
 
175
213
  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.`
176
214
  };
@@ -259,6 +297,45 @@ function buildProviderReferenceTokens(providerAssetMapping) {
259
297
  audioReference: "@audio1"
260
298
  };
261
299
  }
300
+ function buildStoryboardCreationMetadata(request, storyboardImagePrompt, providerAssetMapping) {
301
+ const storyboardEntry = Object.values(providerAssetMapping)
302
+ .find(entry => entry.role === "storyboard_plan");
303
+ return {
304
+ provider: "gpt-image-2",
305
+ prompt_path: storyboardImagePrompt.outputPath,
306
+ alias_path: `${request.outputDir}/storyboard-prompt.md`,
307
+ source_mode: storyboardImagePrompt.externalStoryboardGuideIds.length > 0
308
+ ? "generated-with-external-guide"
309
+ : "generated",
310
+ panel_count: storyboardImagePrompt.panelCount,
311
+ reading_order: "left-to-right, top-to-bottom",
312
+ character_sheet_ids: storyboardImagePrompt.characterSheetIds,
313
+ external_storyboard_guide_ids: storyboardImagePrompt.externalStoryboardGuideIds,
314
+ seedance_token: storyboardEntry?.token ?? "@Image2",
315
+ annotation_policy: {
316
+ rendered_in_video: false,
317
+ color_system: {
318
+ red: "body movement",
319
+ blue: "camera movement",
320
+ green: "framing / composition",
321
+ orange: "lighting direction",
322
+ purple: "vocal / emotional emphasis",
323
+ black: "short lens notes and panel labels"
324
+ },
325
+ forbidden_in_video: [
326
+ "arrows",
327
+ "annotation marks",
328
+ "lens notes",
329
+ "panel labels",
330
+ "timestamps",
331
+ "panel borders",
332
+ "watermark",
333
+ "logo"
334
+ ]
335
+ },
336
+ prompt_text: storyboardImagePrompt.promptText
337
+ };
338
+ }
262
339
  function buildStoryboardReferencePolicy(request, phaseBudget, providerFileLimits, bundles, providerReferenceTokens, maxPhases, splitRequired) {
263
340
  const continuityModes = Array.from(new Set(bundles.map(bundle => bundle.continuityMode)));
264
341
  return {
@@ -293,9 +370,9 @@ function buildStoryboardReferencePolicy(request, phaseBudget, providerFileLimits
293
370
  provider: "gpt-image-2",
294
371
  generated_per_shot: true,
295
372
  aspect_ratio: "16:9",
296
- max_panels_per_shot: maxPhases,
373
+ max_panels_per_shot: MAX_STORYBOARD_SHEET_PANELS,
297
374
  panel_budget: phaseBudget.policy,
298
- professional_prompt_target_words: "160-240 words per shot storyboard prompt"
375
+ professional_prompt_target_words: "240-420 words per shot storyboard prompt"
299
376
  },
300
377
  role_separation: {
301
378
  character_identity: `${providerReferenceTokens.characterIdentities.join(", ")} control identity, face, hair, body proportions, wardrobe, accessories, and visible props.`,
@@ -320,7 +397,7 @@ function buildStoryboardReferencePolicy(request, phaseBudget, providerFileLimits
320
397
  function buildModelPrompts(request, bundleInput) {
321
398
  const modelPrompts = {};
322
399
  for (const model of request.targetModels) {
323
- const adapter = ADAPTERS[model];
400
+ const adapter = resolvePromptAdapter(model);
324
401
  const output = adapter.buildPrompt({ ...bundleInput, request });
325
402
  const validatorQa = validateModelPromptOutput(output);
326
403
  output.qa = {
@@ -344,15 +421,16 @@ export function buildStoryboardReferencePromptBundles(input) {
344
421
  const voiceCast = buildVoiceCast(request);
345
422
  const phaseBudget = buildStoryboardPhaseBudget(request.durationSeconds, request.storyboardReferenceMode.maxStoryboardPhases);
346
423
  const providerFileLimits = buildProviderFileLimitReport(request, characterReferenceSheetPrompts.length + 1);
347
- const panelCount = getStoryboardPanelCount(request, phaseBudget);
424
+ const storyboardSheetPanelCount = getStoryboardSheetPanelCount(request, phaseBudget);
425
+ const videoPhaseCount = getVideoPhaseCount(request, phaseBudget);
348
426
  const maxPhases = phaseBudget.effectiveMaxStoryboardPhases;
349
- const splitRequired = panelCount > maxPhases;
427
+ const splitRequired = videoPhaseCount > maxPhases;
350
428
  if (splitRequired && !request.storyboardReferenceMode.splitStoryboardOverload) {
351
- throw new Error(`Storyboard has ${panelCount} phases, which exceeds maxStoryboardPhases=${maxPhases}. Enable splitStoryboardOverload or split the storyboard manually.`);
429
+ throw new Error(`Storyboard has ${videoPhaseCount} video phases, which exceeds maxStoryboardPhases=${maxPhases}. Enable splitStoryboardOverload or split the storyboard manually.`);
352
430
  }
353
431
  const phaseCounts = splitRequired && request.storyboardReferenceMode.splitStoryboardOverload
354
- ? getSplitPhaseCounts(panelCount, maxPhases)
355
- : [Math.min(panelCount, maxPhases)];
432
+ ? getSplitPhaseCounts(videoPhaseCount, maxPhases)
433
+ : [Math.min(videoPhaseCount, maxPhases)];
356
434
  const generatedAt = new Date().toISOString();
357
435
  const bundles = [];
358
436
  let previousShotHandoff = "Project opening: start from the screenplay's first visual beat.";
@@ -370,11 +448,13 @@ export function buildStoryboardReferencePromptBundles(input) {
370
448
  assets,
371
449
  shotId,
372
450
  interpretation,
451
+ storyboardSheetPanelCount,
373
452
  characterReferenceSheetPrompts,
374
453
  previousShotHandoff,
375
454
  nextShotHandoff: handoffNote.exitHandoff
376
455
  });
377
456
  const providerAssetMapping = buildProviderAssetMapping(assets, characterReferenceSheetPrompts, storyboardImagePrompt);
457
+ const storyboard_creation = buildStoryboardCreationMetadata(request, storyboardImagePrompt, providerAssetMapping);
378
458
  const referenceAssetRequirements = buildReferenceAssetRequirements(providerAssetMapping);
379
459
  const modelPrompts = buildModelPrompts(request, {
380
460
  assets,
@@ -399,6 +479,7 @@ export function buildStoryboardReferencePromptBundles(input) {
399
479
  providerFileLimits,
400
480
  handoffNote,
401
481
  storyboardImagePrompt,
482
+ storyboard_creation,
402
483
  referenceAssetRequirements,
403
484
  providerAssetMapping,
404
485
  qa: { verdict: "pass", checks: {}, issues: [], splitRequired },
@@ -1,5 +1,5 @@
1
+ import { validateModelAllowed } from "../model-registry/index.js";
1
2
  import { DEFAULT_STORYBOARD_ASPECT_RATIO, DEFAULT_STORYBOARD_DURATION_SECONDS, DEFAULT_STORYBOARD_LANGUAGE, DEFAULT_STORYBOARD_OUTPUT_DIR, DEFAULT_STORYBOARD_TARGET_MODELS, STORYBOARD_REFERENCE_MODE, resolveStoryboardReferenceRuntime } from "./defaults.js";
2
- const SUPPORTED_MODELS = ["veo31", "seedance-2.0", "kling-3.0"];
3
3
  const SUPPORTED_ASPECT_RATIOS = ["16:9", "9:16", "1:1"];
4
4
  function normalizePositiveInteger(value, fallback, fieldName) {
5
5
  const normalized = value ?? fallback;
@@ -13,9 +13,11 @@ function assertSupportedModels(models) {
13
13
  return DEFAULT_STORYBOARD_TARGET_MODELS.slice();
14
14
  }
15
15
  for (const model of models) {
16
- if (!SUPPORTED_MODELS.includes(model)) {
17
- throw new Error(`Unsupported target model: ${model}. Supported: ${SUPPORTED_MODELS.join(", ")}`);
18
- }
16
+ validateModelAllowed(model, {
17
+ requiredModalities: ["video"],
18
+ referenceMode: STORYBOARD_REFERENCE_MODE,
19
+ usage: "storyboard target"
20
+ });
19
21
  }
20
22
  return Array.from(new Set(models));
21
23
  }
@@ -135,6 +135,30 @@ export interface StoryboardImagePrompt {
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
+ reading_order: "left-to-right, top-to-bottom";
145
+ character_sheet_ids: string[];
146
+ external_storyboard_guide_ids: string[];
147
+ seedance_token: string;
148
+ annotation_policy: {
149
+ rendered_in_video: false;
150
+ color_system: {
151
+ red: "body movement";
152
+ blue: "camera movement";
153
+ green: "framing / composition";
154
+ orange: "lighting direction";
155
+ purple: "vocal / emotional emphasis";
156
+ black: "short lens notes and panel labels";
157
+ };
158
+ forbidden_in_video: string[];
159
+ };
160
+ prompt_text: string;
161
+ }
138
162
  export type ProviderAssetMappingRole = "character_identity" | "storyboard_plan" | "style_reference" | "camera_reference" | "action_reference" | "prop_reference";
139
163
  export interface ProviderAssetMappingEntry {
140
164
  token: string;
@@ -254,6 +278,7 @@ export interface PromptBundle {
254
278
  providerFileLimits: ProviderFileLimitReport;
255
279
  handoffNote: ShotHandoffNote;
256
280
  storyboardImagePrompt: StoryboardImagePrompt;
281
+ storyboard_creation: StoryboardCreationMetadata;
257
282
  referenceAssetRequirements: ReferenceAssetRequirement[];
258
283
  providerAssetMapping: Record<string, ProviderAssetMappingEntry>;
259
284
  qa: PromptBundleQa;
@@ -113,6 +113,10 @@ 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_path === bundle.storyboardImagePrompt.outputPath
118
+ && bundle.storyboard_creation?.panel_count === bundle.storyboardImagePrompt.panelCount
119
+ && bundle.storyboard_creation?.annotation_policy.rendered_in_video === false,
116
120
  storyboardPromptHasReferenceLockStructure: hasGptImageStillPromptContract(bundle.storyboardImagePrompt?.promptText ?? ""),
117
121
  hasAvoidLineEverywhere: Object.values(bundle.modelPrompts).every(output => Boolean(output) && hasAvoidOrNegativePrompt(output.promptText)),
118
122
  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) {
@@ -1,5 +1,6 @@
1
+ import type { VideoModelId } from "./model-registry/index.js";
1
2
  export type SupportedPlatform = "cursor" | "claude" | "copilot" | "antigravity" | "codex";
2
- export type SupportedModel = "veo31" | "kling-3.0" | "seedance-2.0";
3
+ export type SupportedModel = VideoModelId;
3
4
  export type KlingPreset = "ultra-realism" | "balanced" | "custom";
4
5
  export type FilmKitPreset = "single" | "multi" | "hybrid" | "hybrid-smart" | "gpt-image-smart" | "studio";
5
6
  export type ReferenceMode = "start-end" | "storyboard-reference" | "hybrid";
@@ -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,9 +36,10 @@ 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 follows the duration-aware phase budget, but an explicit storyboard panel hint may request 1-12 panels in one GPT Image 2 storyboard sheet
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
44
  - storyboard art grammar: black-and-white rough pencil drawings, minimal detail, rapid gesture energy, simple anatomy construction, strong silhouette readability, unfinished previsualization feel
44
45
  - 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
@@ -108,6 +109,7 @@ Each shot file contains:
108
109
  - provider reference tokens
109
110
  - GPT Image 2 storyboard prompt
110
111
  - storyboard interpretation
112
+ - storyboard_creation metadata in `SHOTNN.bundle.json`
111
113
  - audio plan
112
114
  - prompt bundle for requested models
113
115
  - QA verdict
@@ -116,6 +118,7 @@ Generated files:
116
118
 
117
119
  ```text
118
120
  $OUTPUT_DIR/storyboard-reference-plan.json
121
+ $OUTPUT_DIR/storyboard-prompt.md
119
122
  $OUTPUT_DIR/reference-prep/CHARACTER-SHEET-*.md
120
123
  $OUTPUT_DIR/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md
121
124
  $OUTPUT_DIR/prompt-bundles/SHOTNN.bundle.json
@@ -33,11 +33,12 @@ description: Generate character sheet prompts, per-shot GPT Image 2 storyboard p
33
33
  - exact identity, wardrobe, accessories, and visible props
34
34
  - no labels, text, logos, watermarks, alternate designs, or extra characters
35
35
  3. Confirm target models: `veo31`, `seedance-2.0`, `kling-3.0`, or a user-provided subset.
36
- 4. Select shot storyboard panel budget:
37
- - 4-6 seconds: 1-2 panels/phases
38
- - 7-10 seconds: 2-3 panels/phases
39
- - 11-15 seconds: 3-4 panels/phases
40
- - 5+ distinct phases: split into multiple `SHOTNN.md` files
36
+ 4. Select video phase budget and storyboard sheet panel count:
37
+ - 4-6 seconds: 1-2 video phases
38
+ - 7-10 seconds: 2-3 video phases
39
+ - 11-15 seconds: 3-4 video phases
40
+ - GPT Image 2 storyboard sheet may contain 1-12 panels
41
+ - 5+ distinct real video phases, scene changes, or location/action blocks: split into multiple `SHOTNN.md` files
41
42
  5. Build `visual_world`:
42
43
  - environment
43
44
  - lighting
@@ -89,7 +90,7 @@ npx @milenyumai/film-kit generate-storyboard \
89
90
  - Missing character reference: stop and request a valid reference.
90
91
  - Empty brief: stop and request a brief.
91
92
  - Public figure / real-person likeness / trademark risk: stop or safely anonymize before prompt generation.
92
- - 5+ storyboard phases: do not compress into one prompt; split shots.
93
+ - 5+ real video phases: do not compress into one prompt; split shots. 5-12 storyboard sheet panels alone do not force a split.
93
94
  - Missing GPT Image 2 character sheet prompt: output is invalid.
94
95
  - Missing GPT Image 2 per-shot storyboard prompt: output is invalid.
95
96
  - Missing `Avoid` / negative prompt: output is invalid.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milenyumai/film-kit",
3
- "version": "2.3.3",
3
+ "version": "2.3.5",
4
4
  "description": "Single-package Film-Kit distribution with preset-driven cinematic runtime setup for OpenAI Codex App, Claude Code, Cursor, Copilot, and Antigravity.",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",
@@ -36,6 +36,7 @@
36
36
  "packages/gpt-image-smart/content",
37
37
  "packages/studio/content",
38
38
  "content",
39
+ "MODEL_REGISTRY.md",
39
40
  "README.md",
40
41
  "LICENSE"
41
42
  ],
@@ -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,9 +36,10 @@ 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 follows the duration-aware phase budget, but an explicit storyboard panel hint may request 1-12 panels in one GPT Image 2 storyboard sheet
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
44
  - storyboard art grammar: black-and-white rough pencil drawings, minimal detail, rapid gesture energy, simple anatomy construction, strong silhouette readability, unfinished previsualization feel
44
45
  - 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
@@ -108,6 +109,7 @@ Each shot file contains:
108
109
  - provider reference tokens
109
110
  - GPT Image 2 storyboard prompt
110
111
  - storyboard interpretation
112
+ - storyboard_creation metadata in `SHOTNN.bundle.json`
111
113
  - audio plan
112
114
  - prompt bundle for requested models
113
115
  - QA verdict
@@ -116,6 +118,7 @@ Generated files:
116
118
 
117
119
  ```text
118
120
  $OUTPUT_DIR/storyboard-reference-plan.json
121
+ $OUTPUT_DIR/storyboard-prompt.md
119
122
  $OUTPUT_DIR/reference-prep/CHARACTER-SHEET-*.md
120
123
  $OUTPUT_DIR/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md
121
124
  $OUTPUT_DIR/prompt-bundles/SHOTNN.bundle.json
@@ -33,11 +33,12 @@ description: Generate character sheet prompts, per-shot GPT Image 2 storyboard p
33
33
  - exact identity, wardrobe, accessories, and visible props
34
34
  - no labels, text, logos, watermarks, alternate designs, or extra characters
35
35
  3. Confirm target models: `veo31`, `seedance-2.0`, `kling-3.0`, or a user-provided subset.
36
- 4. Select shot storyboard panel budget:
37
- - 4-6 seconds: 1-2 panels/phases
38
- - 7-10 seconds: 2-3 panels/phases
39
- - 11-15 seconds: 3-4 panels/phases
40
- - 5+ distinct phases: split into multiple `SHOTNN.md` files
36
+ 4. Select video phase budget and storyboard sheet panel count:
37
+ - 4-6 seconds: 1-2 video phases
38
+ - 7-10 seconds: 2-3 video phases
39
+ - 11-15 seconds: 3-4 video phases
40
+ - GPT Image 2 storyboard sheet may contain 1-12 panels
41
+ - 5+ distinct real video phases, scene changes, or location/action blocks: split into multiple `SHOTNN.md` files
41
42
  5. Build `visual_world`:
42
43
  - environment
43
44
  - lighting
@@ -89,7 +90,7 @@ npx @milenyumai/film-kit generate-storyboard \
89
90
  - Missing character reference: stop and request a valid reference.
90
91
  - Empty brief: stop and request a brief.
91
92
  - Public figure / real-person likeness / trademark risk: stop or safely anonymize before prompt generation.
92
- - 5+ storyboard phases: do not compress into one prompt; split shots.
93
+ - 5+ real video phases: do not compress into one prompt; split shots. 5-12 storyboard sheet panels alone do not force a split.
93
94
  - Missing GPT Image 2 character sheet prompt: output is invalid.
94
95
  - Missing GPT Image 2 per-shot storyboard prompt: output is invalid.
95
96
  - Missing `Avoid` / negative prompt: output is invalid.
@@ -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,9 +36,10 @@ 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 follows the duration-aware phase budget, but an explicit storyboard panel hint may request 1-12 panels in one GPT Image 2 storyboard sheet
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
44
  - storyboard art grammar: black-and-white rough pencil drawings, minimal detail, rapid gesture energy, simple anatomy construction, strong silhouette readability, unfinished previsualization feel
44
45
  - 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
@@ -108,6 +109,7 @@ Each shot file contains:
108
109
  - provider reference tokens
109
110
  - GPT Image 2 storyboard prompt
110
111
  - storyboard interpretation
112
+ - storyboard_creation metadata in `SHOTNN.bundle.json`
111
113
  - audio plan
112
114
  - prompt bundle for requested models
113
115
  - QA verdict
@@ -116,6 +118,7 @@ Generated files:
116
118
 
117
119
  ```text
118
120
  $OUTPUT_DIR/storyboard-reference-plan.json
121
+ $OUTPUT_DIR/storyboard-prompt.md
119
122
  $OUTPUT_DIR/reference-prep/CHARACTER-SHEET-*.md
120
123
  $OUTPUT_DIR/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md
121
124
  $OUTPUT_DIR/prompt-bundles/SHOTNN.bundle.json