@clipwright/core 0.35.0 → 0.37.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.
Files changed (210) hide show
  1. package/README.md +3 -2
  2. package/dist/account-actors.d.ts +5 -6
  3. package/dist/account-actors.js +5 -6
  4. package/dist/account-actors.js.map +1 -1
  5. package/dist/actors.d.ts +8 -0
  6. package/dist/actors.js +2 -0
  7. package/dist/actors.js.map +1 -1
  8. package/dist/api-failure.d.ts +1 -1
  9. package/dist/api-failure.js +2 -2
  10. package/dist/api-failure.js.map +1 -1
  11. package/dist/aspect.d.ts +1 -1
  12. package/dist/aspect.js +5 -5
  13. package/dist/aspect.js.map +1 -1
  14. package/dist/assets.d.ts +13 -5
  15. package/dist/assets.js +7 -6
  16. package/dist/assets.js.map +1 -1
  17. package/dist/billing-terms.d.ts +1 -1
  18. package/dist/billing-terms.js +1 -1
  19. package/dist/billing-terms.js.map +1 -1
  20. package/dist/canvas-fit.js +1 -1
  21. package/dist/canvas-fit.js.map +1 -1
  22. package/dist/caption-geometry.d.ts +43 -0
  23. package/dist/caption-geometry.js +41 -0
  24. package/dist/caption-geometry.js.map +1 -0
  25. package/dist/contract-dispositions.d.ts +1005 -43
  26. package/dist/contract-dispositions.js +36 -16
  27. package/dist/contract-dispositions.js.map +1 -1
  28. package/dist/contracts/v1/workflow-brief.d.ts +2045 -38
  29. package/dist/contracts/v1/workflow-brief.js +2 -2
  30. package/dist/contracts/v1/workflow-brief.js.map +1 -1
  31. package/dist/contracts/v1/workflow-catalog.d.ts +2196 -72
  32. package/dist/contracts/v1/workflow-client.d.ts +1249 -70
  33. package/dist/contracts/v1/workflow-execution.d.ts +3 -3
  34. package/dist/contracts/v1/workflow-plan.d.ts +3294 -108
  35. package/dist/contracts/v1/workflow-run-read.d.ts +2 -2
  36. package/dist/edit-billing.d.ts +1 -0
  37. package/dist/edit-billing.js +3 -2
  38. package/dist/edit-billing.js.map +1 -1
  39. package/dist/edit-candidate.d.ts +2 -2
  40. package/dist/edit-candidate.js +2 -2
  41. package/dist/edit-candidate.js.map +1 -1
  42. package/dist/edit-document.d.ts +22 -0
  43. package/dist/edit-document.js +3 -0
  44. package/dist/edit-document.js.map +1 -1
  45. package/dist/edit-long-form.d.ts +2 -2
  46. package/dist/edit-long-form.js +3 -3
  47. package/dist/edit-long-form.js.map +1 -1
  48. package/dist/edit-revision.d.ts +10 -1
  49. package/dist/edit-revision.js +1 -1
  50. package/dist/edit-revision.js.map +1 -1
  51. package/dist/edit-rules.d.ts +1 -0
  52. package/dist/edit-rules.js +3 -0
  53. package/dist/edit-rules.js.map +1 -1
  54. package/dist/edit-shots.d.ts +2 -0
  55. package/dist/edit-validate.d.ts +4 -2
  56. package/dist/edit-validate.js +18 -2
  57. package/dist/edit-validate.js.map +1 -1
  58. package/dist/endpoint-notes.js +12 -8
  59. package/dist/endpoint-notes.js.map +1 -1
  60. package/dist/endpoints.d.ts +1 -1
  61. package/dist/endpoints.js +4 -1
  62. package/dist/endpoints.js.map +1 -1
  63. package/dist/errors.d.ts +3 -2
  64. package/dist/errors.js +5 -2
  65. package/dist/errors.js.map +1 -1
  66. package/dist/face-billing.d.ts +1 -1
  67. package/dist/face-billing.js +3 -3
  68. package/dist/face-billing.js.map +1 -1
  69. package/dist/face-delivery.d.ts +1 -1
  70. package/dist/face-delivery.js +1 -1
  71. package/dist/face-delivery.js.map +1 -1
  72. package/dist/faceless-media-record.d.ts +28 -1
  73. package/dist/faceless-media-record.js +16 -2
  74. package/dist/faceless-media-record.js.map +1 -1
  75. package/dist/faceless-price.d.ts +25 -6
  76. package/dist/faceless-price.js +13 -6
  77. package/dist/faceless-price.js.map +1 -1
  78. package/dist/faceless-public-plan.d.ts +6 -2
  79. package/dist/faceless-public-plan.js +11 -7
  80. package/dist/faceless-public-plan.js.map +1 -1
  81. package/dist/faceless-public.d.ts +108 -1
  82. package/dist/faceless-public.js +38 -5
  83. package/dist/faceless-public.js.map +1 -1
  84. package/dist/faceless-voices.d.ts +6 -6
  85. package/dist/faceless-voices.js +5 -5
  86. package/dist/faceless-voices.js.map +1 -1
  87. package/dist/feedback.d.ts +29 -0
  88. package/dist/feedback.js +29 -0
  89. package/dist/feedback.js.map +1 -0
  90. package/dist/generations.d.ts +2 -19
  91. package/dist/generations.js +28 -48
  92. package/dist/generations.js.map +1 -1
  93. package/dist/index.d.ts +5 -0
  94. package/dist/index.js +6 -0
  95. package/dist/index.js.map +1 -1
  96. package/dist/long-form-revision.d.ts +8 -0
  97. package/dist/media-timebase.js +2 -2
  98. package/dist/media-timebase.js.map +1 -1
  99. package/dist/openapi.d.ts +4 -3
  100. package/dist/openapi.js +8 -3
  101. package/dist/openapi.js.map +1 -1
  102. package/dist/parts-pricing.d.ts +3 -3
  103. package/dist/parts-pricing.js +6 -6
  104. package/dist/parts-pricing.js.map +1 -1
  105. package/dist/presenter-beats.d.ts +2 -2
  106. package/dist/presenter-beats.js +2 -2
  107. package/dist/presenter-beats.js.map +1 -1
  108. package/dist/prices.js +5 -1
  109. package/dist/prices.js.map +1 -1
  110. package/dist/public-responses.d.ts +1 -1
  111. package/dist/public-responses.js +1 -1
  112. package/dist/public-responses.js.map +1 -1
  113. package/dist/rate-limit.d.ts +2 -2
  114. package/dist/rate-limit.js +2 -2
  115. package/dist/rate-limit.js.map +1 -1
  116. package/dist/reference-analysis.d.ts +636 -43
  117. package/dist/reference-analysis.js +262 -22
  118. package/dist/reference-analysis.js.map +1 -1
  119. package/dist/reference-display.d.ts +36 -0
  120. package/dist/reference-display.js +78 -0
  121. package/dist/reference-display.js.map +1 -0
  122. package/dist/reference-kinds.d.ts +3 -1
  123. package/dist/reference-kinds.js +3 -1
  124. package/dist/reference-kinds.js.map +1 -1
  125. package/dist/reference-profile.d.ts +2394 -40
  126. package/dist/reference-profile.js +192 -17
  127. package/dist/reference-profile.js.map +1 -1
  128. package/dist/reference-staging.d.ts +71 -57
  129. package/dist/reference-staging.js +9 -6
  130. package/dist/reference-staging.js.map +1 -1
  131. package/dist/reference-voice.d.ts +1 -1
  132. package/dist/reference-voice.js +3 -3
  133. package/dist/reference-voice.js.map +1 -1
  134. package/dist/render-backend.d.ts +1 -1
  135. package/dist/resolved-timeline.d.ts +201 -4
  136. package/dist/resolved-timeline.js +20 -8
  137. package/dist/resolved-timeline.js.map +1 -1
  138. package/dist/run-static-warnings.js +1 -1
  139. package/dist/run-static-warnings.js.map +1 -1
  140. package/dist/runs.d.ts +3 -3
  141. package/dist/runs.js +3 -3
  142. package/dist/runs.js.map +1 -1
  143. package/dist/scene-place.d.ts +225 -0
  144. package/dist/scene-place.js +120 -0
  145. package/dist/scene-place.js.map +1 -0
  146. package/dist/semantic-inserts.d.ts +1 -1
  147. package/dist/semantic-inserts.js +2 -2
  148. package/dist/semantic-inserts.js.map +1 -1
  149. package/dist/skills.d.ts +4685 -30
  150. package/dist/skills.js +153 -37
  151. package/dist/skills.js.map +1 -1
  152. package/dist/templates/index.d.ts +15 -5
  153. package/dist/templates/index.js +50 -6
  154. package/dist/templates/index.js.map +1 -1
  155. package/dist/templates/size.d.ts +1 -1
  156. package/dist/templates/size.js +1 -1
  157. package/dist/templates/size.js.map +1 -1
  158. package/dist/templates/sounds.js +1 -1
  159. package/dist/templates/sounds.js.map +1 -1
  160. package/dist/ugc-call.d.ts +1 -1
  161. package/dist/ugc-call.js +2 -2
  162. package/dist/ugc-call.js.map +1 -1
  163. package/dist/ugc-delivery.d.ts +1 -1
  164. package/dist/ugc-delivery.js +1 -1
  165. package/dist/ugc-delivery.js.map +1 -1
  166. package/dist/ugc-interview.d.ts +122 -0
  167. package/dist/ugc-interview.js +260 -0
  168. package/dist/ugc-interview.js.map +1 -0
  169. package/dist/ugc-layers.d.ts +88 -6
  170. package/dist/ugc-layers.js +193 -5
  171. package/dist/ugc-layers.js.map +1 -1
  172. package/dist/ugc-video-media.d.ts +1 -1
  173. package/dist/ugc-video-media.js +1 -1
  174. package/dist/ugc-video-media.js.map +1 -1
  175. package/dist/uploads.d.ts +2 -2
  176. package/dist/uploads.js +2 -2
  177. package/dist/uploads.js.map +1 -1
  178. package/dist/vendor-response.d.ts +1 -1
  179. package/dist/vendor-response.js +1 -1
  180. package/dist/vendor-response.js.map +1 -1
  181. package/dist/voice-admission.d.ts +1450 -498
  182. package/dist/voice-admission.js +22 -5
  183. package/dist/voice-admission.js.map +1 -1
  184. package/dist/voice-listing.d.ts +4 -4
  185. package/dist/voice-listing.js +4 -5
  186. package/dist/voice-listing.js.map +1 -1
  187. package/dist/voice-pace.js +1 -1
  188. package/dist/voice-pace.js.map +1 -1
  189. package/dist/voices.d.ts +12 -12
  190. package/dist/voices.js +41 -20
  191. package/dist/voices.js.map +1 -1
  192. package/dist/workflows/methods/faceless-explainer.d.ts +612 -15
  193. package/dist/workflows/methods/kinetic-launch.d.ts +612 -15
  194. package/dist/workflows/methods/kinetic-launch.js +1 -1
  195. package/dist/workflows/methods/product-image-story.d.ts +612 -15
  196. package/dist/workflows/methods/reference-remake.d.ts +612 -15
  197. package/dist/workflows/methods/shared.d.ts +612 -15
  198. package/dist/workflows/methods/shared.js +2 -2
  199. package/dist/workflows/methods/shared.js.map +1 -1
  200. package/dist/workflows/methods/ugc-faq-answer.d.ts +612 -15
  201. package/dist/workflows/methods/ugc-product-intro.d.ts +612 -15
  202. package/dist/workflows/methods/website-proof-demo.d.ts +612 -15
  203. package/dist/workflows/methods/website-proof-demo.js +1 -1
  204. package/dist/workflows/reference-remake.d.ts +152 -35
  205. package/dist/workflows/reference-remake.js +188 -23
  206. package/dist/workflows/reference-remake.js.map +1 -1
  207. package/dist/workflows/validate.js +4 -4
  208. package/dist/workflows/validate.js.map +1 -1
  209. package/package.json +2 -3
  210. package/CHANGELOG.md +0 -1500
@@ -0,0 +1,260 @@
1
+ import { lexicalTokens, quoteOccurrences } from "./semantic-inserts.js";
2
+ import { defaultVoiceOf } from "./voices.js";
3
+ import { layerWordRange } from "./ugc-layers.js";
4
+ // An interview (#972): an off-screen speaker's words inside the script, the presenter answering on screen and holding still while they speak.
5
+ export const INTERVIEW_GAZES = ["camera", "left", "right"];
6
+ export const INTERVIEW_LISTENING = ["freeze", "live"];
7
+ export const MAX_INTERVIEW_TURNS = 12;
8
+ /** The presenter's takes in one interview: one per answer, and one more at each change of gaze. */
9
+ export const MAX_INTERVIEW_TAKES = 10;
10
+ export const MAX_PRESENTER_GAZE = 6;
11
+ /** Past this the presenter holds still long enough to name it. */
12
+ export const INTERVIEW_FREEZE_WARN_SEC = 6;
13
+ /** An off-screen line's length before synthesis, at a conversation's 19 characters a second. */
14
+ export const INTERVIEW_CHARS_PER_SEC = 19;
15
+ /** The conversation's pauses, cut down to a tenth of a second unless pause_trim names others: an interview answers without waiting. */
16
+ export const INTERVIEW_PAUSE_TRIM = Object.freeze({ sentence_end_s: 0.1, comma_s: 0.1, mid_phrase_s: 0.1 });
17
+ /** The off-screen voice when none is named, never the presenter's own. */
18
+ export const DEFAULT_INTERVIEW_VOICE = "en_male_mark";
19
+ export const SECOND_INTERVIEW_VOICE = "en_female_cassidy";
20
+ /** The off-screen speaker's word ranges in script order, adjacent turns joined; a string names the first turn that does not resolve or overlaps. */
21
+ export function interviewTurnRanges(script, turns) {
22
+ const tokens = lexicalTokens(script), ranges = [];
23
+ for (const [index, turn] of turns.entries()) {
24
+ const range = layerWordRange(tokens, { id: "turn", anchor: turn.anchor, cover_words: turn.cover_words });
25
+ if (typeof range === "string")
26
+ return { index, message: range };
27
+ const other = ranges.find(item => item.startWord < range.coverWord && range.startWord < item.coverWord);
28
+ if (other)
29
+ return { index, message: `overlaps turn ${other.index}` };
30
+ ranges.push({ ...range, index });
31
+ }
32
+ const sorted = ranges.sort((a, b) => a.startWord - b.startWord), joined = [];
33
+ for (const { startWord, coverWord } of sorted) {
34
+ const last = joined.at(-1);
35
+ if (last && last.coverWord === startWord)
36
+ last.coverWord = coverWord;
37
+ else
38
+ joined.push({ startWord, coverWord });
39
+ }
40
+ return joined;
41
+ }
42
+ /** The script cut into the lines of the conversation, at word boundaries with each word's punctuation kept, in order. */
43
+ export function interviewTexts(script, turns) {
44
+ const total = lexicalTokens(script).length, cuts = new Set();
45
+ for (const turn of turns) {
46
+ cuts.add(turn.startWord);
47
+ cuts.add(turn.coverWord);
48
+ }
49
+ const boundaries = [...cuts].filter(word => word > 0 && word < total).sort((a, b) => a - b);
50
+ const pieces = splitAtWords(script, boundaries);
51
+ let at = 0;
52
+ return pieces.map((text, index) => {
53
+ const startWord = at, coverWord = boundaries[index] ?? total;
54
+ at = coverWord;
55
+ const speaker = turns.some(turn => turn.startWord <= startWord && startWord < turn.coverWord) ? "off_screen" : "presenter";
56
+ return { speaker, text, startWord, coverWord };
57
+ });
58
+ }
59
+ /** A conversation's pace before synthesis (#991): each line takes a start and a time per word, a short answer reading slower than narration. */
60
+ export const INTERVIEW_LINE_SEC = 0.43;
61
+ export const INTERVIEW_WORD_SEC = 0.39;
62
+ /** An interview's estimated length and the presenter's share of it, line by line. */
63
+ export function interviewSecondsEstimate(script, turns) {
64
+ let totalSec = 0, presenterSec = 0;
65
+ for (const line of interviewTexts(script, turns)) {
66
+ const seconds = INTERVIEW_LINE_SEC + INTERVIEW_WORD_SEC * (line.coverWord - line.startWord);
67
+ totalSec += seconds;
68
+ if (line.speaker === "presenter")
69
+ presenterSec += seconds;
70
+ }
71
+ return { totalSec, presenterSec };
72
+ }
73
+ /** The script split before each lexical word in `boundaries`: whole whitespace chunks where possible, else inside one at the shortest prefix
74
+ * that holds exactly the words before the cut. */
75
+ function splitAtWords(script, boundaries) {
76
+ const chunks = script.split(/(\s+)/u), pieces = [];
77
+ let current = "", words = 0, next = 0;
78
+ for (const chunk of chunks) {
79
+ if (/^\s*$/u.test(chunk)) {
80
+ current += chunk;
81
+ continue;
82
+ }
83
+ let rest = chunk;
84
+ let count = lexicalTokens(rest).length;
85
+ while (next < boundaries.length && words + count > boundaries[next]) {
86
+ const need = boundaries[next] - words;
87
+ if (need <= 0) {
88
+ pieces.push(current);
89
+ current = "";
90
+ }
91
+ else {
92
+ // The longest such prefix, so the punctuation after the last word stays with it.
93
+ const cut = [...Array(rest.length).keys()].map(i => i + 1).findLast(p => lexicalTokens(rest.slice(0, p)).length === need &&
94
+ lexicalTokens(rest.slice(p)).length === count - need);
95
+ pieces.push(current + rest.slice(0, cut));
96
+ current = "";
97
+ rest = rest.slice(cut);
98
+ words += need;
99
+ count -= need;
100
+ }
101
+ next++;
102
+ }
103
+ current += rest;
104
+ words += count;
105
+ }
106
+ pieces.push(current);
107
+ return pieces.map(piece => piece.trim());
108
+ }
109
+ /** Each lexical word's speaker. */
110
+ export function wordSpeakers(total, turns) {
111
+ return Array.from({ length: total }, (_, word) => turns.some(turn => turn.startWord <= word && word < turn.coverWord) ? "off_screen" : "presenter");
112
+ }
113
+ /** The presenter's gaze on each lexical word: the interview's own, else camera, then each presenter_gaze item on its words. */
114
+ export function wordGazes(script, input) {
115
+ const tokens = lexicalTokens(script), gazes = tokens.map(() => input.interview?.gaze ?? "camera");
116
+ for (const item of input.presenter_gaze ?? []) {
117
+ const range = layerWordRange(tokens, { id: "gaze", anchor: item.anchor, cover_words: item.cover_words });
118
+ if (typeof range === "string")
119
+ continue;
120
+ for (let word = range.startWord; word < range.coverWord; word++)
121
+ gazes[word] = item.gaze;
122
+ }
123
+ return gazes;
124
+ }
125
+ /** Every view of the actor the run needs, the main one first. */
126
+ export function gazesNeeded(input) {
127
+ return [...new Set([input.interview?.gaze ?? "camera", ...(input.presenter_gaze ?? []).map(item => item.gaze)])];
128
+ }
129
+ /** The presenter's takes before timing: each run of words on screen is one, and a change of gaze inside a run starts another. */
130
+ export function presenterTakeCount(script, input) {
131
+ const tokens = lexicalTokens(script), turns = input.interview ? interviewTurnRanges(script, input.interview.turns) : [];
132
+ if (!Array.isArray(turns))
133
+ return 0;
134
+ const covered = new Set();
135
+ for (const insert of input.inserts ?? []) {
136
+ const range = layerWordRange(tokens, insert);
137
+ if (typeof range !== "string")
138
+ for (let word = range.startWord; word < range.coverWord; word++)
139
+ covered.add(word);
140
+ }
141
+ const speakers = wordSpeakers(tokens.length, turns), gazes = wordGazes(script, input);
142
+ let takes = 0;
143
+ for (let word = 0; word < tokens.length; word++) {
144
+ const shown = speakers[word] === "presenter" && !covered.has(word);
145
+ const before = word > 0 && speakers[word - 1] === "presenter" && !covered.has(word - 1);
146
+ if (shown && (!before || gazes[word] !== gazes[word - 1]))
147
+ takes++;
148
+ }
149
+ return takes;
150
+ }
151
+ /** The one model that speaks a conversation in one request. */
152
+ export const INTERVIEW_TTS_MODEL = "eleven_v4";
153
+ /** Every refusal of `interview` and `presenter_gaze` before money, named by path. */
154
+ export function interviewRefusals(input) {
155
+ const { interview } = input;
156
+ if (interview === undefined && input.presenter_gaze === undefined)
157
+ return [];
158
+ if (input.script === undefined || input.segments !== undefined || input.call !== undefined) {
159
+ const field = interview ? "interview" : "presenter_gaze";
160
+ return [{ path: [field], message: `${field} needs script and cannot be combined with segments or call` }];
161
+ }
162
+ const refusals = [], tokens = lexicalTokens(input.script);
163
+ let turns = [];
164
+ if (interview) {
165
+ const ranges = interviewTurnRanges(input.script, interview.turns);
166
+ if (!Array.isArray(ranges))
167
+ refusals.push({ path: ["interview", "turns", ranges.index, "anchor"], message: ranges.message });
168
+ else {
169
+ turns = ranges;
170
+ if (turns.reduce((sum, turn) => sum + turn.coverWord - turn.startWord, 0) === tokens.length) {
171
+ refusals.push({ path: ["interview", "turns"], message: "every word is the off-screen speaker's: the presenter needs words" });
172
+ }
173
+ }
174
+ // An actor_id's gender is the pin's, so admission checks its default voice (#972 I2); an unknown gender speaks the default actor's voice.
175
+ const presenter = input.actor_id === undefined || input.voice !== undefined
176
+ ? interviewPresenterVoice(input, input.image === undefined ? undefined : input.actor_gender) : undefined;
177
+ if (interview.off_screen?.voice !== undefined && interview.off_screen.voice === presenter) {
178
+ refusals.push({ path: ["interview", "off_screen", "voice"], message: INTERVIEW_SHARED_VOICE_REFUSAL });
179
+ }
180
+ if (input.tts_model !== undefined && input.tts_model !== INTERVIEW_TTS_MODEL) {
181
+ refusals.push({ path: ["tts_model"], message: `an interview speaks both voices as one conversation on ${INTERVIEW_TTS_MODEL}: omit tts_model or pass ${INTERVIEW_TTS_MODEL}` });
182
+ }
183
+ if (interview.listening === "live") {
184
+ refusals.push({ path: ["interview", "listening"], message: "listening live is not offered yet: omit listening, and the presenter holds still while the off-screen speaker talks" });
185
+ }
186
+ if (interview.off_screen?.caption !== undefined && input.captions !== true) {
187
+ refusals.push({ path: ["interview", "off_screen", "caption"], message: "interview.off_screen.caption requires captions=true: it styles the off-screen speaker's captions" });
188
+ }
189
+ if (interview.gaze !== undefined && interview.gaze !== "camera" && input.actor_id === undefined) {
190
+ refusals.push({ path: ["interview", "gaze"], message: "interview.gaze needs actor_id; list_actors shows each actor's views" });
191
+ }
192
+ }
193
+ const off = wordSpeakers(tokens.length, turns), gazed = [];
194
+ for (const [index, item] of (input.presenter_gaze ?? []).entries()) {
195
+ if (input.actor_id === undefined) {
196
+ refusals.push({ path: ["presenter_gaze", index], message: `presenter_gaze[${index}]: needs actor_id; list_actors shows each actor's views` });
197
+ continue;
198
+ }
199
+ const range = layerWordRange(tokens, { id: "gaze", anchor: item.anchor, cover_words: item.cover_words });
200
+ if (typeof range === "string") {
201
+ refusals.push({ path: ["presenter_gaze", index, "anchor"], message: range });
202
+ continue;
203
+ }
204
+ if (off.slice(range.startWord, range.coverWord).includes("off_screen")) {
205
+ refusals.push({ path: ["presenter_gaze", index, "anchor"], message: "the presenter looks where they speak: these words are the off-screen speaker's" });
206
+ }
207
+ if (gazed.some(other => other.startWord < range.coverWord && range.startWord < other.coverWord)) {
208
+ refusals.push({ path: ["presenter_gaze", index, "anchor"], message: "overlaps an earlier presenter_gaze item: one gaze holds a word" });
209
+ }
210
+ gazed.push(range);
211
+ }
212
+ if (interview && input.captions === true) {
213
+ for (const [index, item] of (input.caption_emphasis ?? []).entries()) {
214
+ const quote = typeof item === "string" ? item : item.quote;
215
+ if (quoteOccurrences(tokens, quote).some(match => off.slice(match.startWord, match.endWord).includes("off_screen"))) {
216
+ refusals.push({ path: ["caption_emphasis", index], message: `"${quote}" is spoken off screen; emphasis marks the presenter's words` });
217
+ }
218
+ }
219
+ }
220
+ if (!refusals.length) {
221
+ const takes = presenterTakeCount(input.script, input), cap = interview ? MAX_INTERVIEW_TAKES : undefined;
222
+ if (cap !== undefined && takes > cap) {
223
+ refusals.push({ path: ["interview"], message: `the presenter appears in ${takes} takes, more than ${cap}; merge answers or drop a change of gaze` });
224
+ }
225
+ }
226
+ return refusals;
227
+ }
228
+ /** What an interview does differently from what was asked, named before money (rule 3). */
229
+ export function interviewWarnings(input) {
230
+ const interview = input.interview;
231
+ if (typeof input.script !== "string" || !interview || !Array.isArray(interview.turns))
232
+ return [];
233
+ const turns = interviewTurnRanges(input.script, interview.turns);
234
+ if (!Array.isArray(turns))
235
+ return [];
236
+ const warnings = [];
237
+ const lines = interviewTexts(input.script, turns).filter(line => line.speaker === "off_screen");
238
+ const longest = Math.max(0, ...lines.map(line => line.text.length / INTERVIEW_CHARS_PER_SEC));
239
+ if (longest > INTERVIEW_FREEZE_WARN_SEC) {
240
+ warnings.push(`the presenter holds still for about ${longest.toFixed(1)} s while the off-screen speaker talks`);
241
+ }
242
+ if (turns[0]?.startWord === 0)
243
+ warnings.push("the opening question freezes the presenter on the first frame of their first answer");
244
+ if (input.voice_pace !== undefined) {
245
+ warnings.push("voice_pace does not change an interview: both voices speak as one conversation at their own pace; list_voices names each voice's words_per_second");
246
+ }
247
+ return warnings;
248
+ }
249
+ export const INTERVIEW_SHARED_VOICE_REFUSAL = "the off-screen speaker needs a voice other than the presenter's";
250
+ /** The presenter's voice by name: the named one, else its model's default for the gender; a raw voice_id has no name. */
251
+ export function interviewPresenterVoice(input, gender) {
252
+ if (input.voice_id !== undefined)
253
+ return undefined;
254
+ return input.voice ?? defaultVoiceOf(input.tts_model, gender).name;
255
+ }
256
+ /** The off-screen voice: the named one, else the default, kept off the presenter's voice; the server compares by vendor id (#987). */
257
+ export function interviewOffScreenVoice(interview, speaksPresenterVoice) {
258
+ return interview.off_screen?.voice ?? (speaksPresenterVoice(DEFAULT_INTERVIEW_VOICE) ? SECOND_INTERVIEW_VOICE : DEFAULT_INTERVIEW_VOICE);
259
+ }
260
+ //# sourceMappingURL=ugc-interview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ugc-interview.js","sourceRoot":"","sources":["../src/ugc-interview.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,15 @@
1
+ import { CAPTION_POSITION_VERTICAL } from "./caption-geometry.js";
2
+ import { type CaptionPlace, type Place, type PresenterPlace } from "./scene-place.js";
1
3
  import type { WordTiming } from "./tts-backend.js";
2
4
  export declare const OVERLAY_POSITIONS: readonly ["top_left", "top_right", "bottom_left", "bottom_right", "top", "bottom"];
3
5
  export type OverlayPosition = (typeof OVERLAY_POSITIONS)[number];
4
- export declare const LAYER_ENTERS: readonly ["cut", "fade", "slide", "tilt_in"];
6
+ export declare const LAYER_ENTERS: readonly ["cut", "fade", "slide", "tilt_in", "pop", "scale_up"];
5
7
  export type LayerEnter = (typeof LAYER_ENTERS)[number];
8
+ /** How an overlay leaves (#973 S3); absent is a cut, as every overlay before it. */
9
+ export declare const LAYER_EXITS: readonly ["cut", "fade", "pop_out", "slide"];
10
+ export type LayerExit = (typeof LAYER_EXITS)[number];
11
+ /** The most an overlay's appearance moves off its first word, in seconds. */
12
+ export declare const MAX_ENTER_OFFSET_S = 0.5;
6
13
  export declare const LAYOUT_WINDOW_KINDS: readonly ["split", "card"];
7
14
  export type LayoutWindowKind = (typeof LAYOUT_WINDOW_KINDS)[number];
8
15
  export declare const INSERT_TRANSITIONS: readonly ["cut", "wipe", "flash", "zoom"];
@@ -57,24 +64,99 @@ export interface LayerRefusal {
57
64
  path: (string | number)[];
58
65
  message: string;
59
66
  }
67
+ /** An overlay at a preset position or at a place: exactly one of the two. */
68
+ /** A template drawn over the presenter carries `own`, the rect its kind draws (#973 S4): its box without a place, its shape scaled whole with one. */
69
+ export type PlaceableOverlay = AnchoredItem & {
70
+ position?: OverlayPosition | undefined;
71
+ place?: Place | undefined;
72
+ own?: LayerRect | undefined;
73
+ };
74
+ /** The templates a scene adds to the overlays for one framing; templates/index.ts gives them, which this module cannot import. */
75
+ export type SceneExtras = (framing: PresenterFraming) => readonly PlaceableOverlay[];
60
76
  export interface LayerCheckInput {
61
77
  script: string;
62
78
  aspect_ratio?: string | undefined;
79
+ presenter_framing?: PresenterFraming | undefined;
80
+ actor_id?: string | undefined;
63
81
  inserts?: readonly AnchoredItem[] | undefined;
64
- overlays?: readonly (AnchoredItem & {
65
- position: OverlayPosition;
66
- })[] | undefined;
82
+ overlays?: readonly PlaceableOverlay[] | undefined;
67
83
  layout_windows?: readonly (AnchoredItem & {
68
84
  layout: LayoutWindowKind;
69
85
  })[] | undefined;
86
+ captions?: boolean | undefined;
87
+ caption_style?: string | undefined;
88
+ caption_position?: keyof typeof CAPTION_POSITION_VERTICAL | undefined;
89
+ caption_place?: CaptionPlace | undefined;
90
+ presenter_place?: PresenterPlace | undefined;
91
+ }
92
+ /** What a placed overlay may stand by at admission: the planned face and, with captions, the tallest page's box where they sit (#973 S2). */
93
+ export interface AdmissionScene {
94
+ face: LayerRect;
95
+ captions?: LayerRect | undefined;
70
96
  }
71
- /** Every refusal of overlays and layout windows against the script, named by path; empty when they render. */
72
- export declare function layerRefusals(input: LayerCheckInput): LayerRefusal[];
97
+ export declare function admissionScene(input: Pick<LayerCheckInput, "captions" | "caption_style" | "caption_position" | "caption_place" | "presenter_place">, aspectRatio: string, framing: PresenterFraming): AdmissionScene;
98
+ /** The sides a place may take next to the captions: a page grows sideways with its words. */
99
+ export declare const CAPTION_SIDES: readonly string[];
100
+ /** The framings an admitted run may render: a wide request may render close when the actor has no wide view; wide needs an actor and 9:16. */
101
+ export declare function admissionFramings(input: {
102
+ aspect_ratio?: string | undefined;
103
+ presenter_framing?: unknown;
104
+ actor_id?: unknown;
105
+ }): PresenterFraming[];
106
+ /** How many layers a place leans on through `{ layer }`, Infinity in a loop or past a missing or preset anchor; a template is an anchor as drawn. */
107
+ export declare function placeDepth(overlays: readonly PlaceableOverlay[], id: string, seen?: ReadonlySet<string>): number;
108
+ /** A template's own rect in pixels: the shape its place scales it to. */
109
+ export declare const ownPixels: (own: LayerRect, canvas: {
110
+ width: number;
111
+ height: number;
112
+ }) => {
113
+ width: number;
114
+ height: number;
115
+ };
116
+ /** Each layer's box at admission, by id: a preset's footprint, a template's own rect, a place resolved on the usual face (a template's shape scaled
117
+ * whole into it); a place on a broken chain has none. */
118
+ export declare function overlayFootprints(overlays: readonly PlaceableOverlay[], aspectRatio: string, framing: PresenterFraming, scene?: AdmissionScene): Map<string, LayerRect>;
119
+ /** Over this share of the face's box a placed overlay covers the face; under it, it touches the edge (#973 S1). */
120
+ export declare const FACE_COVER_SHARE = 0.1;
121
+ /** Under this share of the frame's short side an overlay would not read. */
122
+ export declare const OVERLAY_MIN_SIDE = 0.03;
123
+ /** Over this share of the frame an overlay hides a presenter who is still billed. */
124
+ export declare const OVERLAY_COVERED_PRESENTER = 0.6;
125
+ /** Admission warnings for placed overlays and templates: a box at the face's edge, and a box that hides most of a billed presenter. */
126
+ export declare function placeWarnings(input: {
127
+ overlays?: unknown;
128
+ aspect_ratio?: unknown;
129
+ presenter_framing?: unknown;
130
+ actor_id?: unknown;
131
+ }, extras?: SceneExtras): string[];
132
+ /** The refusals a placed overlay or template meets on its anchor and on its box in every framing, at the path `at` names (#973 S1, S4). */
133
+ export declare function placedRefusals(what: "overlay" | "template", item: PlaceableOverlay & {
134
+ place: Place;
135
+ }, range: WordRange, at: (...rest: string[]) => (string | number)[], scene: {
136
+ items: readonly PlaceableOverlay[];
137
+ tokens: readonly string[];
138
+ footprints: readonly {
139
+ boxes: ReadonlyMap<string, LayerRect>;
140
+ face: LayerRect;
141
+ }[];
142
+ canvas: {
143
+ width: number;
144
+ height: number;
145
+ };
146
+ }): LayerRefusal[];
147
+ /** Every refusal of overlays and layout windows against the script, named by path; empty when they render. `extras` adds the run's templates. */
148
+ export declare function layerRefusals(input: LayerCheckInput, extras?: SceneExtras): LayerRefusal[];
73
149
  export interface LayerFrames {
74
150
  id: string;
75
151
  startFrame: number;
76
152
  endFrame: number;
77
153
  }
154
+ /** Each overlay's first frame moved by its enter_offset_s (#973 S3), inside its own frames and the video. Overlays that left on or before its first */
155
+ /** word and still show then leave as it enters, so no more overlays share the screen than their words allow. */
156
+ export declare function offsetOverlayFrames(frames: readonly LayerFrames[], overlays: readonly {
157
+ id: string;
158
+ enter_offset_s?: number | undefined;
159
+ }[], fps: number, warnings: string[]): LayerFrames[];
78
160
  /** Frames of each word range on the run's narration, by the rule inserts follow: a range ends where its first uncovered word starts. */
79
161
  export declare function resolveLayerFrames(input: {
80
162
  tokens: readonly string[];