@glissade/narrate 0.5.0-pre.4 → 0.5.0-pre.6

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 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
- return new Text({
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: style.fontSize ?? Math.round(Math.min(size.w, size.h) * (portrait ? .052 : .06)),
113
+ fontSize: baseFont,
107
114
  ...style.fontFamily !== void 0 ? { fontFamily: style.fontFamily } : {},
108
115
  fill: style.fill ?? "#ffffff",
109
- width: Math.round(size.w * (style.widthFrac ?? .82)),
110
- lineHeight: style.lineHeight ?? 1.3,
111
- position: [size.w / 2, Math.round(size.h * (1 - inset))],
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.4",
3
+ "version": "0.5.0-pre.6",
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.4",
23
- "@glissade/scene": "0.5.0-pre.4"
22
+ "@glissade/core": "0.5.0-pre.6",
23
+ "@glissade/scene": "0.5.0-pre.6"
24
24
  },
25
25
  "repository": {
26
26
  "type": "git",