@glissade/cli 0.9.0-pre.1 → 0.9.1-pre.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/dist/cli.js CHANGED
@@ -61,6 +61,7 @@ render options:
61
61
  --music <m> auto (default): mix a sibling *.music.timing.json bed, ducked under narration | off
62
62
  --sfx <m> auto (default): mix effect hits from a sibling *.sfx.timing.json | off
63
63
  --chapters <m> vtt: also write WebVTT chapters from cue markers (cues.json is always written when cues exist)
64
+ --chapters-kind <k[,k]> cue kinds that become VTT chapters (default: chapter); cues.json keeps all kinds
64
65
  --strict fail on an unregistered font family or an uncovered glyph (§3.6; default: warn)
65
66
 
66
67
  dev options:
@@ -189,6 +190,7 @@ async function main() {
189
190
  ...frameRange ? { frameRange } : {},
190
191
  ...formatFlag === "png-seq" ? { format: "png-seq" } : {},
191
192
  ...flags.get("chapters") === "vtt" ? { chapters: "vtt" } : {},
193
+ ...flags.has("chapters-kind") ? { chapterKinds: new Set(flags.get("chapters-kind").split(",").map((s) => s.trim()).filter(Boolean)) } : {},
192
194
  ...flags.has("trace") ? { trace: flags.get("trace") } : {},
193
195
  ...flags.has("state") ? { state: flags.get("state") } : {},
194
196
  ...flags.has("force") ? { force: true } : {},
package/dist/cues.js CHANGED
@@ -28,20 +28,25 @@ function vttTime(seconds) {
28
28
  const p = (n, w = 2) => String(n).padStart(w, "0");
29
29
  return `${p(Math.floor(ms / 36e5))}:${p(Math.floor(ms % 36e5 / 6e4))}:${p(Math.floor(ms % 6e4 / 1e3))}.${p(ms % 1e3, 3)}`;
30
30
  }
31
+ /** The cue kinds that become WebVTT chapters by default (the YouTube use case). */
32
+ const DEFAULT_CHAPTER_KINDS = new Set(["chapter"]);
31
33
  /**
32
- * WebVTT chapters from cues; each runs until its duration or the next cue. The
33
- * cue text is the human `title` (falling back to `name`), not the machine
34
- * `kind`. When the earliest cue starts after 0, a `00:00` "Intro" chapter is
35
- * auto-anchored both valid WebVTT and required for YouTube description
36
- * chapters (which read the cue text as the title and need a 0:00 start).
34
+ * WebVTT chapters from cues. Only cues whose `kind` is in `kinds` (default just
35
+ * `'chapter'`) become chapters ad-break / plain `cue` markers stay out of the
36
+ * chapter list (they remain in `cues.json` for machines), so the VTT pastes
37
+ * straight into a YouTube description. Each chapter runs until its duration or
38
+ * the next chapter; the cue text is the human `title` (falling back to `name`),
39
+ * never the machine `kind`. When the earliest chapter starts after 0, a `00:00`
40
+ * "Intro" chapter is auto-anchored (valid WebVTT, and YouTube needs a 0:00 start).
37
41
  */
38
- function cuesToVtt(cues, totalDuration) {
39
- const anchored = cues.length > 0 && cues[0].t > 0 ? [{
42
+ function cuesToVtt(cues, totalDuration, kinds = DEFAULT_CHAPTER_KINDS) {
43
+ const chapters = cues.filter((c) => kinds.has(c.kind));
44
+ const anchored = chapters.length > 0 && chapters[0].t > 0 ? [{
40
45
  t: 0,
41
46
  kind: "chapter",
42
47
  name: "Intro",
43
48
  title: "Intro"
44
- }, ...cues] : cues;
49
+ }, ...chapters] : chapters;
45
50
  let out = "WEBVTT\n\n";
46
51
  anchored.forEach((c, i) => {
47
52
  const end = c.duration !== void 0 ? c.t + c.duration : anchored[i + 1]?.t ?? totalDuration;
@@ -54,7 +59,7 @@ function cuesToVtt(cues, totalDuration) {
54
59
  * `<stem>.chapters.vtt`, next to the render output. Deterministic. Returns the
55
60
  * paths written.
56
61
  */
57
- function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt) {
62
+ function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt, chapterKinds = DEFAULT_CHAPTER_KINDS) {
58
63
  const cues = collectCues(markers);
59
64
  if (cues.length === 0) return [];
60
65
  const isFile = /\.(mp4|webm)$/i.test(outPath);
@@ -66,7 +71,7 @@ function writeCueSidecars(outPath, markers, totalDuration, chaptersVtt) {
66
71
  written.push(jsonPath);
67
72
  if (chaptersVtt) {
68
73
  const vttPath = join(dir, `${prefix}chapters.vtt`);
69
- writeFileSync(vttPath, cuesToVtt(cues, totalDuration));
74
+ writeFileSync(vttPath, cuesToVtt(cues, totalDuration, chapterKinds));
70
75
  written.push(vttPath);
71
76
  }
72
77
  return written;
package/dist/index.d.ts CHANGED
@@ -32,6 +32,8 @@ interface RenderOptions {
32
32
  sfx?: 'auto' | 'off';
33
33
  /** also write WebVTT chapters from cue markers ('vtt'); cues.json is always written when cues exist. */
34
34
  chapters?: 'vtt' | 'off';
35
+ /** cue kinds that become VTT chapters (default just 'chapter'); cues.json keeps all kinds. */
36
+ chapterKinds?: ReadonlySet<string>;
35
37
  /** --strict: font validation throws on an unregistered family / missing glyph (§3.6). Default dev-warn. */
36
38
  strictFonts?: boolean;
37
39
  onProgress?: (frame: number, total: number) => void;
package/dist/render.js CHANGED
@@ -126,7 +126,7 @@ async function render(opts) {
126
126
  process.stderr.write(`captions: ${srt}, ${vtt}\n`);
127
127
  };
128
128
  const emitCues = (target) => {
129
- const written = writeCueSidecars(target, compiled.markers, duration, opts.chapters === "vtt");
129
+ const written = writeCueSidecars(target, compiled.markers, duration, opts.chapters === "vtt", opts.chapterKinds);
130
130
  if (written.length) process.stderr.write(`cues: ${written.join(", ")}\n`);
131
131
  };
132
132
  if (!isVideo) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/cli",
3
- "version": "0.9.0-pre.1",
3
+ "version": "0.9.1-pre.0",
4
4
  "description": "glissade CLI: headless rendering via backend-skia (+ FFmpeg mux).",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -20,15 +20,15 @@
20
20
  "@napi-rs/canvas": "^0.1.65",
21
21
  "esbuild": "^0.28.0",
22
22
  "jiti": "^2.4.2",
23
- "@glissade/backend-skia": "0.9.0-pre.1",
24
- "@glissade/core": "0.9.0-pre.1",
25
- "@glissade/interact": "0.9.0-pre.1",
26
- "@glissade/lottie": "0.9.0-pre.1",
27
- "@glissade/svg": "0.9.0-pre.1",
28
- "@glissade/narrate": "0.9.0-pre.1",
29
- "@glissade/player": "0.9.0-pre.1",
30
- "@glissade/scene": "0.9.0-pre.1",
31
- "@glissade/sfx": "0.9.0-pre.1"
23
+ "@glissade/backend-skia": "0.9.1-pre.0",
24
+ "@glissade/core": "0.9.1-pre.0",
25
+ "@glissade/interact": "0.9.1-pre.0",
26
+ "@glissade/lottie": "0.9.1-pre.0",
27
+ "@glissade/svg": "0.9.1-pre.0",
28
+ "@glissade/narrate": "0.9.1-pre.0",
29
+ "@glissade/player": "0.9.1-pre.0",
30
+ "@glissade/scene": "0.9.1-pre.0",
31
+ "@glissade/sfx": "0.9.1-pre.0"
32
32
  },
33
33
  "repository": {
34
34
  "type": "git",