@milenyumai/film-kit 2.2.1 → 2.3.0
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.
- package/README.md +68 -17
- package/build/index.d.ts +1 -1
- package/build/lib/cli.js +2 -2
- package/build/lib/film-kit.js +6 -4
- package/build/lib/storyboard-reference/adapters/kling30.js +3 -1
- package/build/lib/storyboard-reference/adapters/seedance20.d.ts +4 -0
- package/build/lib/storyboard-reference/adapters/seedance20.js +72 -13
- package/build/lib/storyboard-reference/adapters/veo31.js +3 -1
- package/build/lib/storyboard-reference/index.d.ts +1 -1
- package/build/lib/storyboard-reference/output-writer.js +84 -6
- package/build/lib/storyboard-reference/prompt-bundle-builder.js +295 -8
- package/build/lib/storyboard-reference/request-normalizer.js +8 -4
- package/build/lib/storyboard-reference/storyboard-interpreter.d.ts +3 -1
- package/build/lib/storyboard-reference/storyboard-interpreter.js +21 -1
- package/build/lib/storyboard-reference/types.d.ts +151 -2
- package/build/lib/storyboard-reference/validators.js +2 -5
- package/build/lib/templates.js +10 -6
- package/content/ARCHITECTURE.md +4 -4
- package/content/MASTER.md +2 -2
- package/content/RULES.md +4 -4
- package/content/agents/prompt-engineer.md +7 -7
- package/content/skills/prompt-structure/SKILL.md +14 -11
- package/content/skills/reference-locking/SKILL.md +6 -4
- package/content/skills/semantic-consistency/SKILL.md +1 -1
- package/content/skills/storyboard-reference/SKILL.md +54 -13
- package/content/workflows/generate-storyboard.md +37 -16
- package/content/workflows/generate.md +7 -7
- package/content/workflows/safety-check.md +2 -2
- package/package.json +1 -1
- package/packages/gpt-image-smart/content/skills/storyboard-reference/SKILL.md +104 -12
- package/packages/gpt-image-smart/content/workflows/generate-storyboard.md +89 -12
- package/packages/hybrid/content/skills/storyboard-reference/SKILL.md +104 -12
- package/packages/hybrid/content/workflows/generate-storyboard.md +89 -12
- package/packages/hybrid-smart/content/skills/storyboard-reference/SKILL.md +104 -12
- package/packages/hybrid-smart/content/workflows/generate-storyboard.md +89 -12
- package/packages/multi/build/cli.js +39 -0
- package/packages/multi/build/index.d.ts +1 -1
- package/packages/multi/build/lib/configure.js +208 -1
- package/packages/multi/build/lib/defaults.d.ts +3 -1
- package/packages/multi/build/lib/defaults.js +32 -0
- package/packages/multi/build/lib/templates.js +146 -60
- package/packages/multi/build/lib/types.d.ts +16 -0
- package/packages/multi/content/agents/continuity-editor.md +6 -6
- package/packages/multi/content/agents/delivery-editor.md +2 -2
- package/packages/multi/content/agents/lead-director.md +18 -10
- package/packages/multi/content/agents/semantic-auditor.md +4 -5
- package/packages/multi/content/agents/shot-generator.md +9 -27
- package/packages/multi/content/skills/storyboard-reference/SKILL.md +104 -12
- package/packages/multi/content/workflows/chain-multi.md +4 -4
- package/packages/multi/content/workflows/generate-multi.md +6 -6
- package/packages/multi/content/workflows/generate-storyboard.md +89 -12
- package/packages/multi/content/workflows/generate-teammate.md +8 -14
- package/packages/multi/content/workflows/safety-check-multi.md +7 -11
- package/packages/studio/content/skills/storyboard-reference/SKILL.md +104 -12
- package/packages/studio/content/workflows/generate-storyboard.md +89 -12
package/README.md
CHANGED
|
@@ -55,18 +55,18 @@ After the first run, Film-Kit writes `film-kit.config.json` and uses that file a
|
|
|
55
55
|
|
|
56
56
|
In Codex-enabled projects, all presets now include an optional `/codex-images` still phase after a successful `/generate`. It is always opt-in and never auto-starts.
|
|
57
57
|
|
|
58
|
-
Storyboard-reference prompt generation is also available when you have a character reference image
|
|
58
|
+
Storyboard-reference prompt generation is also available when you have a character reference image and brief. It creates one-time GPT Image 2 character sheet prompts, per-shot GPT Image 2 storyboard prompts, and model-specific video prompt bundles without requiring start/end frames. A storyboard guide image can still be supplied, but it is optional.
|
|
59
59
|
|
|
60
60
|
## Presets
|
|
61
61
|
|
|
62
|
-
| Preset | Purpose |
|
|
63
|
-
|
|
64
|
-
| `single` | Single-agent prompt runtime | `veo31`, `kling-3.0`, `seedance-2.0` | Defaults to all supported platforms |
|
|
65
|
-
| `multi` | Lead-directed multi-agent shot generation | `veo31`, `kling-3.0`, `seedance-2.0` | Defaults to `maxTeammates=5`, `batchSize=4` |
|
|
66
|
-
| `hybrid` | Nano Banana still generation + GPT Image 2 companion metadata + fixed Kling video runtime | fixed `kling-3.0` | No `--model` flag |
|
|
67
|
-
| `hybrid-smart` | Nano Banana still generation + GPT Image 2 companion metadata + dialogue-aware Veo/Kling routing | fixed smart route | No `--model` flag |
|
|
68
|
-
| `gpt-image-smart` | GPT Image 2 still generation + dialogue-aware Veo/Kling routing | fixed smart route | Defaults to `size=2048x1152`, `quality=medium`, `format=png` |
|
|
69
|
-
| `studio` | Scenario-to-render pipeline with fal.ai render-stage configuration plus GPT Image 2 companion metadata | `veo31`, `kling-3.0`, `seedance-2.0` | Includes refs dir and fal model configuration |
|
|
62
|
+
| Preset | Purpose | Video/model surface | Storyboard / reference support | Default notes |
|
|
63
|
+
|---|---|---|---|---|
|
|
64
|
+
| `single` | Single-agent prompt runtime | `veo31`, `kling-3.0`, `seedance-2.0` | Can store `storyboard-reference` config and ships the storyboard skill/workflow | Defaults to all supported platforms |
|
|
65
|
+
| `multi` | Lead-directed multi-agent shot generation | `veo31`, `kling-3.0`, `seedance-2.0` | Best fit for Seedance storyboard-reference teams: character sheets, shot storyboard prompts, team-plan metadata, handoff notes | Defaults to `maxTeammates=5`, `batchSize=4` |
|
|
66
|
+
| `hybrid` | Nano Banana still generation + GPT Image 2 companion metadata + fixed Kling video runtime | fixed `kling-3.0` | Ships the updated storyboard skill/workflow for prompt planning; video runtime stays Kling-focused | No `--model` flag |
|
|
67
|
+
| `hybrid-smart` | Nano Banana still generation + GPT Image 2 companion metadata + dialogue-aware Veo/Kling routing | fixed smart route | Ships the updated storyboard skill/workflow and GPT Image companion metadata | No `--model` flag |
|
|
68
|
+
| `gpt-image-smart` | GPT Image 2 still generation + dialogue-aware Veo/Kling routing | fixed smart route | GPT Image 2-first preset; includes the character-sheet + per-shot storyboard prompt contract | Defaults to `size=2048x1152`, `quality=medium`, `format=png` |
|
|
69
|
+
| `studio` | Scenario-to-render pipeline with fal.ai render-stage configuration plus GPT Image 2 companion metadata | `veo31`, `kling-3.0`, `seedance-2.0` | Full pipeline option for Seedance storyboard-reference plus refs dir and render-stage config | Includes refs dir and fal model configuration |
|
|
70
70
|
|
|
71
71
|
## Model Support
|
|
72
72
|
|
|
@@ -81,9 +81,9 @@ Storyboard-reference prompt generation is also available when you have a charact
|
|
|
81
81
|
- Supported in `single`, `multi`, and `studio`
|
|
82
82
|
- Runtime now includes Seedance-specific prompt guidance
|
|
83
83
|
- Seedance prompt behavior emphasizes:
|
|
84
|
-
- multimodal role assignment such as `@image1`, `@video1`, `@audio1`
|
|
85
|
-
- first-frame anchoring like `Use @
|
|
86
|
-
- continuous-shot wording such as `No scene cuts throughout, one continuous shot.`
|
|
84
|
+
- multimodal role assignment such as `@Image1` / `@image1`, `@video1`, `@audio1`
|
|
85
|
+
- first-frame anchoring like `Use @Image1 as the first frame of the scene.`
|
|
86
|
+
- continuous-shot wording such as `No scene cuts throughout, one continuous shot.` only for uninterrupted camera moves
|
|
87
87
|
- explicit extension syntax such as `Extend @video1 by 5s`
|
|
88
88
|
- separation of identity reference vs camera reference vs action reference
|
|
89
89
|
|
|
@@ -122,12 +122,34 @@ When the active model is not Kling, generated runtime files intentionally render
|
|
|
122
122
|
|
|
123
123
|
## Storyboard Reference Mode
|
|
124
124
|
|
|
125
|
-
Use this mode when the source material is a character reference image plus a
|
|
125
|
+
Use this mode when the source material is a character reference image plus a brief rather than explicit start/end frames. Film-Kit first prepares character-sheet prompts, then per-shot storyboard prompts. Optional storyboard images can be supplied as loose composition/timing guides.
|
|
126
|
+
|
|
127
|
+
Initialize a Seedance storyboard-reference runtime:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npx @milenyumai/film-kit init \
|
|
131
|
+
--preset multi \
|
|
132
|
+
--model seedance-2.0 \
|
|
133
|
+
--reference-mode storyboard-reference \
|
|
134
|
+
--max-storyboard-phases 4
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
For a GPT Image 2-first workflow, initialize the smart image preset with the same reference mode:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx @milenyumai/film-kit init \
|
|
141
|
+
--preset gpt-image-smart \
|
|
142
|
+
--reference-mode storyboard-reference \
|
|
143
|
+
--gpt-image-size 2048x1152 \
|
|
144
|
+
--gpt-image-quality medium \
|
|
145
|
+
--gpt-image-format png
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Generate prompt bundle files directly:
|
|
126
149
|
|
|
127
150
|
```bash
|
|
128
151
|
npx @milenyumai/film-kit generate-storyboard \
|
|
129
152
|
--character-ref ./refs/character.png \
|
|
130
|
-
--storyboard-ref ./refs/storyboard.png \
|
|
131
153
|
--brief ./scenario.md \
|
|
132
154
|
--models veo31,seedance-2.0,kling-3.0 \
|
|
133
155
|
--duration 8 \
|
|
@@ -135,20 +157,49 @@ npx @milenyumai/film-kit generate-storyboard \
|
|
|
135
157
|
--output-dir ./outputs
|
|
136
158
|
```
|
|
137
159
|
|
|
160
|
+
Add an external storyboard guide only when you already have one:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npx @milenyumai/film-kit generate-storyboard \
|
|
164
|
+
--character-ref ./refs/character.png \
|
|
165
|
+
--storyboard-ref ./refs/storyboard-guide.png \
|
|
166
|
+
--brief ./scenario.md \
|
|
167
|
+
--models seedance-2.0 \
|
|
168
|
+
--duration 8
|
|
169
|
+
```
|
|
170
|
+
|
|
138
171
|
Outputs:
|
|
139
172
|
|
|
140
173
|
- `outputs/storyboard-reference-plan.json`
|
|
174
|
+
- `outputs/reference-prep/CHARACTER-SHEET-*.md`
|
|
175
|
+
- `outputs/storyboard-prompts/SHOTNN-GPT-IMAGE-2-STORYBOARD.md`
|
|
141
176
|
- `outputs/prompt-bundles/SHOTNN.bundle.json`
|
|
142
177
|
- `outputs/shots/SHOTNN.md`
|
|
143
178
|
- `outputs/reports/STORYBOARD-REFERENCE-QA.md`
|
|
144
179
|
|
|
145
180
|
Rules:
|
|
146
181
|
|
|
147
|
-
- `@character1` is
|
|
148
|
-
-
|
|
149
|
-
-
|
|
182
|
+
- `@character1` is used once to create a 16:9 character sheet prompt with front, back, side, three-quarter, and face close-up views.
|
|
183
|
+
- Each `SHOTNN.md` includes a `GPT IMAGE 2 STORYBOARD PROMPT`; the generated shot storyboard controls composition, blocking, camera, timing, and editorial phase order only.
|
|
184
|
+
- 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.
|
|
185
|
+
- Phase budget: 4-6s uses 1-2 phases, 7-10s uses 2-3 phases, and 11-15s uses 3-4 phases.
|
|
186
|
+
- 5+ storyboard phases are split into multiple `SHOTNN.md` files by default.
|
|
187
|
+
- Multi-phase storyboards use planned phase transitions instead of forcing `No scene cuts throughout, one continuous shot.`
|
|
150
188
|
- Existing start/end workflows stay unchanged and remain the default.
|
|
151
189
|
|
|
190
|
+
CLI flags for direct storyboard bundle generation:
|
|
191
|
+
|
|
192
|
+
| Flag | Description |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `--character-ref` | Required character identity reference image path or URL. Repeatable or comma-separated |
|
|
195
|
+
| `--storyboard-ref` | Optional storyboard guide image path or URL. Repeatable or comma-separated |
|
|
196
|
+
| `--brief` | Inline brief text or a path to a brief/scenario file |
|
|
197
|
+
| `--models` | Comma-separated target models: `veo31`, `seedance-2.0`, `kling-3.0` |
|
|
198
|
+
| `--duration` | Duration in seconds per generated shot. Seedance provider range is 4-15 seconds |
|
|
199
|
+
| `--aspect` | `16:9`, `9:16`, or `1:1` |
|
|
200
|
+
| `--storyboard-panel-count-hint` | Optional total panel/phase hint. 5+ phases are split when overload splitting is enabled |
|
|
201
|
+
| `--max-storyboard-phases` | Upper bound per shot. Default: `4` |
|
|
202
|
+
|
|
152
203
|
## CLI
|
|
153
204
|
|
|
154
205
|
Base command:
|
package/build/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { configureFilmKit, detectFilmKitPreset, FILM_KIT_CONFIG_FILE, FILM_KIT_P
|
|
|
2
2
|
export { configureAgents } from "./lib/configure.js";
|
|
3
3
|
export { buildStoryboardReferencePromptBundles, normalizeVideoPromptRequest, renderShotMarkdown, writeStoryboardReferenceOutputs } from "./lib/storyboard-reference/index.js";
|
|
4
4
|
export type { AgentConfigOptions, ConfigureFilmKitResult, ConfigureResult, FilmKitConfigFile, FilmKitConfigOptions, FilmKitPreset, GptImageFormat, GptImageQuality, GptImageSize, HybridAspectRatio, KlingPreset, NanoBananaImageSize, ReferenceMode, StoryboardReferenceConfig, SupportedModel, SupportedPlatform } from "./lib/types.js";
|
|
5
|
-
export type { ModelPromptOutput, PromptBundle, ReferenceAsset, StoryboardReferenceBuildResult, StoryboardReferenceWriteResult, VideoPromptRequest } from "./lib/storyboard-reference/index.js";
|
|
5
|
+
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";
|
package/build/lib/cli.js
CHANGED
|
@@ -492,7 +492,7 @@ Usage:
|
|
|
492
492
|
npx @milenyumai/film-kit init --preset hybrid-smart --kling-preset balanced --gpt-image-size 2048x1152
|
|
493
493
|
npx @milenyumai/film-kit init --preset gpt-image-smart --gpt-image-size 2048x1152 --gpt-image-quality medium
|
|
494
494
|
npx @milenyumai/film-kit init --preset studio --refs-dir ./refs --fal-video-model fal-ai/kling-video/v3/pro/image-to-video
|
|
495
|
-
npx @milenyumai/film-kit generate-storyboard --character-ref ./refs/character.png --
|
|
495
|
+
npx @milenyumai/film-kit generate-storyboard --character-ref ./refs/character.png --brief ./scenario.md --models veo31,seedance-2.0,kling-3.0 --duration 8 --aspect 16:9
|
|
496
496
|
npx @milenyumai/film-kit init --overwrite
|
|
497
497
|
|
|
498
498
|
Common flags:
|
|
@@ -513,7 +513,7 @@ Preset-specific flags:
|
|
|
513
513
|
|
|
514
514
|
generate-storyboard flags:
|
|
515
515
|
--character-ref Character identity reference image path or URL (repeatable or comma-separated)
|
|
516
|
-
--storyboard-ref
|
|
516
|
+
--storyboard-ref Optional storyboard guide image path or URL (repeatable or comma-separated)
|
|
517
517
|
--brief Inline brief text or a path to a brief file
|
|
518
518
|
--models Comma-separated models: veo31,seedance-2.0,kling-3.0
|
|
519
519
|
--duration Duration in seconds per generated shot
|
package/build/lib/film-kit.js
CHANGED
|
@@ -372,10 +372,12 @@ export async function configureFilmKit(options = {}) {
|
|
|
372
372
|
merged.preset = preset;
|
|
373
373
|
const runtime = await loadPresetRuntime(preset);
|
|
374
374
|
const resolved = runtime.resolve(pickPresetOptions(preset, merged));
|
|
375
|
-
|
|
376
|
-
referenceMode
|
|
377
|
-
|
|
378
|
-
|
|
375
|
+
if (resolved.referenceMode === undefined && merged.referenceMode !== undefined) {
|
|
376
|
+
resolved.referenceMode = merged.referenceMode;
|
|
377
|
+
}
|
|
378
|
+
if (resolved.storyboardReferenceMode === undefined && merged.storyboardReferenceMode !== undefined) {
|
|
379
|
+
resolved.storyboardReferenceMode = merged.storyboardReferenceMode;
|
|
380
|
+
}
|
|
379
381
|
const configureOptions = pickPresetOptions(preset, resolved);
|
|
380
382
|
const result = await runtime.configure(configureOptions);
|
|
381
383
|
const configPath = join(rootDir, FILM_KIT_CONFIG_FILE);
|
|
@@ -22,7 +22,7 @@ export class Kling30PromptAdapter extends BaseVideoModelPromptAdapter {
|
|
|
22
22
|
const visualWorld = input.visualWorld;
|
|
23
23
|
const route = routeForPhaseCount(input.interpretation.phases.length);
|
|
24
24
|
const promptText = `[CHARACTER / SUBJECT CONSISTENCY]
|
|
25
|
-
Use the character reference as the exact identity and wardrobe anchor. Same face, hair, skin texture, body proportions, wardrobe, accessories, and visible props. The storyboard reference controls staging, camera rhythm, and phase order only. Do not inherit alternate character design from the storyboard.
|
|
25
|
+
Use the generated character sheet reference as the exact identity and wardrobe anchor. Same face, hair, skin texture, body proportions, wardrobe, accessories, and visible props. The generated shot storyboard reference (${input.storyboardImagePrompt.outputPath}) controls staging, camera rhythm, and phase order only. Do not inherit alternate character design from the storyboard.
|
|
26
26
|
|
|
27
27
|
[CORE INTENT]
|
|
28
28
|
${input.request.brief}
|
|
@@ -60,6 +60,8 @@ identity drift, face drift, outfit drift, storyboard text, panel borders, waterm
|
|
|
60
60
|
displayName: getDisplayName(this.model),
|
|
61
61
|
routeMetadata: {
|
|
62
62
|
route,
|
|
63
|
+
providerAssetMapping: input.providerAssetMapping,
|
|
64
|
+
phaseBudget: input.phaseBudget,
|
|
63
65
|
phaseCount: input.interpretation.phases.length,
|
|
64
66
|
maxCustomStoryboardPhases: this.maxStoryboardPhases
|
|
65
67
|
},
|
|
@@ -6,6 +6,10 @@ export declare class Seedance20PromptAdapter extends BaseVideoModelPromptAdapter
|
|
|
6
6
|
readonly supportsCharacterReference = true;
|
|
7
7
|
readonly supportsAudioPlan = true;
|
|
8
8
|
readonly maxStoryboardPhases = 4;
|
|
9
|
+
private buildProviderWarnings;
|
|
10
|
+
private getMappingEntries;
|
|
11
|
+
private formatCharacterRoleLine;
|
|
12
|
+
private formatStoryboardRoleLine;
|
|
9
13
|
buildPrompt(input: AdapterInput): ModelPromptOutput;
|
|
10
14
|
validate(output: ModelPromptOutput): ModelPromptQa;
|
|
11
15
|
}
|
|
@@ -5,12 +5,56 @@ export class Seedance20PromptAdapter extends BaseVideoModelPromptAdapter {
|
|
|
5
5
|
supportsCharacterReference = true;
|
|
6
6
|
supportsAudioPlan = true;
|
|
7
7
|
maxStoryboardPhases = 4;
|
|
8
|
+
buildProviderWarnings(fileLimits) {
|
|
9
|
+
const warnings = [];
|
|
10
|
+
if (fileLimits.observedImages > fileLimits.maxImages) {
|
|
11
|
+
warnings.push(`Seedance provider image reference limit exceeded: ${fileLimits.observedImages}/${fileLimits.maxImages}.`);
|
|
12
|
+
}
|
|
13
|
+
if (fileLimits.observedVideos > fileLimits.maxVideos) {
|
|
14
|
+
warnings.push(`Seedance provider video reference limit exceeded: ${fileLimits.observedVideos}/${fileLimits.maxVideos}.`);
|
|
15
|
+
}
|
|
16
|
+
if (fileLimits.observedAudio > fileLimits.maxAudio) {
|
|
17
|
+
warnings.push(`Seedance provider audio reference limit exceeded: ${fileLimits.observedAudio}/${fileLimits.maxAudio}.`);
|
|
18
|
+
}
|
|
19
|
+
if (fileLimits.observedTotalFiles > fileLimits.maxTotalFiles) {
|
|
20
|
+
warnings.push(`Seedance provider total reference file limit exceeded: ${fileLimits.observedTotalFiles}/${fileLimits.maxTotalFiles}.`);
|
|
21
|
+
}
|
|
22
|
+
return warnings;
|
|
23
|
+
}
|
|
24
|
+
getMappingEntries(input, role) {
|
|
25
|
+
return Object.values(input.providerAssetMapping).filter(entry => entry.role === role);
|
|
26
|
+
}
|
|
27
|
+
formatCharacterRoleLine(input) {
|
|
28
|
+
const characterEntries = this.getMappingEntries(input, "character_identity");
|
|
29
|
+
const tokens = characterEntries.map(entry => entry.token);
|
|
30
|
+
const tokenText = tokens.length === 1 ? tokens[0] : tokens.join(", ");
|
|
31
|
+
const aliasText = characterEntries
|
|
32
|
+
.map(entry => entry.legacyAlias)
|
|
33
|
+
.filter((alias) => Boolean(alias))
|
|
34
|
+
.join(", ");
|
|
35
|
+
return tokens.length === 1
|
|
36
|
+
? `Use ${tokenText} as the exact character identity reference. Preserve the same face, hair, body proportions, wardrobe, accessories, and visible props throughout.${aliasText ? ` Legacy alias: ${aliasText}.` : ""}`
|
|
37
|
+
: `Use ${tokenText} as exact character identity references. Preserve each matching face, hair, body proportion, wardrobe, accessory, and visible prop throughout; never merge or swap identities.${aliasText ? ` Legacy aliases: ${aliasText}.` : ""}`;
|
|
38
|
+
}
|
|
39
|
+
formatStoryboardRoleLine(input) {
|
|
40
|
+
const storyboardEntry = this.getMappingEntries(input, "storyboard_plan")[0];
|
|
41
|
+
const token = storyboardEntry?.token ?? "@Image2";
|
|
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}.` : ""}`;
|
|
44
|
+
}
|
|
8
45
|
buildPrompt(input) {
|
|
9
46
|
const audioPlan = buildAudioPlan(input);
|
|
10
|
-
const
|
|
11
|
-
|
|
47
|
+
const continuityInstruction = input.continuityMode === "continuous-shot"
|
|
48
|
+
? "No scene cuts throughout, one continuous shot."
|
|
49
|
+
: "Use only the planned storyboard phase transitions below; do not add unplanned cuts, extra scene jumps, or new locations.";
|
|
50
|
+
const characterEntries = this.getMappingEntries(input, "character_identity");
|
|
51
|
+
const storyboardEntry = this.getMappingEntries(input, "storyboard_plan")[0];
|
|
52
|
+
const characterTokenText = characterEntries.map(entry => entry.token).join(", ") || "@Image1";
|
|
53
|
+
const storyboardToken = storyboardEntry?.token ?? "@Image2";
|
|
54
|
+
const promptText = `${this.formatCharacterRoleLine(input)}
|
|
55
|
+
${this.formatStoryboardRoleLine(input)}
|
|
12
56
|
|
|
13
|
-
|
|
57
|
+
${continuityInstruction}
|
|
14
58
|
|
|
15
59
|
[CORE INTENT]
|
|
16
60
|
${input.request.brief}
|
|
@@ -18,6 +62,9 @@ ${input.request.brief}
|
|
|
18
62
|
[STORYBOARD PHASES]
|
|
19
63
|
${formatPhaseLines(input.interpretation.phases)}
|
|
20
64
|
|
|
65
|
+
[GPT IMAGE 2 STORYBOARD SOURCE]
|
|
66
|
+
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.
|
|
67
|
+
|
|
21
68
|
[CAMERA]
|
|
22
69
|
${input.interpretation.cameraPlan.framing}, ${input.interpretation.cameraPlan.movement}, ${input.interpretation.cameraPlan.lens}, ${input.interpretation.cameraPlan.stabilization}. Preserve ${input.interpretation.cameraPlan.screenDirection}.
|
|
23
70
|
|
|
@@ -31,23 +78,22 @@ Ambience: ${audioPlan.ambience.join(", ")}.
|
|
|
31
78
|
Music: NONE.
|
|
32
79
|
|
|
33
80
|
[CONTINUITY]
|
|
34
|
-
Identity reference stays locked to
|
|
81
|
+
Identity reference stays locked to ${characterTokenText}. Storyboard ${storyboardToken} controls staging and visual rhythm only. Character design, wardrobe, accessories, and visible props cannot be inherited from the storyboard. Storyboard text, panel borders, watermark, logo, and alternate character design are never identity sources.
|
|
35
82
|
|
|
36
83
|
Avoid: identity drift, face drift, outfit drift, storyboard text, panel borders, watermark, logo, distorted hands, rubbery motion, flicker, unnatural camera jumps.`;
|
|
37
84
|
const output = {
|
|
38
85
|
model: this.model,
|
|
39
86
|
displayName: getDisplayName(this.model),
|
|
40
87
|
routeMetadata: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
continuousShot: true,
|
|
88
|
+
continuityMode: input.continuityMode,
|
|
89
|
+
providerAssetMapping: input.providerAssetMapping,
|
|
90
|
+
phaseBudget: input.phaseBudget,
|
|
91
|
+
providerFileLimits: input.providerFileLimits,
|
|
46
92
|
phaseCount: input.interpretation.phases.length
|
|
47
93
|
},
|
|
48
94
|
promptText,
|
|
49
95
|
audioPlan,
|
|
50
|
-
warnings:
|
|
96
|
+
warnings: this.buildProviderWarnings(input.providerFileLimits),
|
|
51
97
|
qa: { verdict: "pass", checks: {}, issues: [] }
|
|
52
98
|
};
|
|
53
99
|
output.qa = this.validate(output);
|
|
@@ -55,11 +101,24 @@ Avoid: identity drift, face drift, outfit drift, storyboard text, panel borders,
|
|
|
55
101
|
}
|
|
56
102
|
validate(output) {
|
|
57
103
|
const base = super.validate(output);
|
|
104
|
+
const continuityMode = output.routeMetadata.continuityMode;
|
|
105
|
+
const mapping = output.routeMetadata.providerAssetMapping ?? {};
|
|
106
|
+
const mappingEntries = Object.values(mapping);
|
|
107
|
+
const characterTokens = mappingEntries
|
|
108
|
+
.filter(entry => entry.role === "character_identity")
|
|
109
|
+
.map(entry => entry.token);
|
|
110
|
+
const storyboardToken = mappingEntries.find(entry => entry.role === "storyboard_plan")?.token ?? "@Image2";
|
|
111
|
+
const hasNoCutsRule = /No scene cuts throughout, one continuous shot/i.test(output.promptText);
|
|
58
112
|
const checks = {
|
|
59
113
|
...base.checks,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
114
|
+
usesCharacterIdentityTokens: characterTokens.length > 0
|
|
115
|
+
&& characterTokens.every(token => output.promptText.includes(token))
|
|
116
|
+
&& /exact character identity reference/i.test(output.promptText),
|
|
117
|
+
usesStoryboardToken: output.promptText.includes(storyboardToken) && /shot storyboard reference/i.test(output.promptText),
|
|
118
|
+
blocksStoryboardIdentitySources: /Storyboard text, panel borders, watermark, logo, and alternate character design are never identity sources/i.test(output.promptText),
|
|
119
|
+
continuityMode: continuityMode === "continuous-shot"
|
|
120
|
+
? hasNoCutsRule
|
|
121
|
+
: !hasNoCutsRule && /planned storyboard phase transitions/i.test(output.promptText),
|
|
63
122
|
musicNone: /Music: NONE/i.test(output.promptText)
|
|
64
123
|
};
|
|
65
124
|
const issues = [
|
|
@@ -17,7 +17,7 @@ export class Veo31PromptAdapter extends BaseVideoModelPromptAdapter {
|
|
|
17
17
|
const audioPlan = buildAudioPlan(input);
|
|
18
18
|
const camera = input.interpretation.cameraPlan;
|
|
19
19
|
const visualWorld = input.visualWorld;
|
|
20
|
-
const promptText = `Use the
|
|
20
|
+
const promptText = `Use the generated character sheet reference as the exact identity anchor throughout the shot. Preserve the same face, hair, body proportions, wardrobe, accessories, and visible props. Use the generated shot storyboard image from ${input.storyboardImagePrompt.outputPath} as a visual planning reference for composition, blocking, camera angle, pacing, and intended action progression only. Do not copy storyboard text, labels, panel borders, watermarks, logos, or any alternate character design from the storyboard.
|
|
21
21
|
|
|
22
22
|
Cinematic ${camera.shotType} of the referenced character in ${visualWorld.environment}. ${input.request.brief} The scene follows the storyboard's ${input.interpretation.phases.length} visual beats: ${summarizeBeats(input)}. Performance remains grounded in visible micro-behavior, with controlled eye-line changes, breath, posture, and hand tension. The character reference always wins over the storyboard if identity, wardrobe, proportions, accessories, or prop design conflict.
|
|
23
23
|
|
|
@@ -39,6 +39,8 @@ Avoid: identity drift, face drift, outfit drift, storyboard panel borders, on-sc
|
|
|
39
39
|
displayName: getDisplayName(this.model),
|
|
40
40
|
routeMetadata: {
|
|
41
41
|
storyboardRole: "visual planning reference",
|
|
42
|
+
providerAssetMapping: input.providerAssetMapping,
|
|
43
|
+
phaseBudget: input.phaseBudget,
|
|
42
44
|
phaseCount: input.interpretation.phases.length,
|
|
43
45
|
minWordTarget: 120
|
|
44
46
|
},
|
|
@@ -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, validateModelPromptOutput, validatePromptBundle, validateResolvedAssetRoles } from "./validators.js";
|
|
7
|
-
export type { AdapterInput, AudioPlan, CameraPlan, ContinuityAnchors, DialogueLine, ModelPromptOutput, ModelPromptQa, NormalizedVideoPromptRequest, PromptBundle, PromptBundleQa, ReferenceAsset, ReferenceAssetRole, ReferenceLockStrength, ResolvedAssetRoles, StoryboardInterpretation, StoryboardPhase, StoryboardReferenceBuildResult, StoryboardReferencePlan, 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, StoryboardImagePrompt, StoryboardInterpretation, StoryboardPhase, StoryboardPhaseBudget, StoryboardReferenceBuildResult, StoryboardReferencePlan, StoryboardReferencePolicy, StoryboardReferenceWriteResult, VideoModelPromptAdapter, VideoPromptRequest, VisualWorld, VoiceCastEntry } from "./types.js";
|
|
@@ -23,6 +23,23 @@ function formatQa(bundle) {
|
|
|
23
23
|
}
|
|
24
24
|
return lines.join("\n");
|
|
25
25
|
}
|
|
26
|
+
function formatReferenceRequirements(bundle) {
|
|
27
|
+
return bundle.referenceAssetRequirements
|
|
28
|
+
.map(requirement => {
|
|
29
|
+
const alias = requirement.legacyAlias ? ` / ${requirement.legacyAlias}` : "";
|
|
30
|
+
const path = requirement.generatedPromptPath ? ` Prompt: ${requirement.generatedPromptPath}.` : "";
|
|
31
|
+
return `- ${requirement.token}${alias}: ${requirement.source}, ${requirement.role}, ${requirement.required ? "required" : "optional"}. ${requirement.notes}${path}`;
|
|
32
|
+
})
|
|
33
|
+
.join("\n");
|
|
34
|
+
}
|
|
35
|
+
function formatProviderTokens(bundle) {
|
|
36
|
+
return Object.values(bundle.providerAssetMapping)
|
|
37
|
+
.map(entry => {
|
|
38
|
+
const alias = entry.legacyAlias ? ` / ${entry.legacyAlias}` : "";
|
|
39
|
+
return `- ${entry.token}${alias}: ${entry.description}`;
|
|
40
|
+
})
|
|
41
|
+
.join("\n");
|
|
42
|
+
}
|
|
26
43
|
export function renderShotMarkdown(bundle) {
|
|
27
44
|
const interpretation = bundle.storyboardInterpretation;
|
|
28
45
|
const audioPlan = getAudioPlan(bundle);
|
|
@@ -33,24 +50,44 @@ export function renderShotMarkdown(bundle) {
|
|
|
33
50
|
return `# ${bundle.shotId} | ${bundle.durationSeconds}s | Mode: storyboard-reference
|
|
34
51
|
|
|
35
52
|
## Türkçe Özet
|
|
36
|
-
|
|
53
|
+
Önce tek seferlik karakter sheet referansları üretilir. Bu shot için ayrıca GPT Image 2 ile profesyonel storyboard görsel promptu üretilir; Seedance tarafında karakter sheet tokenları kimliği, shot storyboard tokenı ise kompozisyon, bloklama, kamera ve zamanlamayı yönetir.
|
|
37
54
|
|
|
38
55
|
## Model Control
|
|
39
56
|
- Reference Mode: storyboard-reference
|
|
40
57
|
- Target Models: ${Object.keys(bundle.modelPrompts).join(", ")}
|
|
41
58
|
- Aspect Ratio: ${bundle.aspectRatio}
|
|
42
59
|
- Duration: ${bundle.durationSeconds}s
|
|
60
|
+
- Continuity Mode: ${bundle.continuityMode}
|
|
61
|
+
- Phase Budget: ${bundle.phaseBudget.policy}; effective max ${bundle.phaseBudget.effectiveMaxStoryboardPhases}
|
|
43
62
|
- Safety Mode: fail-closed
|
|
44
63
|
|
|
45
64
|
## Input Asset Roles
|
|
46
65
|
${Object.values(bundle.assetRoles).map(role => `- ${role.token}: ${role.role}, ${role.lockStrength} lock`).join("\n")}
|
|
47
66
|
|
|
67
|
+
## Reference Asset Requirements
|
|
68
|
+
${formatReferenceRequirements(bundle)}
|
|
69
|
+
|
|
70
|
+
## Provider Reference Tokens
|
|
71
|
+
${formatProviderTokens(bundle)}
|
|
72
|
+
|
|
73
|
+
## GPT Image 2 Storyboard Prompt
|
|
74
|
+
- Output: ${bundle.storyboardImagePrompt.outputPath}
|
|
75
|
+
- Panel count: ${bundle.storyboardImagePrompt.panelCount}
|
|
76
|
+
- Previous handoff: ${bundle.storyboardImagePrompt.previousShotHandoff}
|
|
77
|
+
- Next handoff: ${bundle.storyboardImagePrompt.nextShotHandoff}
|
|
78
|
+
|
|
79
|
+
\`\`\`text
|
|
80
|
+
${bundle.storyboardImagePrompt.promptText}
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
48
83
|
## Storyboard Interpretation
|
|
49
84
|
- Editorial function: ${interpretation.editorialFunction}
|
|
50
85
|
- Panel/phase count: ${interpretation.panelCount}
|
|
51
86
|
- Camera plan: ${interpretation.cameraPlan.framing}, ${interpretation.cameraPlan.movement}, ${interpretation.cameraPlan.lens}
|
|
52
87
|
- Screen direction: ${interpretation.cameraPlan.screenDirection}
|
|
53
88
|
- Light source: ${interpretation.visualWorld.lighting}
|
|
89
|
+
- Entry handoff: ${bundle.handoffNote.entryHandoff}
|
|
90
|
+
- Exit handoff: ${bundle.handoffNote.exitHandoff}
|
|
54
91
|
- Continuity anchors: ${[
|
|
55
92
|
...interpretation.continuityAnchors.identity,
|
|
56
93
|
...interpretation.continuityAnchors.wardrobe,
|
|
@@ -70,6 +107,34 @@ ${modelPrompts}
|
|
|
70
107
|
${formatQa(bundle)}
|
|
71
108
|
`;
|
|
72
109
|
}
|
|
110
|
+
function renderCharacterSheetPrompt(prompt) {
|
|
111
|
+
return `# ${prompt.id}
|
|
112
|
+
|
|
113
|
+
- Provider: ${prompt.provider}
|
|
114
|
+
- Aspect Ratio: ${prompt.aspectRatio}
|
|
115
|
+
- Source: ${prompt.sourceToken}
|
|
116
|
+
- Generated Once: ${prompt.generatedOnce ? "YES" : "NO"}
|
|
117
|
+
- Cell Count: ${prompt.cellCount}
|
|
118
|
+
|
|
119
|
+
\`\`\`text
|
|
120
|
+
${prompt.promptText}
|
|
121
|
+
\`\`\`
|
|
122
|
+
`;
|
|
123
|
+
}
|
|
124
|
+
function renderStoryboardPromptFile(bundle) {
|
|
125
|
+
return `# ${bundle.shotId} GPT Image 2 Storyboard Prompt
|
|
126
|
+
|
|
127
|
+
- Provider: ${bundle.storyboardImagePrompt.provider}
|
|
128
|
+
- Aspect Ratio: ${bundle.storyboardImagePrompt.aspectRatio}
|
|
129
|
+
- Panel Count: ${bundle.storyboardImagePrompt.panelCount}
|
|
130
|
+
- Character Sheets: ${bundle.storyboardImagePrompt.characterSheetIds.join(", ")}
|
|
131
|
+
- External Storyboard Guides: ${bundle.storyboardImagePrompt.externalStoryboardGuideIds.join(", ") || "none"}
|
|
132
|
+
|
|
133
|
+
\`\`\`text
|
|
134
|
+
${bundle.storyboardImagePrompt.promptText}
|
|
135
|
+
\`\`\`
|
|
136
|
+
`;
|
|
137
|
+
}
|
|
73
138
|
function renderQaReport(result) {
|
|
74
139
|
const models = result.request.targetModels.join(", ");
|
|
75
140
|
const rows = result.bundles
|
|
@@ -82,7 +147,7 @@ function renderQaReport(result) {
|
|
|
82
147
|
.map(row => `| ${row.shotId} | ${row.model} | ${row.verdict.toUpperCase()} | ${row.notes} |`)
|
|
83
148
|
.join("\n");
|
|
84
149
|
const assetRows = result.bundles
|
|
85
|
-
.map(bundle => `| ${bundle.shotId} | ${result.
|
|
150
|
+
.map(bundle => `| ${bundle.shotId} | ${result.characterReferenceSheetPrompts.length} | ${result.assets.storyboards.length} | ${bundle.storyboardImagePrompt ? "YES" : "NO"} | ${bundle.qa.verdict.toUpperCase()} |`)
|
|
86
151
|
.join("\n");
|
|
87
152
|
const issues = result.bundles.flatMap(bundle => bundle.qa.issues);
|
|
88
153
|
return `# Storyboard Reference QA Report
|
|
@@ -90,12 +155,16 @@ function renderQaReport(result) {
|
|
|
90
155
|
## Summary
|
|
91
156
|
- Verdict: ${issues.length === 0 ? "PASS" : "FAIL"}
|
|
92
157
|
- Shots checked: ${result.bundles.length}
|
|
158
|
+
- Character sheet prompts: ${result.characterReferenceSheetPrompts.length}
|
|
159
|
+
- Shot storyboard prompts: ${result.bundles.length}
|
|
93
160
|
- Models checked: ${models}
|
|
94
161
|
- Split required: ${result.plan.splitRequired ? "YES" : "NO"}
|
|
162
|
+
- Phase budget: ${result.plan.policy.storyboard_reference.recommended_phase_budget.policy}
|
|
163
|
+
- Provider files within limits: ${result.plan.policy.storyboard_reference.provider_file_limits.withinLimits ? "YES" : "NO"}
|
|
95
164
|
|
|
96
165
|
## Asset Role Checks
|
|
97
|
-
| Shot | Character
|
|
98
|
-
|
|
166
|
+
| Shot | Character Sheets | External Storyboard Guides | Generated Storyboard | Verdict |
|
|
167
|
+
|---|---:|---:|---:|---|
|
|
99
168
|
${assetRows}
|
|
100
169
|
|
|
101
170
|
## Model Grammar Checks
|
|
@@ -122,17 +191,26 @@ export async function writeStoryboardReferenceOutputs(result, rootDir = process.
|
|
|
122
191
|
|
|
123
192
|
- Mode: storyboard-reference
|
|
124
193
|
- Character references: ${result.assets.characters.length}
|
|
125
|
-
-
|
|
194
|
+
- Character sheet prompts: ${result.characterReferenceSheetPrompts.length}
|
|
195
|
+
- External storyboard guides: ${result.assets.storyboards.length}
|
|
196
|
+
- Generated shot storyboard prompts: ${result.bundles.length}
|
|
126
197
|
- Target models: ${result.request.targetModels.join(", ")}
|
|
127
198
|
- Safety context: ${result.request.safetyContext}
|
|
128
199
|
`);
|
|
129
200
|
written.push(projectInfoPath);
|
|
201
|
+
for (const prompt of result.characterReferenceSheetPrompts) {
|
|
202
|
+
const promptPath = resolve(rootDir, prompt.outputPath);
|
|
203
|
+
await writeText(promptPath, renderCharacterSheetPrompt(prompt));
|
|
204
|
+
written.push(promptPath);
|
|
205
|
+
}
|
|
130
206
|
for (const bundle of result.bundles) {
|
|
131
207
|
const shotPath = join(outputRoot, "shots", `${bundle.shotId}.md`);
|
|
132
208
|
const bundlePath = join(outputRoot, "prompt-bundles", `${bundle.shotId}.bundle.json`);
|
|
209
|
+
const storyboardPromptPath = resolve(rootDir, bundle.storyboardImagePrompt.outputPath);
|
|
210
|
+
await writeText(storyboardPromptPath, renderStoryboardPromptFile(bundle));
|
|
133
211
|
await writeText(shotPath, renderShotMarkdown(bundle));
|
|
134
212
|
await writeText(bundlePath, `${JSON.stringify(bundle, null, 2)}\n`);
|
|
135
|
-
written.push(shotPath, bundlePath);
|
|
213
|
+
written.push(storyboardPromptPath, shotPath, bundlePath);
|
|
136
214
|
}
|
|
137
215
|
await writeText(qaPath, renderQaReport(result));
|
|
138
216
|
written.push(qaPath);
|