@clipwright/core 0.19.0 → 0.21.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/CHANGELOG.md +55 -0
- package/dist/__fixtures__/queue-promises.d.ts +5 -84
- package/dist/__fixtures__/queue-promises.js +7 -84
- package/dist/__fixtures__/queue-promises.js.map +1 -1
- package/dist/account-actors.d.ts +25 -25
- package/dist/account-actors.js +25 -25
- package/dist/account-actors.js.map +1 -1
- package/dist/account.d.ts +4 -10
- package/dist/account.js +6 -12
- package/dist/account.js.map +1 -1
- package/dist/actor-bounds.d.ts +4 -4
- package/dist/actor-bounds.js +4 -4
- package/dist/actor-bounds.js.map +1 -1
- package/dist/actor-qualities.d.ts +3 -3
- package/dist/actor-qualities.js +3 -3
- package/dist/actor-qualities.js.map +1 -1
- package/dist/actors.d.ts +8 -8
- package/dist/actors.js +9 -9
- package/dist/actors.js.map +1 -1
- package/dist/api-failure.d.ts +28 -129
- package/dist/api-failure.js +52 -225
- package/dist/api-failure.js.map +1 -1
- package/dist/aspect.d.ts +26 -96
- package/dist/aspect.js +32 -108
- package/dist/aspect.js.map +1 -1
- package/dist/contract-dispositions.d.ts +42 -167
- package/dist/contract-dispositions.js +54 -184
- package/dist/contract-dispositions.js.map +1 -1
- package/dist/endpoints.d.ts +5 -5
- package/dist/endpoints.js +5 -3
- package/dist/endpoints.js.map +1 -1
- package/dist/errors.d.ts +33 -101
- package/dist/errors.js +42 -108
- package/dist/errors.js.map +1 -1
- package/dist/faceless-cut-style.d.ts +115 -0
- package/dist/faceless-cut-style.js +109 -0
- package/dist/faceless-cut-style.js.map +1 -0
- package/dist/faceless-image-qualification.d.ts +97 -0
- package/dist/faceless-image-qualification.js +145 -0
- package/dist/faceless-image-qualification.js.map +1 -0
- package/dist/faceless-price.d.ts +21 -0
- package/dist/faceless-price.js +25 -0
- package/dist/faceless-price.js.map +1 -0
- package/dist/faceless-public-plan.d.ts +71 -0
- package/dist/faceless-public-plan.js +166 -0
- package/dist/faceless-public-plan.js.map +1 -0
- package/dist/faceless-public.d.ts +107 -0
- package/dist/faceless-public.js +74 -0
- package/dist/faceless-public.js.map +1 -0
- package/dist/faceless-short-61.d.ts +83 -0
- package/dist/faceless-short-61.js +152 -0
- package/dist/faceless-short-61.js.map +1 -0
- package/dist/faceless-storyboard-timing.d.ts +40 -0
- package/dist/faceless-storyboard-timing.js +97 -0
- package/dist/faceless-storyboard-timing.js.map +1 -0
- package/dist/faceless-storyboard-v2-plan.d.ts +3 -0
- package/dist/faceless-storyboard-v2-plan.js +112 -0
- package/dist/faceless-storyboard-v2-plan.js.map +1 -0
- package/dist/faceless-storyboard-v2-timing.d.ts +63 -0
- package/dist/faceless-storyboard-v2-timing.js +143 -0
- package/dist/faceless-storyboard-v2-timing.js.map +1 -0
- package/dist/faceless-storyboard-v2.d.ts +44 -0
- package/dist/faceless-storyboard-v2.js +43 -0
- package/dist/faceless-storyboard-v2.js.map +1 -0
- package/dist/faceless-storyboard.d.ts +55 -0
- package/dist/faceless-storyboard.js +105 -0
- package/dist/faceless-storyboard.js.map +1 -0
- package/dist/idempotency.d.ts +10 -44
- package/dist/idempotency.js +18 -44
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +24 -25
- package/dist/index.js.map +1 -1
- package/dist/long-form-pricing.d.ts +4 -4
- package/dist/long-form-pricing.js +4 -4
- package/dist/long-form-pricing.js.map +1 -1
- package/dist/long-form-profile.d.ts +2 -2
- package/dist/long-form-profile.js +2 -2
- package/dist/long-form-profile.js.map +1 -1
- package/dist/pacing.d.ts +1 -1
- package/dist/pacing.js +1 -1
- package/dist/pacing.js.map +1 -1
- package/dist/public-endpoints.d.ts +9 -11
- package/dist/public-endpoints.js +11 -13
- package/dist/public-endpoints.js.map +1 -1
- package/dist/rate-limit.d.ts +23 -130
- package/dist/rate-limit.js +27 -132
- package/dist/rate-limit.js.map +1 -1
- package/dist/render-backend.d.ts +30 -145
- package/dist/render-backend.js +4 -27
- package/dist/render-backend.js.map +1 -1
- package/dist/run-preflight.d.ts +4 -4
- package/dist/run-preflight.js +10 -10
- package/dist/run-preflight.js.map +1 -1
- package/dist/run-static-warnings.d.ts +8 -8
- package/dist/run-static-warnings.js +26 -24
- package/dist/run-static-warnings.js.map +1 -1
- package/dist/runs.d.ts +34 -55
- package/dist/runs.js +28 -94
- package/dist/runs.js.map +1 -1
- package/dist/script-integrity.d.ts +6 -7
- package/dist/script-integrity.js +7 -8
- package/dist/script-integrity.js.map +1 -1
- package/dist/semantic-inserts.d.ts +4 -4
- package/dist/semantic-inserts.js +6 -6
- package/dist/semantic-inserts.js.map +1 -1
- package/dist/skills.d.ts +37 -108
- package/dist/skills.js +77 -161
- package/dist/skills.js.map +1 -1
- package/dist/tts-backend.d.ts +13 -42
- package/dist/tts-backend.js +2 -10
- package/dist/tts-backend.js.map +1 -1
- package/dist/uploads.d.ts +4 -4
- package/dist/uploads.js +4 -4
- package/dist/uploads.js.map +1 -1
- package/dist/vendor-response.d.ts +17 -80
- package/dist/vendor-response.js +19 -67
- package/dist/vendor-response.js.map +1 -1
- package/dist/voice-admission.d.ts +5 -5
- package/dist/voice-admission.js +6 -6
- package/dist/voice-admission.js.map +1 -1
- package/dist/voice-catalog-data.d.ts +2 -2
- package/dist/voice-catalog-data.js +2 -2
- package/dist/voice-catalog-data.js.map +1 -1
- package/dist/voice-catalog.d.ts +5 -5
- package/dist/voice-catalog.generated.json +56 -54
- package/dist/voice-catalog.js +6 -6
- package/dist/voice-catalog.js.map +1 -1
- package/dist/voice-listing.d.ts +4 -4
- package/dist/voice-listing.js +6 -6
- package/dist/voice-listing.js.map +1 -1
- package/dist/voices.d.ts +40 -82
- package/dist/voices.js +56 -99
- package/dist/voices.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type StoryboardProposal } from "./faceless-storyboard.js";
|
|
2
|
+
type WordTiming = {
|
|
3
|
+
word: string;
|
|
4
|
+
startSec: number;
|
|
5
|
+
endSec: number;
|
|
6
|
+
};
|
|
7
|
+
type PhraseRange = {
|
|
8
|
+
wordStart: number;
|
|
9
|
+
wordEnd: number;
|
|
10
|
+
accentWord: number;
|
|
11
|
+
};
|
|
12
|
+
type Cut = {
|
|
13
|
+
afterWord: number;
|
|
14
|
+
frame: number;
|
|
15
|
+
reason: string;
|
|
16
|
+
};
|
|
17
|
+
export type StoryboardFramePlan = {
|
|
18
|
+
version: "faceless_storyboard_61_v1";
|
|
19
|
+
outputFrames: 1522;
|
|
20
|
+
script: string;
|
|
21
|
+
captionPhrases: PhraseRange[];
|
|
22
|
+
narrationStartFrame: number;
|
|
23
|
+
shots: Array<{
|
|
24
|
+
id: string;
|
|
25
|
+
mediaType: "video" | "image";
|
|
26
|
+
startFrame: number;
|
|
27
|
+
endFrame: number;
|
|
28
|
+
motion?: "PAN_UP" | "PAN_DOWN";
|
|
29
|
+
beatIds: string[];
|
|
30
|
+
cutAfterWord?: number;
|
|
31
|
+
cutReason?: string;
|
|
32
|
+
}>;
|
|
33
|
+
rejectedCandidates: Cut[];
|
|
34
|
+
imageBudget: {
|
|
35
|
+
allowance: 24;
|
|
36
|
+
remaining: number;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
export declare function planStoryboardFrames(input: StoryboardProposal, words: readonly WordTiming[], narrationStartFrame: number): StoryboardFramePlan;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { assertStoryboardWords, parseStoryboardProposal, storyboardImageBudget } from "./faceless-storyboard.js";
|
|
2
|
+
const priority = { place: 4, reveal: 4, action: 3, emphasis: 1 };
|
|
3
|
+
function better(candidate, current) {
|
|
4
|
+
return !current || candidate.score > current.score ||
|
|
5
|
+
(candidate.score === current.score && candidate.penalty < current.penalty);
|
|
6
|
+
}
|
|
7
|
+
export function planStoryboardFrames(input, words, narrationStartFrame) {
|
|
8
|
+
const proposal = parseStoryboardProposal(input);
|
|
9
|
+
assertStoryboardWords(proposal.script, words);
|
|
10
|
+
if (!Number.isSafeInteger(narrationStartFrame) || narrationStartFrame < 0 || narrationStartFrame >= 1522) {
|
|
11
|
+
throw new Error("invalid narration start frame");
|
|
12
|
+
}
|
|
13
|
+
const speechEnd = narrationStartFrame / 25 + words[words.length - 1].endSec;
|
|
14
|
+
if (speechEnd > 1522 / 25)
|
|
15
|
+
throw new Error("narration exceeds output duration");
|
|
16
|
+
if (1522 / 25 - speechEnd > 0.5 + 1e-9)
|
|
17
|
+
throw new Error("narration leaves more than 0.5 seconds tail");
|
|
18
|
+
const candidates = proposal.beats.slice(1).map((beat, i) => {
|
|
19
|
+
const afterWord = beat.wordStart - 1;
|
|
20
|
+
const previous = words[afterWord];
|
|
21
|
+
const next = words[afterWord + 1];
|
|
22
|
+
const edgeSec = next.startSec > previous.endSec ? (previous.endSec + next.startSec) / 2 : next.startSec;
|
|
23
|
+
const frame = narrationStartFrame + Math.round(edgeSec * 25);
|
|
24
|
+
if (!Number.isSafeInteger(frame) || frame <= 0 || frame >= 1522)
|
|
25
|
+
throw new Error("cut outside output");
|
|
26
|
+
const time = (frame - narrationStartFrame) / 25;
|
|
27
|
+
const inside = words.some(w => time - w.startSec > 1 / 25 + 1e-9 && w.endSec - time > 1 / 25 + 1e-9);
|
|
28
|
+
return { afterWord, frame, reason: beat.reason, beatIndex: i + 1, priority: priority[beat.reason],
|
|
29
|
+
...(inside ? { rejection: "cut more than one frame inside timed word" } : {}) };
|
|
30
|
+
});
|
|
31
|
+
const opener = candidates[0];
|
|
32
|
+
if (opener.rejection || opener.frame < 75 || opener.frame > 125) {
|
|
33
|
+
throw new Error("no feasible storyboard: mandatory VIDEO boundary violates timing");
|
|
34
|
+
}
|
|
35
|
+
const nodes = [...candidates, { frame: 1522, beatIndex: proposal.beats.length, priority: 0, afterWord: words.length - 1, reason: "output end" }];
|
|
36
|
+
const states = nodes.map(() => Array(20));
|
|
37
|
+
states[0][0] = { score: opener.priority, penalty: 0, previous: -1 };
|
|
38
|
+
for (let end = 1; end < nodes.length; end++) {
|
|
39
|
+
const destination = nodes[end];
|
|
40
|
+
if ("rejection" in destination && destination.rejection)
|
|
41
|
+
continue;
|
|
42
|
+
for (let start = 0; start < end; start++) {
|
|
43
|
+
const duration = destination.frame - nodes[start].frame;
|
|
44
|
+
if (duration < 25 || duration > 150)
|
|
45
|
+
continue;
|
|
46
|
+
for (let count = 1; count <= 19; count++) {
|
|
47
|
+
const prior = states[start][count - 1];
|
|
48
|
+
if (!prior)
|
|
49
|
+
continue;
|
|
50
|
+
const state = { score: prior.score + destination.priority,
|
|
51
|
+
penalty: prior.penalty + Math.abs(duration - 68.75), previous: start };
|
|
52
|
+
if (better(state, states[end][count]))
|
|
53
|
+
states[end][count] = state;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const last = nodes.length - 1;
|
|
58
|
+
let imageCount = 0;
|
|
59
|
+
let best;
|
|
60
|
+
for (let count = 1; count <= 19; count++) {
|
|
61
|
+
const state = states[last][count];
|
|
62
|
+
if (state && better(state, best)) {
|
|
63
|
+
best = state;
|
|
64
|
+
imageCount = count;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!best)
|
|
68
|
+
throw new Error("no feasible storyboard within scene duration and image budget limits");
|
|
69
|
+
const chosen = [last];
|
|
70
|
+
let cursor = last;
|
|
71
|
+
for (let count = imageCount; count > 0; count--) {
|
|
72
|
+
cursor = states[cursor][count].previous;
|
|
73
|
+
chosen.push(cursor);
|
|
74
|
+
}
|
|
75
|
+
chosen.reverse();
|
|
76
|
+
const selected = new Set(chosen);
|
|
77
|
+
const shots = [];
|
|
78
|
+
let startFrame = 0;
|
|
79
|
+
let beatStart = 0;
|
|
80
|
+
for (const [shotIndex, nodeIndex] of chosen.entries()) {
|
|
81
|
+
const node = nodes[nodeIndex];
|
|
82
|
+
shots.push({ id: proposal.beats[beatStart].id, mediaType: shotIndex === 0 ? "video" : "image",
|
|
83
|
+
startFrame, endFrame: node.frame,
|
|
84
|
+
...(shotIndex > 0 ? { motion: shotIndex % 2 === 1 ? "PAN_UP" : "PAN_DOWN" } : {}),
|
|
85
|
+
beatIds: proposal.beats.slice(beatStart, node.beatIndex).map(b => b.id),
|
|
86
|
+
...(nodeIndex < last ? { cutAfterWord: node.afterWord, cutReason: node.reason } : {}), });
|
|
87
|
+
startFrame = node.frame;
|
|
88
|
+
beatStart = node.beatIndex;
|
|
89
|
+
}
|
|
90
|
+
return { version: proposal.version, outputFrames: 1522, script: proposal.script,
|
|
91
|
+
captionPhrases: proposal.captionPhrases, narrationStartFrame, shots,
|
|
92
|
+
rejectedCandidates: candidates.flatMap((candidate, i) => selected.has(i) ? [] : [{
|
|
93
|
+
afterWord: candidate.afterWord, frame: candidate.frame,
|
|
94
|
+
reason: candidate.rejection ?? `unselected ${candidate.reason} boundary under timing and image budget constraints`,
|
|
95
|
+
}]), imageBudget: storyboardImageBudget(imageCount, 2) };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=faceless-storyboard-timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faceless-storyboard-timing.js","sourceRoot":"","sources":["../src/faceless-storyboard-timing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,qBAAqB,EAA2B,MAAM,0BAA0B,CAAC;AA4B1I,MAAM,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAEjE,SAAS,MAAM,CAAC,SAAgB,EAAE,OAA0B;IAC1D,OAAO,CAAC,OAAO,IAAI,SAAS,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK;QAChD,CAAC,SAAS,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAAyB,EACzB,KAA4B,EAC5B,mBAA2B;IAE3B,MAAM,QAAQ,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAChD,qBAAqB,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC,IAAI,mBAAmB,GAAG,CAAC,IAAI,mBAAmB,IAAI,IAAI,EAAE,CAAC;QACzG,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,SAAS,GAAG,mBAAmB,GAAG,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,MAAM,CAAC;IAC7E,IAAI,SAAS,GAAG,IAAI,GAAG,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAChF,IAAI,IAAI,GAAG,EAAE,GAAG,SAAS,GAAG,GAAG,GAAG,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAEvG,MAAM,UAAU,GAAgB,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;QACtE,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAE,CAAC;QACnC,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,GAAG,CAAC,CAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;QACxG,MAAM,KAAK,GAAG,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAC;QAC7D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACvG,MAAM,IAAI,GAAG,CAAC,KAAK,GAAG,mBAAmB,CAAC,GAAG,EAAE,CAAC;QAChD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,QAAQ,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QACrG,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;YAC/F,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,2CAA2C,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACpF,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC;IAC9B,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,KAAK,GAAG,EAAE,IAAI,MAAM,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACjJ,MAAM,MAAM,GAAoC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAoB,EAAE,CAAC,CAAC,CAAC;IAC9F,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC;IACrE,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAE,CAAC;QAChC,IAAI,WAAW,IAAI,WAAW,IAAI,WAAW,CAAC,SAAS;YAAE,SAAS;QAClE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC;YACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAE,CAAC,KAAK,CAAC;YACzD,IAAI,QAAQ,GAAG,EAAE,IAAI,QAAQ,GAAG,GAAG;gBAAE,SAAS;YAC9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;gBACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;gBACxC,IAAI,CAAC,KAAK;oBAAE,SAAS;gBACrB,MAAM,KAAK,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC,QAAQ;oBACvD,OAAO,EAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;gBACzE,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAE,CAAC,KAAK,CAAC,CAAC;oBAAE,MAAM,CAAC,GAAG,CAAE,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;YACtE,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,IAAuB,CAAC;IAC5B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAE,CAAC,KAAK,CAAC,CAAC;QACnC,IAAI,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;YAAC,IAAI,GAAG,KAAK,CAAC;YAAC,UAAU,GAAG,KAAK,CAAC;QAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;IACnG,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC;IACtB,IAAI,MAAM,GAAG,IAAI,CAAC;IAClB,KAAK,IAAI,KAAK,GAAG,UAAU,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,MAAM,GAAG,MAAM,CAAC,MAAM,CAAE,CAAC,KAAK,CAAE,CAAC,QAAQ,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IACD,MAAM,CAAC,OAAO,EAAE,CAAC;IACjB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,MAAM,KAAK,GAAiC,EAAE,CAAC;IAC/C,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,CAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO;YAC5F,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK;YAChC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAiB,CAAC,CAAC,CAAC,UAAmB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnG,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GACtF,CAAC,CAAC;QACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAC7B,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM;QAC7E,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,mBAAmB,EAAE,KAAK;QACnE,kBAAkB,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC/E,SAAS,EAAE,SAAS,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,KAAK;gBACtD,MAAM,EAAE,SAAS,CAAC,SAAS,IAAI,cAAc,SAAS,CAAC,MAAM,qDAAqD;aACnH,CAAC,CAAC,EAAE,WAAW,EAAE,qBAAqB,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { assertStoryboardWords } from "./faceless-storyboard.js";
|
|
2
|
+
const phases = ["setup", "development", "climax", "resolution"];
|
|
3
|
+
const reasons = ["action", "place", "reveal", "emphasis"];
|
|
4
|
+
function record(value, keys) {
|
|
5
|
+
if (!value || typeof value !== "object" || Array.isArray(value) ||
|
|
6
|
+
Object.keys(value).some(key => !keys.includes(key)))
|
|
7
|
+
throw new Error("invalid storyboard v2 object or unknown fields");
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
function uint(value) { return Number.isSafeInteger(value) && value >= 0; }
|
|
11
|
+
function finite(value) { return typeof value === "number" && Number.isFinite(value) && value >= 0; }
|
|
12
|
+
function label(value) { return typeof value === "string" && value.trim().length > 0; }
|
|
13
|
+
function score(value) {
|
|
14
|
+
const s = record(value, ["semanticValue", "cutCost", "pacePenalty", "net"]);
|
|
15
|
+
if (!finite(s.semanticValue) || !finite(s.cutCost) || !finite(s.pacePenalty) ||
|
|
16
|
+
typeof s.net !== "number" || !Number.isFinite(s.net) ||
|
|
17
|
+
Math.abs(s.net - (s.semanticValue - s.cutCost - s.pacePenalty)) > 1e-8)
|
|
18
|
+
throw new Error("invalid storyboard v2 score");
|
|
19
|
+
}
|
|
20
|
+
export function parseStoryboardV2Plan(input, words) {
|
|
21
|
+
const raw = record(input, ["version", "outputFrames", "script", "narrationStartFrame", "captionPhrases", "shots", "rejectedCandidates", "scoreBreakdown"]);
|
|
22
|
+
if (raw.version !== "faceless_storyboard_61_v2" || raw.outputFrames !== 1522 || !label(raw.script) ||
|
|
23
|
+
!uint(raw.narrationStartFrame) || raw.narrationStartFrame > 50 ||
|
|
24
|
+
!Array.isArray(raw.shots) || raw.shots.length < 2 ||
|
|
25
|
+
!Array.isArray(raw.captionPhrases) || !raw.captionPhrases.length || !Array.isArray(raw.rejectedCandidates)) {
|
|
26
|
+
throw new Error("invalid storyboard v2 frame plan");
|
|
27
|
+
}
|
|
28
|
+
assertStoryboardWords(raw.script, words);
|
|
29
|
+
if (raw.narrationStartFrame + words.at(-1).endSec * 25 > 1522 + 1e-9 ||
|
|
30
|
+
1522 - raw.narrationStartFrame - words.at(-1).endSec * 25 > 12.5 + 1e-9)
|
|
31
|
+
throw new Error("invalid storyboard v2 narration tail");
|
|
32
|
+
let captionEnd = 0;
|
|
33
|
+
for (const phrase of raw.captionPhrases) {
|
|
34
|
+
const p = record(phrase, ["wordStart", "wordEnd", "accentWord"]);
|
|
35
|
+
if (!uint(p.wordStart) || !uint(p.wordEnd) || !uint(p.accentWord) || p.wordStart !== captionEnd || p.wordStart >= p.wordEnd ||
|
|
36
|
+
p.wordEnd > words.length || p.accentWord < p.wordStart || p.accentWord >= p.wordEnd)
|
|
37
|
+
throw new Error("invalid storyboard v2 caption");
|
|
38
|
+
captionEnd = p.wordEnd;
|
|
39
|
+
}
|
|
40
|
+
if (captionEnd !== words.length)
|
|
41
|
+
throw new Error("incomplete storyboard v2 captions");
|
|
42
|
+
const ids = new Set();
|
|
43
|
+
const beatIds = new Set();
|
|
44
|
+
let end = 0;
|
|
45
|
+
let previousWord = -1;
|
|
46
|
+
let previousPhase = -1;
|
|
47
|
+
let semanticValue = 0, cutCost = 0, pacePenalty = 0, total = 0, cuts = 0;
|
|
48
|
+
for (const [i, value] of raw.shots.entries()) {
|
|
49
|
+
const shot = record(value, ["id", "mediaType", "startFrame", "endFrame", "beatIds", "phase", "mergedPhases", "motion", "panExceptionReason", "cutAfterWord", "cutReason", "score"]);
|
|
50
|
+
if (!label(shot.id) || ids.has(shot.id))
|
|
51
|
+
throw new Error("duplicate or invalid storyboard v2 shot ID");
|
|
52
|
+
ids.add(shot.id);
|
|
53
|
+
if (!uint(shot.startFrame) || !uint(shot.endFrame) || shot.startFrame !== end || shot.endFrame > 1522 ||
|
|
54
|
+
shot.endFrame - shot.startFrame < (i ? 25 : 50) || shot.endFrame - shot.startFrame > (i ? 150 : 125) ||
|
|
55
|
+
shot.mediaType !== (i ? "image" : "video") || (i ? !(typeof shot.motion === "string" && ["PAN_UP", "PAN_DOWN"].includes(shot.motion)) : shot.motion !== undefined) ||
|
|
56
|
+
!Array.isArray(shot.beatIds) || !shot.beatIds.length || !shot.beatIds.every(label) ||
|
|
57
|
+
!(typeof shot.phase === "string" && phases.includes(shot.phase)) || phases.indexOf(shot.phase) < previousPhase ||
|
|
58
|
+
(shot.mergedPhases !== undefined && (!Array.isArray(shot.mergedPhases) || !shot.mergedPhases.length || !shot.mergedPhases.every(p => phases.includes(p)))) ||
|
|
59
|
+
(shot.panExceptionReason !== undefined && (!i || !label(shot.panExceptionReason))))
|
|
60
|
+
throw new Error("invalid storyboard v2 shot coverage, duration, or fields");
|
|
61
|
+
for (const beat of shot.beatIds) {
|
|
62
|
+
if (beatIds.has(beat))
|
|
63
|
+
throw new Error("duplicate storyboard v2 beat ID");
|
|
64
|
+
beatIds.add(beat);
|
|
65
|
+
}
|
|
66
|
+
previousPhase = phases.indexOf(shot.phase);
|
|
67
|
+
end = shot.endFrame;
|
|
68
|
+
score(shot.score);
|
|
69
|
+
const s = shot.score;
|
|
70
|
+
semanticValue += s.semanticValue;
|
|
71
|
+
cutCost += s.cutCost;
|
|
72
|
+
pacePenalty += s.pacePenalty;
|
|
73
|
+
total += s.net;
|
|
74
|
+
if (i < raw.shots.length - 1) {
|
|
75
|
+
if (!uint(shot.cutAfterWord) || shot.cutAfterWord <= previousWord || shot.cutAfterWord >= words.length - 1 ||
|
|
76
|
+
!(typeof shot.cutReason === "string" && reasons.includes(shot.cutReason)))
|
|
77
|
+
throw new Error("invalid storyboard v2 cut word or reason");
|
|
78
|
+
const previous = words[shot.cutAfterWord];
|
|
79
|
+
const next = words[shot.cutAfterWord + 1];
|
|
80
|
+
const edgeSec = next.startSec > previous.endSec ? (previous.endSec + next.startSec) / 2 : next.startSec;
|
|
81
|
+
const frame = raw.narrationStartFrame + Math.round(edgeSec * 25);
|
|
82
|
+
const sec = (shot.endFrame - raw.narrationStartFrame) / 25;
|
|
83
|
+
if (shot.endFrame !== frame || words.some(w => sec - w.startSec > 1 / 25 + 1e-9 && w.endSec - sec > 1 / 25 + 1e-9)) {
|
|
84
|
+
throw new Error("storyboard v2 cut lies mid-word or differs from measured boundary");
|
|
85
|
+
}
|
|
86
|
+
previousWord = shot.cutAfterWord;
|
|
87
|
+
cuts++;
|
|
88
|
+
}
|
|
89
|
+
else if (shot.cutAfterWord !== undefined || shot.cutReason !== undefined)
|
|
90
|
+
throw new Error("final storyboard v2 shot cannot end in a cut");
|
|
91
|
+
}
|
|
92
|
+
if (end !== 1522)
|
|
93
|
+
throw new Error("incomplete storyboard v2 output coverage");
|
|
94
|
+
for (const value of raw.rejectedCandidates) {
|
|
95
|
+
const candidate = record(value, ["afterWord", "frame", "beatId", "reason", "semanticValue", "cutCost", "pacePenalty", "net"]);
|
|
96
|
+
if (!uint(candidate.afterWord) || candidate.afterWord >= words.length - 1 || !uint(candidate.frame) || candidate.frame > 1522 ||
|
|
97
|
+
!label(candidate.beatId) || !label(candidate.reason) || !finite(candidate.semanticValue) || !finite(candidate.cutCost) ||
|
|
98
|
+
(candidate.pacePenalty !== null && !finite(candidate.pacePenalty)) ||
|
|
99
|
+
(candidate.net !== null && (typeof candidate.net !== "number" || !Number.isFinite(candidate.net))) ||
|
|
100
|
+
((candidate.pacePenalty === null) !== (candidate.net === null)))
|
|
101
|
+
throw new Error("invalid storyboard v2 rejected candidate");
|
|
102
|
+
}
|
|
103
|
+
const summary = record(raw.scoreBreakdown, ["semanticValue", "cutCost", "pacePenalty", "total", "cuts"]);
|
|
104
|
+
if (!finite(summary.semanticValue) || !finite(summary.cutCost) || !finite(summary.pacePenalty) ||
|
|
105
|
+
typeof summary.total !== "number" || !Number.isFinite(summary.total) || !uint(summary.cuts) ||
|
|
106
|
+
Math.abs(summary.semanticValue - semanticValue) > 1e-8 || Math.abs(summary.cutCost - cutCost) > 1e-8 ||
|
|
107
|
+
Math.abs(summary.pacePenalty - pacePenalty) > 1e-8 || Math.abs(summary.total - total) > 1e-8 || summary.cuts !== cuts) {
|
|
108
|
+
throw new Error("invalid storyboard v2 score breakdown");
|
|
109
|
+
}
|
|
110
|
+
return raw;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=faceless-storyboard-v2-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faceless-storyboard-v2-plan.js","sourceRoot":"","sources":["../src/faceless-storyboard-v2-plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type StoryboardV2Proposal } from "./faceless-storyboard-v2.js";
|
|
2
|
+
import type { CutStyleProfile } from "./faceless-cut-style.js";
|
|
3
|
+
import type { WordTiming } from "./tts-backend.js";
|
|
4
|
+
type Phase = StoryboardV2Proposal["beats"][number]["phase"];
|
|
5
|
+
type Score = {
|
|
6
|
+
semanticValue: number;
|
|
7
|
+
cutCost: number;
|
|
8
|
+
pacePenalty: number;
|
|
9
|
+
net: number;
|
|
10
|
+
};
|
|
11
|
+
export type StoryboardV2FramePlan = {
|
|
12
|
+
version: "faceless_storyboard_61_v2";
|
|
13
|
+
outputFrames: 1522;
|
|
14
|
+
script: string;
|
|
15
|
+
captionPhrases: StoryboardV2Proposal["captionPhrases"];
|
|
16
|
+
narrationStartFrame: number;
|
|
17
|
+
shots: Array<{
|
|
18
|
+
id: string;
|
|
19
|
+
mediaType: "video" | "image";
|
|
20
|
+
startFrame: number;
|
|
21
|
+
endFrame: number;
|
|
22
|
+
beatIds: string[];
|
|
23
|
+
phase: Phase;
|
|
24
|
+
mergedPhases?: Phase[];
|
|
25
|
+
motion?: "PAN_UP" | "PAN_DOWN";
|
|
26
|
+
panExceptionReason?: string;
|
|
27
|
+
cutAfterWord?: number;
|
|
28
|
+
cutReason?: string;
|
|
29
|
+
score: Score;
|
|
30
|
+
}>;
|
|
31
|
+
/** Rejected scores are local incoming-edge estimates, not alternate complete-path scores.
|
|
32
|
+
* Null pacePenalty/net means no feasible incoming edge was reachable. */
|
|
33
|
+
rejectedCandidates: Array<{
|
|
34
|
+
afterWord: number;
|
|
35
|
+
frame: number;
|
|
36
|
+
beatId: string;
|
|
37
|
+
reason: string;
|
|
38
|
+
semanticValue: number;
|
|
39
|
+
cutCost: number;
|
|
40
|
+
pacePenalty: number | null;
|
|
41
|
+
net: number | null;
|
|
42
|
+
}>;
|
|
43
|
+
scoreBreakdown: {
|
|
44
|
+
semanticValue: number;
|
|
45
|
+
cutCost: number;
|
|
46
|
+
pacePenalty: number;
|
|
47
|
+
total: number;
|
|
48
|
+
cuts: number;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
declare const semantic: {
|
|
52
|
+
readonly place: 4;
|
|
53
|
+
readonly reveal: 4;
|
|
54
|
+
readonly action: 3;
|
|
55
|
+
readonly emphasis: 1;
|
|
56
|
+
};
|
|
57
|
+
/** Shared semantic objective; duration feasibility belongs to each profile. */
|
|
58
|
+
export declare function facelessCutScore(reason: keyof typeof semantic | null, duration: number, range: {
|
|
59
|
+
p25: number | null;
|
|
60
|
+
p75: number | null;
|
|
61
|
+
}): Score;
|
|
62
|
+
export declare function planStoryboardV2(input: StoryboardV2Proposal, words: readonly WordTiming[], narrationStartFrame: number, style: CutStyleProfile): StoryboardV2FramePlan;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { assertStoryboardWords } from "./faceless-storyboard.js";
|
|
2
|
+
import { parseStoryboardV2 } from "./faceless-storyboard-v2.js";
|
|
3
|
+
const semantic = { place: 4, reveal: 4, action: 3, emphasis: 1 };
|
|
4
|
+
const CUT_COST = 2;
|
|
5
|
+
const OUTPUT_FRAMES = 1522;
|
|
6
|
+
const FPS = 25;
|
|
7
|
+
/** Shared semantic objective; duration feasibility belongs to each profile. */
|
|
8
|
+
export function facelessCutScore(reason, duration, range) {
|
|
9
|
+
const value = reason === null ? 0 : semantic[reason];
|
|
10
|
+
const cost = reason === null ? 0 : CUT_COST;
|
|
11
|
+
const distance = duration < range.p25 ? range.p25 - duration : duration > range.p75 ? duration - range.p75 : 0;
|
|
12
|
+
const penalty = 0.25 * distance / FPS;
|
|
13
|
+
return { semanticValue: value, cutCost: cost, pacePenalty: penalty, net: value - cost - penalty };
|
|
14
|
+
}
|
|
15
|
+
function better(a, b) {
|
|
16
|
+
if (!b)
|
|
17
|
+
return true;
|
|
18
|
+
if (Math.abs(a.total - b.total) > 1e-9)
|
|
19
|
+
return a.total > b.total;
|
|
20
|
+
if (a.cuts !== b.cuts)
|
|
21
|
+
return a.cuts < b.cuts;
|
|
22
|
+
for (let i = 0; i < a.path.length; i++) {
|
|
23
|
+
if (a.path[i] !== b.path[i])
|
|
24
|
+
return a.path[i] < b.path[i];
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
export function planStoryboardV2(input, words, narrationStartFrame, style) {
|
|
29
|
+
const proposal = parseStoryboardV2(input);
|
|
30
|
+
assertStoryboardWords(proposal.script, words);
|
|
31
|
+
if (!Number.isSafeInteger(narrationStartFrame) || narrationStartFrame < 0 || narrationStartFrame > 50) {
|
|
32
|
+
throw new Error("invalid narration start frame");
|
|
33
|
+
}
|
|
34
|
+
const speechEndFrame = narrationStartFrame + words.at(-1).endSec * FPS;
|
|
35
|
+
if (speechEndFrame > OUTPUT_FRAMES + 1e-9)
|
|
36
|
+
throw new Error("narration exceeds output duration");
|
|
37
|
+
if (OUTPUT_FRAMES - speechEndFrame > 12.5 + 1e-9)
|
|
38
|
+
throw new Error("narration leaves more than 0.5 seconds tail");
|
|
39
|
+
const candidates = proposal.beats.slice(1).map((beat, i) => {
|
|
40
|
+
const afterWord = beat.wordStart - 1;
|
|
41
|
+
const previous = words[afterWord];
|
|
42
|
+
const next = words[afterWord + 1];
|
|
43
|
+
const edgeSec = next.startSec > previous.endSec ? (previous.endSec + next.startSec) / 2 : next.startSec;
|
|
44
|
+
const frame = narrationStartFrame + Math.round(edgeSec * FPS);
|
|
45
|
+
const time = (frame - narrationStartFrame) / FPS;
|
|
46
|
+
const inside = words.some(w => time - w.startSec > 1 / FPS + 1e-9 && w.endSec - time > 1 / FPS + 1e-9);
|
|
47
|
+
return { beatIndex: i + 1, afterWord, frame, reason: beat.reason,
|
|
48
|
+
...(frame <= 0 || frame >= OUTPUT_FRAMES ? { invalidReason: "candidate lies outside output frames" } : {}),
|
|
49
|
+
...(inside ? { invalidReason: "candidate lies more than one frame inside a timed word" } : {}) };
|
|
50
|
+
});
|
|
51
|
+
const opener = candidates[0];
|
|
52
|
+
if (opener.invalidReason || opener.frame < 50 || opener.frame > 125) {
|
|
53
|
+
throw new Error(`no feasible storyboard: mandatory VIDEO boundary violates timing${opener.invalidReason ? ` (${opener.invalidReason})` : ""}`);
|
|
54
|
+
}
|
|
55
|
+
const nodes = [...candidates, { beatIndex: proposal.beats.length, afterWord: words.length - 1, frame: OUTPUT_FRAMES, reason: "output end" }];
|
|
56
|
+
const final = nodes.length - 1;
|
|
57
|
+
const states = Array(nodes.length);
|
|
58
|
+
const openerValue = semantic[proposal.beats[1].reason];
|
|
59
|
+
states[0] = { total: openerValue - CUT_COST, semantic: openerValue, cutCost: CUT_COST, pacePenalty: 0,
|
|
60
|
+
cuts: 1, path: [0], previous: -1, edge: { semanticValue: openerValue, cutCost: CUT_COST, pacePenalty: 0, net: openerValue - CUT_COST } };
|
|
61
|
+
function pacePenalty(start, end) {
|
|
62
|
+
const phase = proposal.beats[nodes[start].beatIndex].phase;
|
|
63
|
+
const phaseRange = style.pacing.by_phase[phase];
|
|
64
|
+
const range = phaseRange && phaseRange.n > 0 ? phaseRange : style.pacing.global_image_frames;
|
|
65
|
+
const duration = nodes[end].frame - nodes[start].frame;
|
|
66
|
+
return facelessCutScore(null, duration, range).pacePenalty;
|
|
67
|
+
}
|
|
68
|
+
for (let end = 1; end <= final; end++) {
|
|
69
|
+
const destination = nodes[end];
|
|
70
|
+
if (destination.invalidReason)
|
|
71
|
+
continue;
|
|
72
|
+
const value = end === final ? 0 : semantic[proposal.beats[destination.beatIndex].reason];
|
|
73
|
+
const cost = end === final ? 0 : CUT_COST;
|
|
74
|
+
for (let start = 0; start < end; start++) {
|
|
75
|
+
const prior = states[start];
|
|
76
|
+
if (!prior)
|
|
77
|
+
continue;
|
|
78
|
+
const duration = destination.frame - nodes[start].frame;
|
|
79
|
+
if (duration < 25 || duration > 150)
|
|
80
|
+
continue;
|
|
81
|
+
const penalty = pacePenalty(start, end);
|
|
82
|
+
const edge = { semanticValue: value, cutCost: cost, pacePenalty: penalty, net: value - cost - penalty };
|
|
83
|
+
const next = { total: prior.total + edge.net, semantic: prior.semantic + value,
|
|
84
|
+
cutCost: prior.cutCost + cost, pacePenalty: prior.pacePenalty + penalty,
|
|
85
|
+
cuts: prior.cuts + (end === final ? 0 : 1), path: [...prior.path, end], previous: start, edge };
|
|
86
|
+
if (better(next, states[end]))
|
|
87
|
+
states[end] = next;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const best = states[final];
|
|
91
|
+
if (!best)
|
|
92
|
+
throw new Error("no feasible storyboard within VIDEO and IMAGE duration bounds");
|
|
93
|
+
const selected = new Set(best.path);
|
|
94
|
+
const shots = [];
|
|
95
|
+
let startFrame = 0;
|
|
96
|
+
let beatStart = 0;
|
|
97
|
+
for (const [shotIndex, nodeIndex] of best.path.entries()) {
|
|
98
|
+
const node = nodes[nodeIndex];
|
|
99
|
+
const current = states[nodeIndex];
|
|
100
|
+
const included = proposal.beats.slice(beatStart, node.beatIndex);
|
|
101
|
+
const phases = [...new Set(included.map(b => b.phase))];
|
|
102
|
+
const holdMotion = style.motion.pan_transition_n > 0 && style.motion.pan_flip_probability !== null && style.motion.pan_flip_probability < 0.5;
|
|
103
|
+
const motion = shotIndex === 0 ? undefined : holdMotion ? "PAN_UP" : shotIndex % 2 === 1 ? "PAN_UP" : "PAN_DOWN";
|
|
104
|
+
shots.push({ id: included[0].id, mediaType: shotIndex === 0 ? "video" : "image", startFrame, endFrame: node.frame,
|
|
105
|
+
beatIds: included.map(b => b.id), phase: included[0].phase,
|
|
106
|
+
...(phases.length > 1 ? { mergedPhases: phases } : {}),
|
|
107
|
+
...(motion ? { motion } : {}),
|
|
108
|
+
...(holdMotion && shotIndex > 1 ? { panExceptionReason: "style profile favors holding PAN direction" } : {}),
|
|
109
|
+
...(nodeIndex < final ? { cutAfterWord: node.afterWord, cutReason: node.reason } : {}),
|
|
110
|
+
score: current.edge });
|
|
111
|
+
startFrame = node.frame;
|
|
112
|
+
beatStart = node.beatIndex;
|
|
113
|
+
}
|
|
114
|
+
const rejectedCandidates = candidates.flatMap((candidate, index) => {
|
|
115
|
+
if (selected.has(index))
|
|
116
|
+
return [];
|
|
117
|
+
let possiblePenalty = null;
|
|
118
|
+
if (!candidate.invalidReason) {
|
|
119
|
+
for (let start = 0; start < index; start++) {
|
|
120
|
+
if (!states[start])
|
|
121
|
+
continue;
|
|
122
|
+
const duration = candidate.frame - nodes[start].frame;
|
|
123
|
+
if (duration < 25 || duration > 150)
|
|
124
|
+
continue;
|
|
125
|
+
const penalty = pacePenalty(start, index);
|
|
126
|
+
possiblePenalty = possiblePenalty === null ? penalty : Math.min(possiblePenalty, penalty);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const value = semantic[proposal.beats[candidate.beatIndex].reason];
|
|
130
|
+
const reason = candidate.invalidReason ?? (possiblePenalty === null
|
|
131
|
+
? "no reachable preceding IMAGE shot within 25–150 frames"
|
|
132
|
+
: value < CUT_COST ? "semantic value does not cover fixed cut cost"
|
|
133
|
+
: "lower total path score or deterministic tie break after IMAGE duration and pace costs");
|
|
134
|
+
return [{ afterWord: candidate.afterWord, frame: candidate.frame, beatId: proposal.beats[candidate.beatIndex].id,
|
|
135
|
+
reason, semanticValue: value, cutCost: CUT_COST, pacePenalty: possiblePenalty,
|
|
136
|
+
net: possiblePenalty === null ? null : value - CUT_COST - possiblePenalty }];
|
|
137
|
+
});
|
|
138
|
+
return { version: proposal.version, outputFrames: OUTPUT_FRAMES, script: proposal.script,
|
|
139
|
+
captionPhrases: proposal.captionPhrases, narrationStartFrame, shots, rejectedCandidates,
|
|
140
|
+
scoreBreakdown: { semanticValue: best.semantic, cutCost: best.cutCost,
|
|
141
|
+
pacePenalty: best.pacePenalty, total: best.total, cuts: best.cuts } };
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=faceless-storyboard-v2-timing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faceless-storyboard-v2-timing.js","sourceRoot":"","sources":["../src/faceless-storyboard-v2-timing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const proposal: z.ZodObject<{
|
|
3
|
+
version: z.ZodLiteral<"faceless_storyboard_61_v2">;
|
|
4
|
+
premise: z.ZodString;
|
|
5
|
+
script: z.ZodString;
|
|
6
|
+
provenance: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
7
|
+
kind: z.ZodLiteral<"fixture">;
|
|
8
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
9
|
+
kind: z.ZodLiteral<"model">;
|
|
10
|
+
model: z.ZodString;
|
|
11
|
+
promptSha256: z.ZodString;
|
|
12
|
+
responseSha256: z.ZodString;
|
|
13
|
+
}, z.core.$strict>], "kind">;
|
|
14
|
+
beats: z.ZodArray<z.ZodObject<{
|
|
15
|
+
id: z.ZodString;
|
|
16
|
+
wordStart: z.ZodNumber;
|
|
17
|
+
wordEnd: z.ZodNumber;
|
|
18
|
+
reason: z.ZodEnum<{
|
|
19
|
+
action: "action";
|
|
20
|
+
emphasis: "emphasis";
|
|
21
|
+
place: "place";
|
|
22
|
+
reveal: "reveal";
|
|
23
|
+
}>;
|
|
24
|
+
mediaType: z.ZodEnum<{
|
|
25
|
+
image: "image";
|
|
26
|
+
video: "video";
|
|
27
|
+
}>;
|
|
28
|
+
visualPrompt: z.ZodString;
|
|
29
|
+
phase: z.ZodEnum<{
|
|
30
|
+
climax: "climax";
|
|
31
|
+
development: "development";
|
|
32
|
+
resolution: "resolution";
|
|
33
|
+
setup: "setup";
|
|
34
|
+
}>;
|
|
35
|
+
}, z.core.$strict>>;
|
|
36
|
+
captionPhrases: z.ZodArray<z.ZodObject<{
|
|
37
|
+
wordStart: z.ZodNumber;
|
|
38
|
+
wordEnd: z.ZodNumber;
|
|
39
|
+
accentWord: z.ZodNumber;
|
|
40
|
+
}, z.core.$strict>>;
|
|
41
|
+
}, z.core.$strict>;
|
|
42
|
+
export type StoryboardV2Proposal = z.infer<typeof proposal>;
|
|
43
|
+
export declare function parseStoryboardV2(input: unknown): StoryboardV2Proposal;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { parseStoryboardProposal } from "./faceless-storyboard.js";
|
|
3
|
+
const nonblank = z.string().trim().min(1);
|
|
4
|
+
const index = z.number().int().nonnegative();
|
|
5
|
+
const sha256 = z.string().regex(/^[0-9a-fA-F]{64}$/);
|
|
6
|
+
const phase = z.enum(["setup", "development", "climax", "resolution"]);
|
|
7
|
+
const phaseOrder = { setup: 0, development: 1, climax: 2, resolution: 3 };
|
|
8
|
+
const proposal = z.strictObject({
|
|
9
|
+
version: z.literal("faceless_storyboard_61_v2"),
|
|
10
|
+
premise: nonblank,
|
|
11
|
+
script: nonblank,
|
|
12
|
+
provenance: z.discriminatedUnion("kind", [
|
|
13
|
+
z.strictObject({ kind: z.literal("fixture") }),
|
|
14
|
+
z.strictObject({ kind: z.literal("model"), model: nonblank, promptSha256: sha256, responseSha256: sha256 }),
|
|
15
|
+
]),
|
|
16
|
+
beats: z.array(z.strictObject({
|
|
17
|
+
id: nonblank, wordStart: index, wordEnd: index,
|
|
18
|
+
reason: z.enum(["action", "place", "reveal", "emphasis"]),
|
|
19
|
+
mediaType: z.enum(["video", "image"]), visualPrompt: nonblank, phase,
|
|
20
|
+
})).min(2),
|
|
21
|
+
captionPhrases: z.array(z.strictObject({ wordStart: index, wordEnd: index, accentWord: index })).min(1),
|
|
22
|
+
});
|
|
23
|
+
export function parseStoryboardV2(input) {
|
|
24
|
+
const parsed = proposal.parse(input);
|
|
25
|
+
const { beats, version: _version, ...v1Fields } = parsed;
|
|
26
|
+
parseStoryboardProposal({
|
|
27
|
+
...v1Fields,
|
|
28
|
+
version: "faceless_storyboard_61_v1",
|
|
29
|
+
beats: beats.map(({ phase: _phase, ...beat }) => beat),
|
|
30
|
+
});
|
|
31
|
+
if (parsed.provenance.kind === "model") {
|
|
32
|
+
const wordCount = parsed.script.normalize("NFKC").match(/[\p{L}\p{N}\p{M}]+(?:['’][\p{L}\p{N}\p{M}]+)*/gu)?.length ?? 0;
|
|
33
|
+
if (wordCount < 155 || wordCount > 165)
|
|
34
|
+
throw new Error("model storyboard requires 155–165 spoken words");
|
|
35
|
+
}
|
|
36
|
+
for (let i = 1; i < beats.length; i++) {
|
|
37
|
+
if (phaseOrder[beats[i].phase] < phaseOrder[beats[i - 1].phase]) {
|
|
38
|
+
throw new Error("storyboard phases must be ordered");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=faceless-storyboard-v2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"faceless-storyboard-v2.js","sourceRoot":"","sources":["../src/faceless-storyboard-v2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC1C,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;AAC7C,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;AACrD,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;AACvE,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAW,CAAC;AAEnF,MAAM,QAAQ,GAAG,CAAC,CAAC,YAAY,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,2BAA2B,CAAC;IAC/C,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;QACvC,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9C,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;KAC5G,CAAC;IACF,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;QAC5B,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK;QAC9C,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QACzD,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK;KACrE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACV,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CACxG,CAAC,CAAC;AAIH,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC;IACzD,uBAAuB,CAAC;QACtB,GAAG,QAAQ;QACX,OAAO,EAAE,2BAA2B;QACpC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;KACvD,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,iDAAiD,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;QACxH,IAAI,SAAS,GAAG,GAAG,IAAI,SAAS,GAAG,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAC5G,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,KAAK,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|