@milenyumai/film-kit 2.3.2 → 2.3.3
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
CHANGED
|
@@ -558,10 +558,7 @@ These subpackages are marked `private: true` and are bundled as internal sources
|
|
|
558
558
|
Maintainer release checklist:
|
|
559
559
|
|
|
560
560
|
```bash
|
|
561
|
-
npm run
|
|
562
|
-
npm test
|
|
563
|
-
npm run build
|
|
564
|
-
npm pack --json --dry-run
|
|
561
|
+
npm run release:check
|
|
565
562
|
```
|
|
566
563
|
|
|
567
564
|
Publish the single public package:
|
|
@@ -572,6 +569,12 @@ npm whoami
|
|
|
572
569
|
npm publish --access public
|
|
573
570
|
```
|
|
574
571
|
|
|
572
|
+
If the account has npm two-factor authentication enabled for publish, include the current one-time password from the authenticator app:
|
|
573
|
+
|
|
574
|
+
```bash
|
|
575
|
+
npm publish --access public --otp=123456
|
|
576
|
+
```
|
|
577
|
+
|
|
575
578
|
Optional validation before publish:
|
|
576
579
|
|
|
577
580
|
```bash
|
package/build/lib/cli.js
CHANGED
|
@@ -41,6 +41,37 @@ function formatProviderTokens(bundle) {
|
|
|
41
41
|
})
|
|
42
42
|
.join("\n");
|
|
43
43
|
}
|
|
44
|
+
function getProviderToken(bundle, role, fallback) {
|
|
45
|
+
return Object.values(bundle.providerAssetMapping)
|
|
46
|
+
.find(entry => entry.role === role)?.token ?? fallback;
|
|
47
|
+
}
|
|
48
|
+
function formatCoverageReferences(bundle) {
|
|
49
|
+
const interpretation = bundle.storyboardInterpretation;
|
|
50
|
+
const characterTokens = Object.values(bundle.providerAssetMapping)
|
|
51
|
+
.filter(entry => entry.role === "character_identity")
|
|
52
|
+
.map(entry => entry.token)
|
|
53
|
+
.join(", ") || "@Image1";
|
|
54
|
+
const storyboardToken = getProviderToken(bundle, "storyboard_plan", "@Image2");
|
|
55
|
+
const visualWorld = interpretation.visualWorld;
|
|
56
|
+
const camera = interpretation.cameraPlan;
|
|
57
|
+
const firstPhase = interpretation.phases[0];
|
|
58
|
+
const lastPhase = interpretation.phases.at(-1) ?? firstPhase;
|
|
59
|
+
return `## Coverage References In Same File
|
|
60
|
+
|
|
61
|
+
Coverage is standalone editorial material for this shot only. Do not chain coverage into the next main shot. Keep the same generated character identity, wardrobe, props, lighting direction, environment, screen direction, and visual_world.
|
|
62
|
+
|
|
63
|
+
### ${bundle.shotId}A - ECU Reaction | 3s
|
|
64
|
+
|
|
65
|
+
\`\`\`text
|
|
66
|
+
Use ${characterTokens} as the exact identity source and ${storyboardToken} only for scene continuity. Extreme close-up reaction coverage during ${firstPhase?.timeRange ?? "the opening beat"}: ${firstPhase?.subjectAction ?? "the character registers the story beat"}. Keep ${visualWorld.lighting}, ${visualWorld.atmosphere}, and ${camera.screenDirection}. Static or barely drifting camera, shallow depth of field, natural skin texture, visible breath or eye tension, no new action beat, no new identity. Audio: close breath, subtle clothing sound, matched ambience, Music: NONE. Avoid: identity drift, face drift, wardrobe drift, beauty filter, plastic skin, distorted eyes, flicker, warping, on-screen text, watermark, logo.
|
|
67
|
+
\`\`\`
|
|
68
|
+
|
|
69
|
+
### ${bundle.shotId}B - Insert / Environmental Detail | 3s
|
|
70
|
+
|
|
71
|
+
\`\`\`text
|
|
72
|
+
Use ${storyboardToken} only for composition and environment continuity; do not introduce a new character identity. Tight insert coverage tied to ${lastPhase?.timeRange ?? "the final beat"}: ${lastPhase?.subjectAction ?? "the action resolves into a clear visual detail"}. Show a physically plausible detail from the same visual world: foreground texture, prop contact, reflection, light spill, hand tension, fabric motion, or environment response. Keep ${visualWorld.environment}; ${visualWorld.foreground}; ${visualWorld.background}; ${visualWorld.lighting}. Audio: matched practical SFX and ambience, no dialogue unless explicitly present in the main Audio Plan, Music: NONE. Avoid: new location, new character, clear logo, readable text, impossible physics, wrong reflection angle, identity override, flicker, warping, cartoon style, CGI look.
|
|
73
|
+
\`\`\``;
|
|
74
|
+
}
|
|
44
75
|
export function renderShotMarkdown(bundle) {
|
|
45
76
|
const interpretation = bundle.storyboardInterpretation;
|
|
46
77
|
const audioPlan = getAudioPlan(bundle);
|
|
@@ -104,6 +135,8 @@ ${JSON.stringify(audioPlan ?? null, null, 2)}
|
|
|
104
135
|
|
|
105
136
|
${modelPrompts}
|
|
106
137
|
|
|
138
|
+
${formatCoverageReferences(bundle)}
|
|
139
|
+
|
|
107
140
|
## QA
|
|
108
141
|
${formatQa(bundle)}
|
|
109
142
|
`;
|
|
@@ -99,8 +99,12 @@ export function validateModelPromptOutput(output) {
|
|
|
99
99
|
}
|
|
100
100
|
export function validatePromptBundle(bundle, assets, voiceCast = []) {
|
|
101
101
|
const roleIssues = validateResolvedAssetRoles(assets);
|
|
102
|
+
const modelValidationResults = Object.values(bundle.modelPrompts)
|
|
103
|
+
.filter((output) => Boolean(output))
|
|
104
|
+
.map(validateModelPromptOutput);
|
|
102
105
|
const modelIssues = Object.values(bundle.modelPrompts)
|
|
103
|
-
.flatMap(output => output?.qa.issues ?? [])
|
|
106
|
+
.flatMap(output => output?.qa.issues ?? [])
|
|
107
|
+
.concat(modelValidationResults.flatMap(result => result.issues));
|
|
104
108
|
const voiceCastKeys = new Set(voiceCast.map(entry => entry.speakerKey));
|
|
105
109
|
const audioPlans = Object.values(bundle.modelPrompts)
|
|
106
110
|
.map(output => output?.audioPlan)
|
|
@@ -110,9 +114,10 @@ export function validatePromptBundle(bundle, assets, voiceCast = []) {
|
|
|
110
114
|
hasStoryboardReference: assets.storyboards.length >= 1 || Boolean(bundle.storyboardImagePrompt),
|
|
111
115
|
hasStoryboardImagePrompt: Boolean(bundle.storyboardImagePrompt?.promptText.trim()),
|
|
112
116
|
storyboardPromptHasReferenceLockStructure: hasGptImageStillPromptContract(bundle.storyboardImagePrompt?.promptText ?? ""),
|
|
113
|
-
hasAvoidLineEverywhere: Object.values(bundle.modelPrompts).every(output => Boolean(output
|
|
117
|
+
hasAvoidLineEverywhere: Object.values(bundle.modelPrompts).every(output => Boolean(output) && hasAvoidOrNegativePrompt(output.promptText)),
|
|
114
118
|
storyboardPromptHasAvoidLine: hasAvoidOrNegativePrompt(bundle.storyboardImagePrompt?.promptText ?? ""),
|
|
115
|
-
modelGrammarPasses: Object.values(bundle.modelPrompts).every(output => output?.qa.verdict === "pass")
|
|
119
|
+
modelGrammarPasses: Object.values(bundle.modelPrompts).every(output => output?.qa.verdict === "pass")
|
|
120
|
+
&& modelValidationResults.every(result => result.verdict === "pass"),
|
|
116
121
|
storyboardDoesNotOverrideIdentity: Object.values(bundle.modelPrompts).every(output => /storyboard.*staging|storyboard.*planning|storyboard.*composition|storyboard.*only/i.test(output?.promptText ?? "")),
|
|
117
122
|
audioPlanPresent: Object.values(bundle.modelPrompts).every(output => Boolean(output?.audioPlan)),
|
|
118
123
|
speakingAudioPlansHaveActiveSpeaker: audioPlans.every(plan => plan.dialogueTranscript === "NONE" || Boolean(plan.activeSpeakerKey)),
|
|
@@ -131,10 +136,20 @@ export function validatePromptBundle(bundle, assets, voiceCast = []) {
|
|
|
131
136
|
};
|
|
132
137
|
}
|
|
133
138
|
export function assertStoryboardReferenceBuildPass(result) {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
const issues = validateCharacterReferenceSheetPrompts(result.characterReferenceSheetPrompts)
|
|
140
|
+
.map(issue => `character-sheet: ${issue}`);
|
|
141
|
+
for (const bundle of result.bundles) {
|
|
142
|
+
const currentQa = validatePromptBundle(bundle, result.assets, result.plan.voiceCast);
|
|
143
|
+
if (bundle.qa.verdict !== "pass" || currentQa.verdict !== "pass") {
|
|
144
|
+
const bundleIssues = [
|
|
145
|
+
...bundle.qa.issues,
|
|
146
|
+
...currentQa.issues
|
|
147
|
+
];
|
|
148
|
+
issues.push(...(bundleIssues.length > 0
|
|
149
|
+
? bundleIssues.map(issue => `${bundle.shotId}: ${issue}`)
|
|
150
|
+
: [`${bundle.shotId}: bundle QA failed without a detailed issue.`]));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
138
153
|
if (result.bundles.length === 0) {
|
|
139
154
|
issues.push("No storyboard-reference prompt bundles were generated.");
|
|
140
155
|
}
|
|
@@ -11,7 +11,7 @@ export function buildCameraPlan(request) {
|
|
|
11
11
|
lens: wideShot ? "35mm lens feel" : closeShot ? "85mm lens feel" : "50mm lens feel",
|
|
12
12
|
framing: wideShot ? "layered wide composition" : closeShot ? "eye-level close framing" : "stable mid-shot framing",
|
|
13
13
|
stabilization: "tripod-stable with minimal organic drift",
|
|
14
|
-
screenDirection: "
|
|
14
|
+
screenDirection: "storyboard screen direction and eyeline relationships"
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
export function buildVisualWorld(request) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milenyumai/film-kit",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
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",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"build:presets": "npm --prefix packages/multi run build && npm --prefix packages/hybrid run build && npm --prefix packages/hybrid-smart run build && npm --prefix packages/gpt-image-smart run build && npm --prefix packages/studio run build",
|
|
45
45
|
"dev:setup": "tsx src/postinstall.ts",
|
|
46
46
|
"postinstall": "node -e \"import('./build/postinstall.js').then(m=>m.runPostinstall()).catch(()=>{})\"",
|
|
47
|
+
"release:check": "npm run typecheck && npm test && npm run build && npm publish --access public --dry-run",
|
|
47
48
|
"test": "vitest run",
|
|
48
49
|
"test:watch": "vitest",
|
|
49
50
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|