@cueframe/kernel 0.2.52 → 0.2.54
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/dist/_members/composition/fonts/bundledFaces.d.ts +9 -15
- package/dist/_members/composition/fonts/captionFaces.d.ts +2 -3
- package/dist/_members/composition/ops/captionOps.d.ts +11 -0
- package/dist/_members/composition/ops/compositionOps.d.ts +20 -19
- package/dist/_members/composition/ops/compositionOps.shared.d.ts +1 -0
- package/dist/_members/composition/validators/composition.d.ts +724 -0
- package/dist/_members/composition/validators/registry.d.ts +1 -1
- package/dist/_members/composition/validators/render.d.ts +332 -0
- package/dist/_members/composition-ops/index.d.ts +89 -0
- package/dist/_members/core/render/compositionAudioAndDepth.d.ts +3 -2
- package/dist/_members/core/render/index.d.ts +1 -1
- package/dist/_members/core/render/types.d.ts +3 -1
- package/dist/_members/plane/contract.d.ts +1 -1
- package/dist/_members/primitives/captions/Captions.d.ts +18 -1
- package/dist/_members/primitives/captions/index.d.ts +1 -1
- package/dist/_members/primitives/lib/text/spec.d.ts +1 -0
- package/dist/animate.js +2 -2
- package/dist/authoring/build-tools.js +6 -6
- package/dist/authoring/context.js +5 -5
- package/dist/authoring/tools.js +5 -5
- package/dist/authoring.js +9 -9
- package/dist/{chunk-MYBK6DKF.js → chunk-2BVKNYRB.js} +1 -1
- package/dist/{chunk-AVTEPAWI.js → chunk-7RGDRDAR.js} +17 -13
- package/dist/{chunk-7XZW26U2.js → chunk-AONWKKXK.js} +1 -1
- package/dist/{chunk-WZ22ZYXD.js → chunk-C3ARYFN6.js} +4 -4
- package/dist/{chunk-4B4V3HYW.js → chunk-C6ONUJIO.js} +1 -1
- package/dist/{chunk-CZOVEX2D.js → chunk-CR3G2JQP.js} +1 -1
- package/dist/{chunk-2PU2TSUG.js → chunk-D5E5XFHK.js} +1 -1
- package/dist/{chunk-D2EG7J7X.js → chunk-DFB7UFZD.js} +1 -1
- package/dist/{chunk-FSEB4LSU.js → chunk-FYMXVYWS.js} +1 -1
- package/dist/{chunk-6WQHVYJD.js → chunk-G7ZSFSQG.js} +1 -1
- package/dist/{chunk-5ZQLMPDY.js → chunk-GAACUQAB.js} +1 -1
- package/dist/{chunk-3I43W7DP.js → chunk-GZMKTLO3.js} +52 -21
- package/dist/{chunk-QVBUYWW6.js → chunk-Q2FWFTDZ.js} +1 -1
- package/dist/{chunk-MBSQKRDF.js → chunk-QCGT3M7M.js} +2 -2
- package/dist/{chunk-KMDZDH5E.js → chunk-QCJUGKRC.js} +4 -4
- package/dist/{chunk-Z6NY6MCL.js → chunk-RMLGMYEJ.js} +1 -1
- package/dist/{chunk-IHXMBXXL.js → chunk-SIGKJOSF.js} +30 -4
- package/dist/{chunk-5JCLZPMV.js → chunk-T7WKIMTB.js} +63 -44
- package/dist/{chunk-ACURZCPN.js → chunk-UKKY7HWN.js} +1 -1
- package/dist/{chunk-2M65KQNG.js → chunk-V6GL37RZ.js} +394 -54
- package/dist/{chunk-CV3QQUMK.js → chunk-VKZTGD5Z.js} +128 -5
- package/dist/{chunk-JWW54N24.js → chunk-VYSBZUXZ.js} +1 -1
- package/dist/{chunk-3OG2674K.js → chunk-ZDE5S3DE.js} +1 -1
- package/dist/component-runtime/render.js +2 -2
- package/dist/component-runtime.js +3 -3
- package/dist/compose.js +5 -5
- package/dist/composition/fonts.js +1 -1
- package/dist/composition/graphics-plan.js +3 -3
- package/dist/composition/ops.js +4 -4
- package/dist/composition/projection.js +3 -3
- package/dist/composition/validators.js +13 -3
- package/dist/composition-ops.js +8 -8
- package/dist/composition.js +15 -5
- package/dist/{context-2MBCDTCZ.js → context-I7SPXR2Z.js} +5 -5
- package/dist/core/render.js +4 -4
- package/dist/core.js +4 -4
- package/dist/mcp/adapter.js +2 -2
- package/dist/mcp/core.js +1 -1
- package/dist/mcp/scene-shot.js +2 -2
- package/dist/mcp/server.js +12 -12
- package/dist/mcp.js +12 -12
- package/dist/primitives/captions.js +276 -44
- package/dist/primitives/effects.js +3 -3
- package/dist/primitives/layouts.js +3 -3
- package/dist/primitives/lib/text/marker.js +1 -1
- package/dist/primitives/scenes.js +3 -3
- package/dist/primitives.js +5 -5
- package/dist/render-harness/cardFonts.js +2 -2
- package/dist/render-harness.js +7 -7
- package/package.json +10 -10
package/dist/mcp/server.js
CHANGED
|
@@ -8,26 +8,26 @@ import {
|
|
|
8
8
|
registerRawTools,
|
|
9
9
|
registerSkillPrompts,
|
|
10
10
|
titleCase
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-C3ARYFN6.js";
|
|
12
|
+
import "../chunk-ZDE5S3DE.js";
|
|
13
|
+
import "../chunk-VYSBZUXZ.js";
|
|
14
14
|
import "../chunk-4WBSXHQA.js";
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
17
|
-
import "../chunk-
|
|
15
|
+
import "../chunk-V6GL37RZ.js";
|
|
16
|
+
import "../chunk-SIGKJOSF.js";
|
|
17
|
+
import "../chunk-GZMKTLO3.js";
|
|
18
18
|
import "../chunk-QH3YI3ND.js";
|
|
19
19
|
import "../chunk-JPMVNMF3.js";
|
|
20
20
|
import "../chunk-IMIUHG2E.js";
|
|
21
21
|
import "../chunk-VZ7TYX6Z.js";
|
|
22
22
|
import "../chunk-T56BK7NS.js";
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-
|
|
23
|
+
import "../chunk-T7WKIMTB.js";
|
|
24
|
+
import "../chunk-QCGT3M7M.js";
|
|
25
|
+
import "../chunk-VKZTGD5Z.js";
|
|
26
26
|
import "../chunk-WPZKOVYF.js";
|
|
27
27
|
import "../chunk-B7J5UUUV.js";
|
|
28
28
|
import "../chunk-KYRDKK2D.js";
|
|
29
|
-
import "../chunk-
|
|
30
|
-
import "../chunk-
|
|
29
|
+
import "../chunk-G7ZSFSQG.js";
|
|
30
|
+
import "../chunk-RMLGMYEJ.js";
|
|
31
31
|
import "../chunk-WREYUH2E.js";
|
|
32
32
|
import "../chunk-ILO4NEZ3.js";
|
|
33
33
|
import "../chunk-E63UEO5C.js";
|
|
@@ -35,7 +35,7 @@ import "../chunk-7PA7FGLD.js";
|
|
|
35
35
|
import "../chunk-VG2ND6PX.js";
|
|
36
36
|
import "../chunk-CL5Y6V6K.js";
|
|
37
37
|
import "../chunk-2L7PYYJK.js";
|
|
38
|
-
import "../chunk-
|
|
38
|
+
import "../chunk-7RGDRDAR.js";
|
|
39
39
|
import "../chunk-2ESYSVXG.js";
|
|
40
40
|
export {
|
|
41
41
|
RAW_EXCLUDED_OPERATION_IDS,
|
package/dist/mcp.js
CHANGED
|
@@ -8,26 +8,26 @@ import {
|
|
|
8
8
|
buildServer,
|
|
9
9
|
registerCuratedTools,
|
|
10
10
|
registerRawTools
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-C3ARYFN6.js";
|
|
12
|
+
import "./chunk-ZDE5S3DE.js";
|
|
13
|
+
import "./chunk-VYSBZUXZ.js";
|
|
14
14
|
import "./chunk-4WBSXHQA.js";
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-V6GL37RZ.js";
|
|
16
|
+
import "./chunk-SIGKJOSF.js";
|
|
17
|
+
import "./chunk-GZMKTLO3.js";
|
|
18
18
|
import "./chunk-QH3YI3ND.js";
|
|
19
19
|
import "./chunk-JPMVNMF3.js";
|
|
20
20
|
import "./chunk-IMIUHG2E.js";
|
|
21
21
|
import "./chunk-VZ7TYX6Z.js";
|
|
22
22
|
import "./chunk-T56BK7NS.js";
|
|
23
|
-
import "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
23
|
+
import "./chunk-T7WKIMTB.js";
|
|
24
|
+
import "./chunk-QCGT3M7M.js";
|
|
25
|
+
import "./chunk-VKZTGD5Z.js";
|
|
26
26
|
import "./chunk-WPZKOVYF.js";
|
|
27
27
|
import "./chunk-B7J5UUUV.js";
|
|
28
28
|
import "./chunk-KYRDKK2D.js";
|
|
29
|
-
import "./chunk-
|
|
30
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-G7ZSFSQG.js";
|
|
30
|
+
import "./chunk-RMLGMYEJ.js";
|
|
31
31
|
import "./chunk-WREYUH2E.js";
|
|
32
32
|
import "./chunk-ILO4NEZ3.js";
|
|
33
33
|
import "./chunk-E63UEO5C.js";
|
|
@@ -35,7 +35,7 @@ import "./chunk-7PA7FGLD.js";
|
|
|
35
35
|
import "./chunk-VG2ND6PX.js";
|
|
36
36
|
import "./chunk-CL5Y6V6K.js";
|
|
37
37
|
import "./chunk-2L7PYYJK.js";
|
|
38
|
-
import "./chunk-
|
|
38
|
+
import "./chunk-7RGDRDAR.js";
|
|
39
39
|
import "./chunk-2ESYSVXG.js";
|
|
40
40
|
export {
|
|
41
41
|
API_URLS,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Marker
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-DFB7UFZD.js";
|
|
4
4
|
import {
|
|
5
5
|
fillStyle
|
|
6
6
|
} from "../chunk-XLIPPLG3.js";
|
|
@@ -13,13 +13,13 @@ import {
|
|
|
13
13
|
} from "../chunk-W2245F6G.js";
|
|
14
14
|
import {
|
|
15
15
|
resolveCaptionFaces
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-7RGDRDAR.js";
|
|
17
17
|
import "../chunk-2ESYSVXG.js";
|
|
18
18
|
|
|
19
19
|
// ../execution/primitives/src/captions/Captions.tsx
|
|
20
20
|
import { useMemo } from "react";
|
|
21
21
|
import { AbsoluteFill, useCurrentFrame, useVideoConfig, interpolate, Easing } from "remotion";
|
|
22
|
-
import { fillTextBox } from "@remotion/layout-utils";
|
|
22
|
+
import { fillTextBox, measureText } from "@remotion/layout-utils";
|
|
23
23
|
|
|
24
24
|
// ../execution/primitives/src/captions/paginate.ts
|
|
25
25
|
import { createTikTokStyleCaptions } from "@remotion/captions";
|
|
@@ -154,7 +154,32 @@ function plateStyleFor(kind, backgroundColor) {
|
|
|
154
154
|
}
|
|
155
155
|
var COMBINE_TOKENS_MS = 1500;
|
|
156
156
|
var CAPTION_LINGER_MS = 600;
|
|
157
|
-
function
|
|
157
|
+
function measuredTextBox(maxWidth, maxLines, gapPx) {
|
|
158
|
+
const lineWidths = [0];
|
|
159
|
+
return {
|
|
160
|
+
add: (word) => {
|
|
161
|
+
const widthOf = (text) => measureText({ ...word, text }).width;
|
|
162
|
+
const current = lineWidths.length - 1;
|
|
163
|
+
const width = widthOf(lineWidths[current] === 0 ? word.text.trimStart() : word.text);
|
|
164
|
+
const nextWidth = lineWidths[current] + (lineWidths[current] ? gapPx : 0) + width;
|
|
165
|
+
if (Math.ceil(nextWidth) < maxWidth) {
|
|
166
|
+
lineWidths[current] = nextWidth;
|
|
167
|
+
return { exceedsBox: false, newLine: false };
|
|
168
|
+
}
|
|
169
|
+
const firstWidth = widthOf(word.text.trimStart());
|
|
170
|
+
if (current + 1 >= maxLines || Math.ceil(firstWidth) >= maxWidth) {
|
|
171
|
+
return { exceedsBox: true, newLine: false };
|
|
172
|
+
}
|
|
173
|
+
lineWidths.push(firstWidth);
|
|
174
|
+
return { exceedsBox: false, newLine: true };
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function tokenBox(maxWidth, maxLines, fontSize, letterSpacing, wordGapEm, textTransform, emphasis) {
|
|
179
|
+
const needsMeasured = emphasis?.emphasisFontStyle === "italic" || letterSpacing !== 0 || (emphasis?.emphasisLetterSpacing ?? 0) !== 0 || wordGapEm !== void 0 || textTransform !== void 0 && textTransform !== "none" || emphasis?.emphasisTextTransform !== void 0 && emphasis.emphasisTextTransform !== "none";
|
|
180
|
+
return needsMeasured ? measuredTextBox(maxWidth, maxLines, fontSize * (wordGapEm ?? 0.35)) : fillTextBox({ maxBoxWidth: maxWidth, maxLines });
|
|
181
|
+
}
|
|
182
|
+
function addTokenToBox(box, token, fontFamily, fontSize, fontWeight, letterSpacing, textTransform, emphasis) {
|
|
158
183
|
const isEmp = emphasis?.emphasisSet.has(token.fromMs) ?? false;
|
|
159
184
|
const tokenSize = isEmp ? Math.round(fontSize * (emphasis?.emphasisScale ?? 1.2)) : fontSize;
|
|
160
185
|
const tokenWeight = emphasis && isEmp ? emphasis.emphasisFontWeight : fontWeight;
|
|
@@ -163,22 +188,25 @@ function addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis) {
|
|
|
163
188
|
text: token.text,
|
|
164
189
|
fontFamily: tokenFamily,
|
|
165
190
|
fontSize: tokenSize,
|
|
166
|
-
fontWeight: String(tokenWeight)
|
|
191
|
+
fontWeight: String(tokenWeight),
|
|
192
|
+
...(isEmp ? emphasis?.emphasisLetterSpacing : letterSpacing) ? { letterSpacing: `${isEmp ? emphasis?.emphasisLetterSpacing : letterSpacing}px` } : {},
|
|
193
|
+
...isEmp ? { textTransform: emphasis?.emphasisTextTransform } : { textTransform },
|
|
194
|
+
...isEmp && emphasis?.emphasisFontStyle === "italic" ? { additionalStyles: { fontStyle: "italic" } } : {}
|
|
167
195
|
});
|
|
168
196
|
}
|
|
169
|
-
function makeBoxFactory(maxWidth, maxLines, fontFamily, fontSize, fontWeight, emphasis) {
|
|
197
|
+
function makeBoxFactory(maxWidth, maxLines, fontFamily, fontSize, fontWeight, letterSpacing, wordGapEm, textTransform, emphasis) {
|
|
170
198
|
return () => {
|
|
171
|
-
const box =
|
|
199
|
+
const box = tokenBox(maxWidth, maxLines, fontSize, letterSpacing, wordGapEm, textTransform, emphasis);
|
|
172
200
|
return {
|
|
173
|
-
add: (token) => !addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis).exceedsBox
|
|
201
|
+
add: (token) => !addTokenToBox(box, token, fontFamily, fontSize, fontWeight, letterSpacing, textTransform, emphasis).exceedsBox
|
|
174
202
|
};
|
|
175
203
|
};
|
|
176
204
|
}
|
|
177
|
-
function layoutTokensIntoLines(tokens, maxWidth, maxLines, fontFamily, fontSize, fontWeight, emphasis) {
|
|
178
|
-
const box =
|
|
205
|
+
function layoutTokensIntoLines(tokens, maxWidth, maxLines, fontFamily, fontSize, fontWeight, letterSpacing, wordGapEm, textTransform, emphasis) {
|
|
206
|
+
const box = tokenBox(maxWidth, maxLines, fontSize, letterSpacing, wordGapEm, textTransform, emphasis);
|
|
179
207
|
const lines = [[]];
|
|
180
208
|
for (const token of tokens) {
|
|
181
|
-
const result = addTokenToBox(box, token, fontFamily, fontSize, fontWeight, emphasis);
|
|
209
|
+
const result = addTokenToBox(box, token, fontFamily, fontSize, fontWeight, letterSpacing, textTransform, emphasis);
|
|
182
210
|
if (result.newLine) {
|
|
183
211
|
lines.push([token]);
|
|
184
212
|
} else {
|
|
@@ -187,10 +215,73 @@ function layoutTokensIntoLines(tokens, maxWidth, maxLines, fontFamily, fontSize,
|
|
|
187
215
|
}
|
|
188
216
|
return lines.filter((line) => line.length > 0);
|
|
189
217
|
}
|
|
218
|
+
function layoutFitError(label, detail) {
|
|
219
|
+
const error = new Error(`Caption layout${label ? ` ${label}` : " word range"} does not fit one page in its region${detail ? ` (${detail})` : ""}; enlarge the region or split the range`);
|
|
220
|
+
error.name = "CaptionLayoutFitError";
|
|
221
|
+
return error;
|
|
222
|
+
}
|
|
223
|
+
function tokenRuns(tokens, emphasisSet, emphasisPlate) {
|
|
224
|
+
const runs = [];
|
|
225
|
+
for (const token of tokens) {
|
|
226
|
+
const emph = emphasisSet.has(token.fromMs);
|
|
227
|
+
const last = runs[runs.length - 1];
|
|
228
|
+
if (emphasisPlate && emph && last?.emph) last.tokens.push(token);
|
|
229
|
+
else runs.push({ tokens: [token], emph });
|
|
230
|
+
}
|
|
231
|
+
return runs;
|
|
232
|
+
}
|
|
233
|
+
function measureVisualRun(run, fontSize, style, faces) {
|
|
234
|
+
const plate = style.emphasisPlate ?? false;
|
|
235
|
+
const emph = run.emph;
|
|
236
|
+
const text = emph && plate ? run.tokens.map((token) => token.text.trim()).join(" ") : plate ? run.tokens[0].text.trim() : run.tokens[0].text;
|
|
237
|
+
const size = emph ? Math.round(fontSize * (style.emphasisScale ?? 1.08)) : fontSize;
|
|
238
|
+
const transform = emph ? style.emphasisTextTransform ?? style.textTransform : style.textTransform;
|
|
239
|
+
const letterSpacing = emph ? style.emphasisLetterSpacing ?? style.letterSpacing : style.letterSpacing;
|
|
240
|
+
return measureText({
|
|
241
|
+
text,
|
|
242
|
+
fontFamily: emph ? faces.emphasis.stack : faces.base.stack,
|
|
243
|
+
fontSize: size,
|
|
244
|
+
fontWeight: String(emph ? faces.emphasis.weight : faces.base.weight),
|
|
245
|
+
...transform ? { textTransform: transform } : {},
|
|
246
|
+
...letterSpacing !== void 0 ? { letterSpacing: `${letterSpacing}px` } : {},
|
|
247
|
+
...emph && faces.emphasis.style === "italic" ? { additionalStyles: { fontStyle: "italic" } } : {}
|
|
248
|
+
}).width + (emph && plate ? 2 * Math.round(size * (style.emphasisPlatePadX ?? 0.16)) : 0);
|
|
249
|
+
}
|
|
250
|
+
function layoutAuthoredTokensIntoLines(tokens, maxWidth, maxLines, fontSize, style, emphasisSet, faces, label) {
|
|
251
|
+
const lines = [[]];
|
|
252
|
+
let lineWidth = 0;
|
|
253
|
+
const plate = style.emphasisPlate ?? false;
|
|
254
|
+
const runGap = fontSize * (style.wordGapEm ?? 0.35);
|
|
255
|
+
for (const run of tokenRuns(tokens, emphasisSet, plate)) {
|
|
256
|
+
const width = measureVisualRun(run, fontSize, style, faces);
|
|
257
|
+
if (Math.ceil(width) > maxWidth) {
|
|
258
|
+
throw layoutFitError(label, `run needs ${Math.ceil(width)}px, box has ${Math.floor(maxWidth)}px`);
|
|
259
|
+
}
|
|
260
|
+
const current = lines[lines.length - 1];
|
|
261
|
+
const nextWidth = lineWidth + (current.length ? runGap : 0) + width;
|
|
262
|
+
if (Math.ceil(nextWidth) > maxWidth) {
|
|
263
|
+
if (lines.length >= maxLines) {
|
|
264
|
+
throw layoutFitError(label, `needs ${lines.length + 1} lines, box allows ${maxLines}`);
|
|
265
|
+
}
|
|
266
|
+
lines.push([...run.tokens]);
|
|
267
|
+
lineWidth = width;
|
|
268
|
+
} else {
|
|
269
|
+
current.push(...run.tokens);
|
|
270
|
+
lineWidth = nextWidth;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return lines.filter((line) => line.length > 0);
|
|
274
|
+
}
|
|
190
275
|
function Captions({
|
|
191
276
|
segments,
|
|
192
277
|
style: userStyle,
|
|
193
|
-
region
|
|
278
|
+
region,
|
|
279
|
+
holdUntilMs,
|
|
280
|
+
scale,
|
|
281
|
+
rotation,
|
|
282
|
+
syncWordVisibility,
|
|
283
|
+
singlePageRequired,
|
|
284
|
+
layoutLabel
|
|
194
285
|
}) {
|
|
195
286
|
const frame = useCurrentFrame();
|
|
196
287
|
const { fps, width, height } = useVideoConfig();
|
|
@@ -206,7 +297,8 @@ function Captions({
|
|
|
206
297
|
const emphasisFontFamily = faces.emphasis.stack;
|
|
207
298
|
const emphasisFontWeight = faces.emphasis.weight;
|
|
208
299
|
const emphasisTextTransform = style.emphasisTextTransform ?? style.textTransform;
|
|
209
|
-
const
|
|
300
|
+
const letterSpacing = style.letterSpacing ?? 0;
|
|
301
|
+
const emphasisLetterSpacing = style.emphasisLetterSpacing ?? letterSpacing;
|
|
210
302
|
const emphasisFontStyle = faces.emphasis.style;
|
|
211
303
|
const entrance = style.entrance ?? "none";
|
|
212
304
|
const entranceFrames = Math.max(1, Math.round((style.entranceMs ?? 160) / 1e3 * fps));
|
|
@@ -220,17 +312,25 @@ function Captions({
|
|
|
220
312
|
const plateRadius = style.emphasisPlateRadius ?? 6;
|
|
221
313
|
const platePadX = style.emphasisPlatePadX ?? 0.16;
|
|
222
314
|
const platePadY = style.emphasisPlatePadY ?? 0.04;
|
|
315
|
+
const plateReveal = style.emphasisPlateReveal ?? false;
|
|
223
316
|
const annotationColor = style.annotationColor ?? VIOLET;
|
|
317
|
+
const annotationStrokeWidth = style.annotationStrokeWidth ?? 4;
|
|
224
318
|
const maxWidthPercent = style.maxWidthPercent ?? 80;
|
|
225
319
|
const plateStyle = plateStyleFor(style.plate ?? "glass", style.backgroundColor);
|
|
226
320
|
const fontSize = Math.round(height * (style.fontSize / 100));
|
|
321
|
+
const wordGapPx = fontSize * (style.wordGapEm ?? 0.35);
|
|
322
|
+
const lineGapPx = fontSize * (style.lineGapEm ?? 0.25);
|
|
227
323
|
const authoredRegion = userStyle?.region;
|
|
228
324
|
const regionWidth = authoredRegion ? width * authoredRegion.w : width;
|
|
229
325
|
const maxTextWidth = authoredRegion ? Math.min(width * (maxWidthPercent / 100), regionWidth - fontSize * 1.6) : width * (maxWidthPercent / 100);
|
|
230
326
|
const availableHeight = authoredRegion ? height * authoredRegion.h - fontSize * 0.8 : Infinity;
|
|
231
327
|
const lineHeight = fontSize * Math.max(1, emphasisScale) * 1.2;
|
|
232
|
-
const maxLines = authoredRegion ? Math.min(3, Math.floor((availableHeight +
|
|
328
|
+
const maxLines = authoredRegion ? Math.min(3, Math.floor((availableHeight + lineGapPx) / (lineHeight + lineGapPx))) : 3;
|
|
233
329
|
if (authoredRegion && (maxTextWidth <= 0 || maxLines < 1)) {
|
|
330
|
+
if (singlePageRequired) throw layoutFitError(
|
|
331
|
+
layoutLabel,
|
|
332
|
+
maxTextWidth <= 0 ? `box has ${Math.floor(maxTextWidth)}px text width` : "box allows no complete line"
|
|
333
|
+
);
|
|
234
334
|
throw new Error("Caption style.region is too small for one caption line at the authored font size");
|
|
235
335
|
}
|
|
236
336
|
const { emphasisStartMs, annotateKind } = useMemo(() => {
|
|
@@ -243,16 +343,78 @@ function Captions({
|
|
|
243
343
|
return { emphasisStartMs: emph, annotateKind: ann };
|
|
244
344
|
}, [segments]);
|
|
245
345
|
const emphasisLayout = useMemo(
|
|
246
|
-
() => emphasisStartMs.size > 0 ? {
|
|
247
|
-
|
|
346
|
+
() => emphasisStartMs.size > 0 ? {
|
|
347
|
+
emphasisSet: emphasisStartMs,
|
|
348
|
+
emphasisScale,
|
|
349
|
+
emphasisFontFamily,
|
|
350
|
+
emphasisFontWeight,
|
|
351
|
+
emphasisFontStyle,
|
|
352
|
+
emphasisLetterSpacing,
|
|
353
|
+
emphasisTextTransform
|
|
354
|
+
} : void 0,
|
|
355
|
+
[
|
|
356
|
+
emphasisStartMs,
|
|
357
|
+
emphasisScale,
|
|
358
|
+
emphasisFontFamily,
|
|
359
|
+
emphasisFontWeight,
|
|
360
|
+
emphasisFontStyle,
|
|
361
|
+
emphasisLetterSpacing,
|
|
362
|
+
emphasisTextTransform
|
|
363
|
+
]
|
|
248
364
|
);
|
|
249
365
|
const pages = useMemo(
|
|
250
|
-
() =>
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
366
|
+
() => {
|
|
367
|
+
const makeBox = makeBoxFactory(
|
|
368
|
+
maxTextWidth,
|
|
369
|
+
maxLines,
|
|
370
|
+
style.fontFamily,
|
|
371
|
+
fontSize,
|
|
372
|
+
style.fontWeight,
|
|
373
|
+
letterSpacing,
|
|
374
|
+
style.wordGapEm,
|
|
375
|
+
style.textTransform,
|
|
376
|
+
emphasisLayout
|
|
377
|
+
);
|
|
378
|
+
const paginated = paginateCaptionSegments(segments, {
|
|
379
|
+
combineMs: singlePageRequired ? Number.MAX_SAFE_INTEGER : COMBINE_TOKENS_MS,
|
|
380
|
+
makeBox: singlePageRequired ? () => ({ add: () => true }) : makeBox,
|
|
381
|
+
lingerMs: CAPTION_LINGER_MS
|
|
382
|
+
});
|
|
383
|
+
if (singlePageRequired) {
|
|
384
|
+
if (paginated.length !== 1) {
|
|
385
|
+
throw layoutFitError(layoutLabel);
|
|
386
|
+
}
|
|
387
|
+
layoutAuthoredTokensIntoLines(
|
|
388
|
+
paginated[0].tokens,
|
|
389
|
+
maxTextWidth,
|
|
390
|
+
maxLines,
|
|
391
|
+
fontSize,
|
|
392
|
+
style,
|
|
393
|
+
emphasisStartMs,
|
|
394
|
+
faces,
|
|
395
|
+
layoutLabel
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
if (holdUntilMs !== void 0 && paginated.length > 0) {
|
|
399
|
+
const last = paginated[paginated.length - 1];
|
|
400
|
+
last.durationMs = Math.max(1, holdUntilMs - last.startMs);
|
|
401
|
+
}
|
|
402
|
+
return paginated;
|
|
403
|
+
},
|
|
404
|
+
[
|
|
405
|
+
segments,
|
|
406
|
+
maxTextWidth,
|
|
407
|
+
maxLines,
|
|
408
|
+
fontSize,
|
|
409
|
+
style,
|
|
410
|
+
emphasisStartMs,
|
|
411
|
+
faces,
|
|
412
|
+
emphasisLayout,
|
|
413
|
+
letterSpacing,
|
|
414
|
+
holdUntilMs,
|
|
415
|
+
singlePageRequired,
|
|
416
|
+
layoutLabel
|
|
417
|
+
]
|
|
256
418
|
);
|
|
257
419
|
if (pages.length === 0) return null;
|
|
258
420
|
const currentTimeMs = frame / fps * 1e3;
|
|
@@ -277,16 +439,32 @@ function Captions({
|
|
|
277
439
|
extrapolateLeft: "clamp",
|
|
278
440
|
extrapolateRight: "clamp"
|
|
279
441
|
}) : 1;
|
|
280
|
-
const lines =
|
|
442
|
+
const lines = singlePageRequired ? layoutAuthoredTokensIntoLines(
|
|
443
|
+
currentPage.tokens,
|
|
444
|
+
maxTextWidth,
|
|
445
|
+
maxLines,
|
|
446
|
+
fontSize,
|
|
447
|
+
style,
|
|
448
|
+
emphasisStartMs,
|
|
449
|
+
faces,
|
|
450
|
+
layoutLabel
|
|
451
|
+
) : layoutTokensIntoLines(
|
|
281
452
|
currentPage.tokens,
|
|
282
453
|
maxTextWidth,
|
|
283
454
|
maxLines,
|
|
284
455
|
style.fontFamily,
|
|
285
456
|
fontSize,
|
|
286
457
|
style.fontWeight,
|
|
458
|
+
letterSpacing,
|
|
459
|
+
style.wordGapEm,
|
|
460
|
+
style.textTransform,
|
|
287
461
|
emphasisLayout
|
|
288
462
|
);
|
|
289
463
|
const wrapperStyle = resolveCaptionPlacement(userStyle?.position, region, authoredRegion);
|
|
464
|
+
if (scale !== void 0 || rotation !== void 0) {
|
|
465
|
+
wrapperStyle.transform = `${wrapperStyle.transform ?? ""} rotate(${rotation ?? 0}deg) scale(${scale ?? 1})`.trim();
|
|
466
|
+
wrapperStyle.transformOrigin = "top left";
|
|
467
|
+
}
|
|
290
468
|
return /* @__PURE__ */ React.createElement(AbsoluteFill, { style: { pointerEvents: "none" } }, /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement(
|
|
291
469
|
"div",
|
|
292
470
|
{
|
|
@@ -295,7 +473,7 @@ function Captions({
|
|
|
295
473
|
display: "flex",
|
|
296
474
|
flexDirection: "column",
|
|
297
475
|
alignItems: authoredRegion ? "flex-start" : "center",
|
|
298
|
-
gap: `${
|
|
476
|
+
gap: `${lineGapPx}px`,
|
|
299
477
|
padding: `${fontSize * 0.4}px ${fontSize * 0.8}px`,
|
|
300
478
|
borderRadius: fontSize * 0.5,
|
|
301
479
|
...plateStyle,
|
|
@@ -315,8 +493,8 @@ function Captions({
|
|
|
315
493
|
if (entrance === "none") return { opacity: 1, scale: 1, y: 0 };
|
|
316
494
|
const start = tokenStartFrame.get(first) ?? 0;
|
|
317
495
|
if (entrance === "word-pop") {
|
|
318
|
-
const { opacity, scale } = wordPop(frame, fps, start, entranceFrames, isEmph ? 0.86 : 0.92);
|
|
319
|
-
return { opacity, scale, y: 0 };
|
|
496
|
+
const { opacity, scale: scale2 } = wordPop(frame, fps, start, entranceFrames, isEmph ? 0.86 : 0.92);
|
|
497
|
+
return { opacity, scale: scale2, y: 0 };
|
|
320
498
|
}
|
|
321
499
|
if (entrance === "stagger-up") {
|
|
322
500
|
const y = interpolate(frame, [start, start + entranceFrames], [RISE_PX, 0], {
|
|
@@ -332,21 +510,18 @@ function Captions({
|
|
|
332
510
|
return { opacity: 1, scale: 1, y: 0 };
|
|
333
511
|
};
|
|
334
512
|
return lines.map((line, lineIdx) => {
|
|
335
|
-
const segs =
|
|
336
|
-
|
|
337
|
-
const e = emphasisStartMs.has(t.fromMs);
|
|
338
|
-
const last = segs[segs.length - 1];
|
|
339
|
-
if (emphasisPlate && e && last && last.emph) last.tokens.push(t);
|
|
340
|
-
else segs.push({ tokens: [t], emph: e });
|
|
341
|
-
}
|
|
342
|
-
return /* @__PURE__ */ React.createElement("div", { key: lineIdx, style: { display: "flex", justifyContent: authoredRegion ? "flex-start" : "center", alignItems: "baseline", gap: `${fontSize * 0.35}px` } }, segs.map((seg, si) => {
|
|
513
|
+
const segs = tokenRuns(line, emphasisStartMs, emphasisPlate);
|
|
514
|
+
return /* @__PURE__ */ React.createElement("div", { key: lineIdx, style: { display: "flex", justifyContent: authoredRegion ? "flex-start" : "center", alignItems: "baseline", gap: `${wordGapPx}px` } }, segs.map((seg, si) => {
|
|
343
515
|
const first = seg.tokens[0];
|
|
344
|
-
const
|
|
345
|
-
const
|
|
346
|
-
const
|
|
516
|
+
const entered = entranceOf(first, seg.emph);
|
|
517
|
+
const opacity = syncWordVisibility && currentTimeMs < first.fromMs ? 0 : entered.opacity;
|
|
518
|
+
const { scale: scale2, y } = entered;
|
|
519
|
+
const entranceTransform = `translateY(${y}px) scale(${scale2})`;
|
|
520
|
+
const annotatedToken = seg.tokens.find((token2) => annotateKind.has(token2.fromMs));
|
|
521
|
+
const annKind = annotatedToken ? annotateKind.get(annotatedToken.fromMs) : void 0;
|
|
347
522
|
let markerP = 1;
|
|
348
|
-
if (annKind && entrance !== "none") {
|
|
349
|
-
const ms = (tokenStartFrame.get(
|
|
523
|
+
if (annKind && annotatedToken && entrance !== "none") {
|
|
524
|
+
const ms = (tokenStartFrame.get(annotatedToken) ?? 0) + Math.round(fps * 0.14);
|
|
350
525
|
markerP = interpolate(frame, [ms, ms + Math.round(fps * 0.32)], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
|
|
351
526
|
}
|
|
352
527
|
if (seg.emph && emphasisPlate) {
|
|
@@ -354,7 +529,16 @@ function Captions({
|
|
|
354
529
|
const bg = idx % 2 === 0 ? plateColor : plateAltColor;
|
|
355
530
|
const fg = idx % 2 === 0 ? plateTextColor : plateAltTextColor;
|
|
356
531
|
const efs = Math.round(fontSize * emphasisScale);
|
|
357
|
-
|
|
532
|
+
const plateTokens = plateReveal ? seg.tokens.filter((token2) => currentTimeMs >= token2.fromMs) : seg.tokens;
|
|
533
|
+
const reservedWidth = plateReveal ? measureVisualRun(seg, fontSize, style, faces) : void 0;
|
|
534
|
+
return /* @__PURE__ */ React.createElement("span", { key: si, style: {
|
|
535
|
+
position: "relative",
|
|
536
|
+
display: "inline-block",
|
|
537
|
+
...reservedWidth !== void 0 ? { width: reservedWidth } : {},
|
|
538
|
+
opacity,
|
|
539
|
+
transform: entranceTransform,
|
|
540
|
+
transformOrigin: "center"
|
|
541
|
+
} }, /* @__PURE__ */ React.createElement(
|
|
358
542
|
"span",
|
|
359
543
|
{
|
|
360
544
|
style: {
|
|
@@ -373,8 +557,10 @@ function Captions({
|
|
|
373
557
|
whiteSpace: "nowrap"
|
|
374
558
|
}
|
|
375
559
|
},
|
|
376
|
-
|
|
377
|
-
|
|
560
|
+
plateTokens.map((token2, tokenIndex) => /* @__PURE__ */ React.createElement("span", { key: token2.fromMs, style: {
|
|
561
|
+
opacity: syncWordVisibility && tokenIndex > 0 ? currentTimeMs < token2.fromMs ? 0 : entranceOf(token2, true).opacity : 1
|
|
562
|
+
} }, tokenIndex > 0 ? " " : "", token2.text.trim()))
|
|
563
|
+
), annKind && annotatedToken && currentTimeMs >= annotatedToken.fromMs ? /* @__PURE__ */ React.createElement(Marker, { spec: { kind: annKind, color: annotationColor, strokeWidth: annotationStrokeWidth }, progress: markerP }) : null);
|
|
378
564
|
}
|
|
379
565
|
const token = first;
|
|
380
566
|
const isActive = token === activeToken;
|
|
@@ -383,7 +569,7 @@ function Captions({
|
|
|
383
569
|
const tokenWeight = isEmphasis ? emphasisFontWeight : style.fontWeight;
|
|
384
570
|
const tokenFamily = isEmphasis ? emphasisFontFamily : style.fontFamily;
|
|
385
571
|
const tokenTransform = isEmphasis ? emphasisTextTransform : style.textTransform;
|
|
386
|
-
const tokenLetterSpacing = isEmphasis
|
|
572
|
+
const tokenLetterSpacing = isEmphasis ? emphasisLetterSpacing ? `${emphasisLetterSpacing}px` : void 0 : letterSpacing ? `${letterSpacing}px` : void 0;
|
|
387
573
|
const tokenFontStyle = isEmphasis ? emphasisFontStyle : "normal";
|
|
388
574
|
let tokenColor = style.color;
|
|
389
575
|
if (isActive && !emphasisPlate) tokenColor = style.highlightColor;
|
|
@@ -406,12 +592,58 @@ function Captions({
|
|
|
406
592
|
},
|
|
407
593
|
emphasisPlate ? token.text.trim() : token.text
|
|
408
594
|
);
|
|
409
|
-
return /* @__PURE__ */ React.createElement("span", { key: si, style: { position: "relative", display: "inline-block", opacity, transform: entranceTransform, transformOrigin: "center" } }, inner, annKind ? /* @__PURE__ */ React.createElement(Marker, { spec: { kind: annKind, color: annotationColor }, progress: markerP }) : null);
|
|
595
|
+
return /* @__PURE__ */ React.createElement("span", { key: si, style: { position: "relative", display: "inline-block", opacity, transform: entranceTransform, transformOrigin: "center" } }, inner, annKind && annotatedToken && currentTimeMs >= annotatedToken.fromMs ? /* @__PURE__ */ React.createElement(Marker, { spec: { kind: annKind, color: annotationColor, strokeWidth: annotationStrokeWidth }, progress: markerP }) : null);
|
|
410
596
|
}));
|
|
411
597
|
});
|
|
412
598
|
})()
|
|
413
599
|
)));
|
|
414
600
|
}
|
|
601
|
+
function CaptionLayoutLayer({
|
|
602
|
+
segments,
|
|
603
|
+
layouts,
|
|
604
|
+
style,
|
|
605
|
+
region
|
|
606
|
+
}) {
|
|
607
|
+
if (!layouts?.length) return /* @__PURE__ */ React.createElement(Captions, { segments, style, region });
|
|
608
|
+
const placed = /* @__PURE__ */ new Set();
|
|
609
|
+
for (const layout of layouts) {
|
|
610
|
+
for (let word = layout.wordStartIndex; word < layout.wordEndIndex; word++) {
|
|
611
|
+
placed.add(`${layout.segmentIndex}:${word}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const remaining = segments.map((words, segmentIndex) => words.filter((_, wordIndex) => !placed.has(`${segmentIndex}:${wordIndex}`)));
|
|
615
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Captions, { segments: remaining, style, region }), layouts.map((layout) => {
|
|
616
|
+
const source = segments[layout.segmentIndex];
|
|
617
|
+
if (!source) return null;
|
|
618
|
+
const marks = new Map((layout.wordMarks ?? []).map((mark) => [mark.wordIndex, mark]));
|
|
619
|
+
const words = source.slice(layout.wordStartIndex, layout.wordEndIndex).map((word, offset) => {
|
|
620
|
+
const mark = marks.get(layout.wordStartIndex + offset);
|
|
621
|
+
if (!mark) return word;
|
|
622
|
+
const updated = { ...word };
|
|
623
|
+
if (mark.emphasis !== void 0) updated.emphasis = mark.emphasis;
|
|
624
|
+
if (mark.annotate === null) delete updated.annotate;
|
|
625
|
+
else if (mark.annotate !== void 0) updated.annotate = mark.annotate;
|
|
626
|
+
return updated;
|
|
627
|
+
});
|
|
628
|
+
const hold = source[layout.holdThroughWordIndex ?? layout.wordEndIndex - 1];
|
|
629
|
+
return /* @__PURE__ */ React.createElement(
|
|
630
|
+
Captions,
|
|
631
|
+
{
|
|
632
|
+
key: `${layout.segmentIndex}:${layout.wordStartIndex}:${layout.wordEndIndex}`,
|
|
633
|
+
segments: [words],
|
|
634
|
+
style: { ...style, ...layout.style, region: layout.region },
|
|
635
|
+
region,
|
|
636
|
+
holdUntilMs: hold?.endMs,
|
|
637
|
+
scale: layout.scale,
|
|
638
|
+
rotation: layout.rotation,
|
|
639
|
+
syncWordVisibility: true,
|
|
640
|
+
singlePageRequired: true,
|
|
641
|
+
layoutLabel: `segment ${layout.segmentIndex} words ${layout.wordStartIndex}..${layout.wordEndIndex - 1}`
|
|
642
|
+
}
|
|
643
|
+
);
|
|
644
|
+
}));
|
|
645
|
+
}
|
|
415
646
|
export {
|
|
647
|
+
CaptionLayoutLayer,
|
|
416
648
|
Captions
|
|
417
649
|
};
|
|
@@ -12,15 +12,15 @@ import {
|
|
|
12
12
|
Vignette,
|
|
13
13
|
catalog,
|
|
14
14
|
laneDepths
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-GAACUQAB.js";
|
|
16
16
|
import "../chunk-MFHXCHRI.js";
|
|
17
17
|
import "../chunk-XHGZ2E77.js";
|
|
18
18
|
import "../chunk-W2245F6G.js";
|
|
19
|
-
import "../chunk-
|
|
19
|
+
import "../chunk-D5E5XFHK.js";
|
|
20
20
|
import "../chunk-XV2K3AQT.js";
|
|
21
21
|
import "../chunk-CL5Y6V6K.js";
|
|
22
22
|
import "../chunk-2L7PYYJK.js";
|
|
23
|
-
import "../chunk-
|
|
23
|
+
import "../chunk-7RGDRDAR.js";
|
|
24
24
|
import "../chunk-2ESYSVXG.js";
|
|
25
25
|
export {
|
|
26
26
|
Blur,
|
|
@@ -8,14 +8,14 @@ import {
|
|
|
8
8
|
SplitScreen,
|
|
9
9
|
StaggeredBentoGrid,
|
|
10
10
|
catalog
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-CR3G2JQP.js";
|
|
12
12
|
import "../chunk-XHGZ2E77.js";
|
|
13
13
|
import "../chunk-W2245F6G.js";
|
|
14
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-D5E5XFHK.js";
|
|
15
15
|
import "../chunk-XV2K3AQT.js";
|
|
16
16
|
import "../chunk-CL5Y6V6K.js";
|
|
17
17
|
import "../chunk-2L7PYYJK.js";
|
|
18
|
-
import "../chunk-
|
|
18
|
+
import "../chunk-7RGDRDAR.js";
|
|
19
19
|
import "../chunk-2ESYSVXG.js";
|
|
20
20
|
export {
|
|
21
21
|
ChatToPreviewLayout,
|
|
@@ -8,17 +8,17 @@ import {
|
|
|
8
8
|
ProductLaunchTrailer,
|
|
9
9
|
TerminalToBrowserDeploy,
|
|
10
10
|
catalog
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-C6ONUJIO.js";
|
|
12
12
|
import "../chunk-S5H6GH6M.js";
|
|
13
13
|
import "../chunk-QAGGJHAF.js";
|
|
14
14
|
import "../chunk-MFHXCHRI.js";
|
|
15
15
|
import "../chunk-QGAWDLYX.js";
|
|
16
16
|
import "../chunk-W2245F6G.js";
|
|
17
|
-
import "../chunk-
|
|
17
|
+
import "../chunk-D5E5XFHK.js";
|
|
18
18
|
import "../chunk-XV2K3AQT.js";
|
|
19
19
|
import "../chunk-CL5Y6V6K.js";
|
|
20
20
|
import "../chunk-2L7PYYJK.js";
|
|
21
|
-
import "../chunk-
|
|
21
|
+
import "../chunk-7RGDRDAR.js";
|
|
22
22
|
import "../chunk-2ESYSVXG.js";
|
|
23
23
|
export {
|
|
24
24
|
ChangelogBite,
|