@glissade/narrate 0.5.0-pre.4 → 0.5.0-pre.5
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/index.d.ts +4 -0
- package/dist/index.js +35 -6
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -130,6 +130,10 @@ interface CaptionStyle {
|
|
|
130
130
|
/** bottom inset as a fraction of scene height; defaults 0.10 (landscape) / 0.18 (portrait) */
|
|
131
131
|
bottomInsetFrac?: number;
|
|
132
132
|
lineHeight?: number;
|
|
133
|
+
/** lines a caption may use before it auto-shrinks to fit; default 2 */
|
|
134
|
+
maxLines?: number;
|
|
135
|
+
/** floor for auto-shrink, as a fraction of the base font size; default 0.7 */
|
|
136
|
+
minScale?: number;
|
|
133
137
|
}
|
|
134
138
|
/**
|
|
135
139
|
* Bottom-centered captions inside the platform-safe area: portrait scenes
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { key, track } from "@glissade/core";
|
|
2
|
-
import { Text, glow } from "@glissade/scene";
|
|
2
|
+
import { Text, breakLines, estimatingMeasurer, glow, quantize } from "@glissade/scene";
|
|
3
3
|
//#region src/index.ts
|
|
4
4
|
/**
|
|
5
5
|
* @glissade/narrate — narration + captions, the PURE side. TTS happens only
|
|
@@ -99,18 +99,47 @@ function captionTrack(timing, opts = {}) {
|
|
|
99
99
|
function captionNode(size, style = {}) {
|
|
100
100
|
const portrait = size.h > size.w;
|
|
101
101
|
const inset = style.bottomInsetFrac ?? (portrait ? .18 : .1);
|
|
102
|
-
|
|
102
|
+
const baseFont = style.fontSize ?? Math.round(Math.min(size.w, size.h) * (portrait ? .052 : .06));
|
|
103
|
+
const fontFamily = style.fontFamily ?? "sans-serif";
|
|
104
|
+
const width = Math.round(size.w * (style.widthFrac ?? .82));
|
|
105
|
+
const lineHeight = style.lineHeight ?? 1.3;
|
|
106
|
+
const maxLines = Math.max(1, style.maxLines ?? 2);
|
|
107
|
+
const minFont = Math.max(1, Math.round(baseFont * (style.minScale ?? .7)));
|
|
108
|
+
const bottomY = Math.round(size.h * (1 - inset));
|
|
109
|
+
const node = new Text({
|
|
103
110
|
id: "captions",
|
|
104
111
|
text: "",
|
|
105
112
|
align: "center",
|
|
106
|
-
fontSize:
|
|
113
|
+
fontSize: baseFont,
|
|
107
114
|
...style.fontFamily !== void 0 ? { fontFamily: style.fontFamily } : {},
|
|
108
115
|
fill: style.fill ?? "#ffffff",
|
|
109
|
-
width
|
|
110
|
-
lineHeight
|
|
111
|
-
position: [size.w / 2,
|
|
116
|
+
width,
|
|
117
|
+
lineHeight,
|
|
118
|
+
position: [size.w / 2, bottomY],
|
|
112
119
|
filters: style.filters ?? glow("#000000cc", 3, 1)
|
|
113
120
|
});
|
|
121
|
+
const lineCountAt = (font, m) => {
|
|
122
|
+
const t = node.text();
|
|
123
|
+
if (!t) return 0;
|
|
124
|
+
return breakLines(t, {
|
|
125
|
+
family: fontFamily,
|
|
126
|
+
size: font,
|
|
127
|
+
weight: node.fontWeight
|
|
128
|
+
}, width > 0 ? width : void 0, m).length;
|
|
129
|
+
};
|
|
130
|
+
node.fontSize.bindSource(() => {
|
|
131
|
+
const m = node.measurerSource?.() ?? estimatingMeasurer;
|
|
132
|
+
let font = baseFont;
|
|
133
|
+
while (font > minFont && lineCountAt(font, m) > maxLines) font -= 1;
|
|
134
|
+
return font;
|
|
135
|
+
});
|
|
136
|
+
node.position.bindSource(() => {
|
|
137
|
+
const m = node.measurerSource?.() ?? estimatingMeasurer;
|
|
138
|
+
const lines = Math.max(1, lineCountAt(node.fontSize(), m));
|
|
139
|
+
const step = quantize(node.fontSize() * lineHeight);
|
|
140
|
+
return [size.w / 2, bottomY - (lines - 1) * step];
|
|
141
|
+
});
|
|
142
|
+
return node;
|
|
114
143
|
}
|
|
115
144
|
/**
|
|
116
145
|
* The bed-ducking envelope every narrated video needs: duck windows are the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/narrate",
|
|
3
|
-
"version": "0.5.0-pre.
|
|
3
|
+
"version": "0.5.0-pre.5",
|
|
4
4
|
"description": "glissade narration + captions: TTS at prepare time (gs narrate), deterministic caching, narration-anchored timeline beats, and captions as plain tracks. Render stays offline.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@glissade/core": "0.5.0-pre.
|
|
23
|
-
"@glissade/scene": "0.5.0-pre.
|
|
22
|
+
"@glissade/core": "0.5.0-pre.5",
|
|
23
|
+
"@glissade/scene": "0.5.0-pre.5"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|