@glissade/cli 0.5.0-pre.5 → 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/cli.js CHANGED
@@ -45,6 +45,7 @@ const USAGE = `usage:
45
45
  gs import <lottie.json> [--out <dir>] [--allow-degraded]
46
46
  gs narrate <scene-module|script.narration.json> [--provider <id>] [--align <id>] [--force]
47
47
  gs sfx <scene-module|script.sfx.json> [--verbose]
48
+ gs prepare <scene-module> [--provider <id>] [--align <id>] [--force]
48
49
 
49
50
  render options:
50
51
  --out <path> output directory for a PNG sequence, or .mp4/.webm (needs ffmpeg). default: ./out
@@ -73,7 +74,7 @@ narrate options (the explicit TTS prepare step; render itself stays offline):
73
74
  `;
74
75
  async function main() {
75
76
  const [command, ...rest] = process.argv.slice(2);
76
- if (command !== "render" && command !== "dev" && command !== "import" && command !== "narrate" && command !== "sfx") {
77
+ if (command !== "render" && command !== "dev" && command !== "import" && command !== "narrate" && command !== "sfx" && command !== "prepare") {
77
78
  console.error(USAGE);
78
79
  process.exit(command === void 0 || command === "help" || command === "--help" ? 0 : 1);
79
80
  }
@@ -100,6 +101,21 @@ async function main() {
100
101
  }
101
102
  return;
102
103
  }
104
+ if (command === "prepare") {
105
+ const { prepareCommand } = await import("./prepare.js");
106
+ try {
107
+ const result = await prepareCommand({
108
+ input: modulePath,
109
+ ...flags.has("provider") ? { provider: flags.get("provider") } : {},
110
+ ...flags.has("align") ? { aligner: flags.get("align") } : {},
111
+ ...flags.has("force") ? { force: true } : {}
112
+ });
113
+ process.stderr.write(`gs prepare: ${result.notes.join("; ") || "nothing to prepare"}\n`);
114
+ } catch (err) {
115
+ fail(err instanceof Error ? err.message : String(err));
116
+ }
117
+ return;
118
+ }
103
119
  if (command === "sfx") {
104
120
  const { prepareSfx, sfxScriptPathFor } = await import("./sfx.js");
105
121
  try {
@@ -0,0 +1,50 @@
1
+ import { r as loadSceneModule } from "./render.js";
2
+ import { narrateCommand } from "./narrate.js";
3
+ import { prepareSfx, sfxScriptPathFor } from "./sfx.js";
4
+ import { existsSync } from "node:fs";
5
+ //#region src/prepare.ts
6
+ /**
7
+ * gs prepare — materialize ALL of a scene's committed audio assets in one step:
8
+ * the narration manifest (gs narrate), the sfx manifest + cache (gs sfx), and
9
+ * any in-code sfx caches the scene writes at module/timeline-build time. The
10
+ * last is flushed simply by IMPORTING the scene module (its top-level
11
+ * renderSfxAssets+writeFileSync run then) — evaluate() is a pure read that
12
+ * writes nothing, so prepare never calls it. After prepare, gs render is a pure
13
+ * read of committed files.
14
+ */
15
+ const sibling = (input, ext) => input.replace(/\.[jt]sx?$/, "") + ext;
16
+ async function prepareCommand(opts) {
17
+ const notes = [];
18
+ let narrationTimingPath = null;
19
+ let sfx = null;
20
+ if (opts.input.endsWith(".narration.json") || existsSync(sibling(opts.input, ".narration.json"))) {
21
+ const r = await narrateCommand({
22
+ input: opts.input,
23
+ ...opts.provider !== void 0 ? { provider: opts.provider } : {},
24
+ ...opts.aligner !== void 0 ? { aligner: opts.aligner } : {},
25
+ ...opts.force !== void 0 ? { force: opts.force } : {}
26
+ });
27
+ narrationTimingPath = r.timingPath;
28
+ notes.push(`narration → ${r.timingPath}`);
29
+ }
30
+ if (opts.input.endsWith(".sfx.json") || existsSync(sibling(opts.input, ".sfx.json"))) {
31
+ sfx = prepareSfx(sfxScriptPathFor(opts.input));
32
+ notes.push(`sfx ${sfx.clipCount} ${sfx.clipCount === 1 ? "hit" : "hits"} → ${sfx.timingPath}`);
33
+ }
34
+ let loaded = false;
35
+ if (!opts.input.endsWith(".json")) try {
36
+ await loadSceneModule(opts.input);
37
+ loaded = true;
38
+ notes.push("flushed in-code caches (scene module imported)");
39
+ } catch (err) {
40
+ notes.push(`scene import skipped (${err instanceof Error ? err.message : String(err)})`);
41
+ }
42
+ return {
43
+ narrationTimingPath,
44
+ sfx,
45
+ loaded,
46
+ notes
47
+ };
48
+ }
49
+ //#endregion
50
+ export { prepareCommand };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glissade/cli",
3
- "version": "0.5.0-pre.5",
3
+ "version": "0.5.0-pre.6",
4
4
  "description": "glissade CLI: headless rendering via backend-skia (+ FFmpeg mux).",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -20,14 +20,14 @@
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.5.0-pre.5",
24
- "@glissade/core": "0.5.0-pre.5",
25
- "@glissade/interact": "0.5.0-pre.5",
26
- "@glissade/lottie": "0.5.0-pre.5",
27
- "@glissade/narrate": "0.5.0-pre.5",
28
- "@glissade/player": "0.5.0-pre.5",
29
- "@glissade/scene": "0.5.0-pre.5",
30
- "@glissade/sfx": "0.5.0-pre.5"
23
+ "@glissade/backend-skia": "0.5.0-pre.6",
24
+ "@glissade/core": "0.5.0-pre.6",
25
+ "@glissade/interact": "0.5.0-pre.6",
26
+ "@glissade/lottie": "0.5.0-pre.6",
27
+ "@glissade/narrate": "0.5.0-pre.6",
28
+ "@glissade/player": "0.5.0-pre.6",
29
+ "@glissade/scene": "0.5.0-pre.6",
30
+ "@glissade/sfx": "0.5.0-pre.6"
31
31
  },
32
32
  "repository": {
33
33
  "type": "git",