@glissade/cli 0.41.1-pre.0 → 0.42.0-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 +26 -2
- package/dist/index.d.ts +2 -1
- package/dist/localize.js +252 -0
- package/dist/render.js +3 -2
- package/package.json +10 -10
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,9 @@ const KNOWN_BOOLEAN_FLAGS = new Set([
|
|
|
22
22
|
"verbose",
|
|
23
23
|
"allow-degraded",
|
|
24
24
|
"bisect",
|
|
25
|
-
"watch"
|
|
25
|
+
"watch",
|
|
26
|
+
"write",
|
|
27
|
+
"keep-voice"
|
|
26
28
|
]);
|
|
27
29
|
function parseArgs(argv) {
|
|
28
30
|
const positional = [];
|
|
@@ -90,6 +92,7 @@ const USAGE = `usage:
|
|
|
90
92
|
gs describe [--out <api.json>] [--examples] snapshot THIS engine's describe() API manifest (stdout, or --out to a file) — the input to gs migrate
|
|
91
93
|
gs migrate <baseline-api.json> [--json] [--check] diff a saved API manifest against the current engine: moved imports / removed / added / changed, with a suggested fix per breaking item (advisory; --check exits non-zero on any breaking change for CI gating)
|
|
92
94
|
gs repin <scene-module> --golden <dir> [--name <p>] [--frames a,b,..] [--fps <n>] [--since <ref>] [--write] [--only a,b] [--heatmap <dir>] [--floor <ssim>] [--force] narration-aware golden reviewer: render current vs committed goldens, report perceptual delta + the re-narration cause, re-pin only frames you allow (default dry-run; --floor refuses a bigger-than-expected drop)
|
|
95
|
+
gs localize <scene-module> --to <locale> [--from <locale>] [--write] [--keep-voice] [--json] fork a narration into a new locale (clone segment/pause structure, PRESERVING beat ids so .start() anchors survive) + stub messages.<locale>.json from the scene's t() ids, running the render path's parity + localize checks BEFORE any TTS. Default dry-run (exits non-zero on drift); --write emits <base>.<locale>.narration.json + messages.<locale>.json
|
|
93
96
|
gs --version print the engine version
|
|
94
97
|
|
|
95
98
|
render options:
|
|
@@ -191,7 +194,7 @@ async function main() {
|
|
|
191
194
|
process.stdout.write(`${describe().version}\n`);
|
|
192
195
|
return;
|
|
193
196
|
}
|
|
194
|
-
if (command !== "render" && command !== "diff" && command !== "verify-determinism" && command !== "dev" && command !== "import" && command !== "narrate" && command !== "narration-lint" && command !== "sfx" && command !== "prepare" && command !== "measure-loudness" && command !== "fonts" && command !== "cache" && command !== "mcp" && command !== "build" && command !== "describe" && command !== "migrate" && command !== "repin" && command !== "master") {
|
|
197
|
+
if (command !== "render" && command !== "diff" && command !== "verify-determinism" && command !== "dev" && command !== "import" && command !== "narrate" && command !== "narration-lint" && command !== "sfx" && command !== "prepare" && command !== "measure-loudness" && command !== "fonts" && command !== "cache" && command !== "mcp" && command !== "build" && command !== "describe" && command !== "migrate" && command !== "repin" && command !== "master" && command !== "localize") {
|
|
195
198
|
console.error(USAGE);
|
|
196
199
|
process.exit(command === void 0 || command === "help" || command === "--help" ? 0 : 1);
|
|
197
200
|
}
|
|
@@ -352,6 +355,27 @@ async function main() {
|
|
|
352
355
|
}
|
|
353
356
|
return;
|
|
354
357
|
}
|
|
358
|
+
if (command === "localize") {
|
|
359
|
+
const { positional: lp, flags: lf } = parseArgs(rest);
|
|
360
|
+
const sceneModule = lp[0];
|
|
361
|
+
if (!sceneModule) fail(`gs localize needs <scene-module>\n${USAGE}`);
|
|
362
|
+
const to = lf.get("to");
|
|
363
|
+
if (!to) fail(`gs localize needs --to <locale> (e.g. --to zh)\n${USAGE}`);
|
|
364
|
+
const { localizeCommand, formatLocalizeReport } = await import("./localize.js");
|
|
365
|
+
try {
|
|
366
|
+
const report = await localizeCommand(sceneModule, {
|
|
367
|
+
to,
|
|
368
|
+
...lf.get("from") ? { from: lf.get("from") } : {},
|
|
369
|
+
...lf.has("write") ? { write: true } : {},
|
|
370
|
+
...lf.has("keep-voice") ? { keepVoice: true } : {}
|
|
371
|
+
});
|
|
372
|
+
process.stdout.write(lf.has("json") ? `${JSON.stringify(report, null, 2)}\n` : `${formatLocalizeReport(report)}\n`);
|
|
373
|
+
if (!lf.has("write") && report.preflight.issues.length > 0) process.exit(1);
|
|
374
|
+
} catch (err) {
|
|
375
|
+
fail(err instanceof Error ? err.message : String(err));
|
|
376
|
+
}
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
355
379
|
const { positional, flags } = parseArgs(rest);
|
|
356
380
|
const modulePath = positional[0];
|
|
357
381
|
if (!modulePath) fail(`missing ${command === "import" ? "<lottie.json|asset.svg>" : "<scene-module>"}\n${USAGE}`);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { AudioClip, CompiledTimeline, Key, Timeline } from "@glissade/core";
|
|
|
2
2
|
import { DisplayList, Scene, SceneModule, VideoFrameSource } from "@glissade/scene";
|
|
3
3
|
import { NarrationTiming } from "@glissade/narrate";
|
|
4
4
|
import { Image } from "@napi-rs/canvas";
|
|
5
|
+
import * as _glissade_core_i18n0 from "@glissade/core/i18n";
|
|
5
6
|
|
|
6
7
|
//#region src/frameCache.d.ts
|
|
7
8
|
|
|
@@ -497,7 +498,7 @@ declare class SceneModuleError extends Error {
|
|
|
497
498
|
* ranges are rejected, since a frame index is an integer.
|
|
498
499
|
*/
|
|
499
500
|
|
|
500
|
-
declare function loadSceneModule(modulePath: string, locale?: string): Promise<SceneModule>;
|
|
501
|
+
declare function loadSceneModule(modulePath: string, locale?: string, messageTableOverride?: _glissade_core_i18n0.MessageTable): Promise<SceneModule>;
|
|
501
502
|
declare function ffmpegAvailable(): boolean;
|
|
502
503
|
declare function render(opts: RenderOptions): Promise<{
|
|
503
504
|
frames: number;
|
package/dist/localize.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { isPause } from "@glissade/narrate";
|
|
2
|
+
import { LocalizationError, ParityError, localize, requireParity } from "@glissade/core/i18n";
|
|
3
|
+
//#region src/localize.ts
|
|
4
|
+
/**
|
|
5
|
+
* `gs localize` (0.42) — the fork/translate/parity orchestrator. Forking a
|
|
6
|
+
* narration into a new locale by hand is where drift creeps in: you clone the
|
|
7
|
+
* script, re-author the timing, hand-write `messages.<locale>.json`, and only
|
|
8
|
+
* discover a missing beat id or an orphaned message when something THROWS deep in
|
|
9
|
+
* a render — after a minute of TTS. `gs localize <base> --to <locale>` does the
|
|
10
|
+
* mechanical fork up front and runs the SAME parity + localize checks the render
|
|
11
|
+
* path runs, BEFORE any synthesis: it clones the segment/pause structure keeping
|
|
12
|
+
* every beat id (so `.start('seg-x')` anchors survive), stubs a translatable
|
|
13
|
+
* `messages.<locale>.json` from the scene's `t()` ids, and reports every drift.
|
|
14
|
+
*
|
|
15
|
+
* This module is the PURE engine (fork + stub + preflight report). The CLI
|
|
16
|
+
* command (file IO, harvesting `t()` ids by loading the scene, `--write`) wraps it.
|
|
17
|
+
* Nothing here synthesizes audio, touches the render path, or calls `evaluate()`.
|
|
18
|
+
*/
|
|
19
|
+
var LocalizeError = class extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = "LocalizeError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Fork an authored narration script for a new locale: a structural clone that
|
|
27
|
+
* PRESERVES every segment/pause id (the beat ids `.start()`/`.end()` anchors and
|
|
28
|
+
* SFX/visual cues resolve against — they MUST survive so the translated locale
|
|
29
|
+
* stays anchor-compatible) and carries the source text through as a translate-me
|
|
30
|
+
* placeholder. Pure: the input is never mutated. The `voice` is dropped so the
|
|
31
|
+
* locale picks its own (an English voice on translated text is a mistake) unless
|
|
32
|
+
* `keepVoice` is set.
|
|
33
|
+
*/
|
|
34
|
+
function forkNarrationScript(base, opts = {}) {
|
|
35
|
+
const segments = base.segments.map((el) => {
|
|
36
|
+
if (isPause(el)) return { ...el };
|
|
37
|
+
if (opts.keepVoice) return { ...el };
|
|
38
|
+
const { voice: _voice, ...rest } = el;
|
|
39
|
+
return rest;
|
|
40
|
+
});
|
|
41
|
+
const forked = {
|
|
42
|
+
...base,
|
|
43
|
+
segments
|
|
44
|
+
};
|
|
45
|
+
if (!opts.keepVoice) delete forked.voice;
|
|
46
|
+
return forked;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Derive an authored-script skeleton from a COMMITTED timing manifest — the fork
|
|
50
|
+
* source when the base project kept only `<base>.narration.timing.json` (no
|
|
51
|
+
* authored `<base>.narration.json`). Maps each timed segment/pause back to its
|
|
52
|
+
* script element, preserving ids and text; drops the resolved timing (start/
|
|
53
|
+
* duration/file/words) which a re-narration of the new locale regenerates.
|
|
54
|
+
*/
|
|
55
|
+
function scriptFromTiming(timing) {
|
|
56
|
+
const pauses = timing.pauses ?? [];
|
|
57
|
+
const els = [...timing.segments.map((s) => ({
|
|
58
|
+
start: s.start,
|
|
59
|
+
el: {
|
|
60
|
+
id: s.id,
|
|
61
|
+
text: s.text
|
|
62
|
+
}
|
|
63
|
+
})), ...pauses.map((p) => ({
|
|
64
|
+
start: p.start,
|
|
65
|
+
el: {
|
|
66
|
+
id: p.id,
|
|
67
|
+
pause: p.duration,
|
|
68
|
+
...p.bed ? { bed: p.bed } : {}
|
|
69
|
+
}
|
|
70
|
+
}))];
|
|
71
|
+
els.sort((a, b) => a.start - b.start);
|
|
72
|
+
return {
|
|
73
|
+
narrationVersion: 1,
|
|
74
|
+
...timing.captionSplit ? { captionSplit: timing.captionSplit } : {},
|
|
75
|
+
...timing.captionMode ? { captionMode: timing.captionMode } : {},
|
|
76
|
+
...timing.budgets ? { budgets: timing.budgets } : {},
|
|
77
|
+
segments: els.map((e) => e.el)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a translatable `messages.<locale>.json` stub for a set of `t()` ids. Each
|
|
82
|
+
* id maps to the base-locale string as a translate-from placeholder (so the
|
|
83
|
+
* translator sees the source), or `''` when no base value exists. Existing target
|
|
84
|
+
* translations are CARRIED OVER (a re-localize never blanks work already done —
|
|
85
|
+
* the translation-memory seed). Keys are sorted for a deterministic, diff-stable
|
|
86
|
+
* file. Pure.
|
|
87
|
+
*/
|
|
88
|
+
function stubMessageTable(ids, opts = {}) {
|
|
89
|
+
const out = {};
|
|
90
|
+
for (const id of [...new Set(ids)].sort()) out[id] = opts.existing?.[id] ?? opts.base?.[id] ?? "";
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Run the SAME checks the render path runs — `requireParity` across the base and
|
|
95
|
+
* new-locale id manifests, and a dry `localize()` of the scene document with the
|
|
96
|
+
* stub table — but as a NON-throwing report, so every drift surfaces at once
|
|
97
|
+
* before a minute of TTS instead of one-at-a-time at render. Pure over its loaded
|
|
98
|
+
* inputs (it catches the `ParityError`/`LocalizationError` the primitives throw).
|
|
99
|
+
*/
|
|
100
|
+
function runLocalizePreflight(args) {
|
|
101
|
+
const issues = [];
|
|
102
|
+
try {
|
|
103
|
+
requireParity(args.baseManifest, args.localeManifest);
|
|
104
|
+
} catch (e) {
|
|
105
|
+
if (e instanceof ParityError) issues.push({
|
|
106
|
+
kind: "parity",
|
|
107
|
+
message: e.message
|
|
108
|
+
});
|
|
109
|
+
else throw e;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
localize(args.doc, args.stubTable, {
|
|
113
|
+
locale: args.locale,
|
|
114
|
+
...args.consumedIds ? { consumedIds: args.consumedIds } : {}
|
|
115
|
+
});
|
|
116
|
+
} catch (e) {
|
|
117
|
+
if (e instanceof LocalizationError) issues.push({
|
|
118
|
+
kind: "localize",
|
|
119
|
+
message: e.message
|
|
120
|
+
});
|
|
121
|
+
else throw e;
|
|
122
|
+
}
|
|
123
|
+
const untranslated = Object.values(args.stubTable).filter((v) => v === "").length;
|
|
124
|
+
return {
|
|
125
|
+
locale: args.locale,
|
|
126
|
+
ids: [...args.localeManifest.ids].sort(),
|
|
127
|
+
untranslated,
|
|
128
|
+
issues,
|
|
129
|
+
ok: issues.length === 0
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const nodeIdOf = (target) => {
|
|
133
|
+
const i = target.indexOf("/");
|
|
134
|
+
return i < 0 ? target : target.slice(0, i);
|
|
135
|
+
};
|
|
136
|
+
const moduleStemOf = (modulePath) => modulePath.replace(/\.[jt]sx?$/, "");
|
|
137
|
+
/** beat ids (segments + pauses, in order) of an authored script — the anchor id set. */
|
|
138
|
+
const scriptBeatIds = (script) => script.segments.map((e) => e.id);
|
|
139
|
+
/**
|
|
140
|
+
* Harvest the message-table keys a scene actually uses: every `t()` id (recorded
|
|
141
|
+
* by loading the scene under a table that treats every id as known — a Proxy whose
|
|
142
|
+
* `has` is always true, so no `t()` throws — then reading `getConsumedMessageIds`)
|
|
143
|
+
* plus every `type:'string'` track's node-id (the `localize()` keys). This is the
|
|
144
|
+
* one impure step (loading the module runs its side effects), quarantined here.
|
|
145
|
+
*/
|
|
146
|
+
async function harvestMessageIds(modulePath) {
|
|
147
|
+
const recording = new Proxy({}, {
|
|
148
|
+
has: () => true,
|
|
149
|
+
get: (_t, prop) => typeof prop === "string" ? prop : void 0
|
|
150
|
+
});
|
|
151
|
+
const { getConsumedMessageIds } = await import("@glissade/core/i18n");
|
|
152
|
+
const { loadSceneModule } = await import("./render.js").then((n) => n.p);
|
|
153
|
+
const mod = await loadSceneModule(modulePath, void 0, recording);
|
|
154
|
+
mod.createScene();
|
|
155
|
+
const tIds = new Set(getConsumedMessageIds());
|
|
156
|
+
const ids = new Set(tIds);
|
|
157
|
+
const doc = mod.timeline;
|
|
158
|
+
for (const tr of doc.tracks ?? []) if (tr.type === "string") ids.add(nodeIdOf(tr.target));
|
|
159
|
+
return {
|
|
160
|
+
ids: [...ids],
|
|
161
|
+
tIds,
|
|
162
|
+
doc
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Fork a scene's narration into a new locale + stub its message table, running the
|
|
167
|
+
* render path's parity + localize checks first. Dry-run by default (reports what it
|
|
168
|
+
* WOULD write); `--write` emits `<base>.<locale>.narration.json` +
|
|
169
|
+
* `messages.<locale>.json`. Never synthesizes audio or calls `evaluate()`.
|
|
170
|
+
*/
|
|
171
|
+
async function localizeCommand(modulePath, opts) {
|
|
172
|
+
const { readFileSync, writeFileSync, existsSync } = await import("node:fs");
|
|
173
|
+
const { scriptPathFor } = await import("@glissade/narrate/providers");
|
|
174
|
+
const { messagesFileFor, loadMessageTable } = await import("./locale.js");
|
|
175
|
+
const { timingPathFor } = await import("./captions.js").then((n) => n.t);
|
|
176
|
+
const to = opts.to;
|
|
177
|
+
if (!/^[a-z]{2}(-[A-Za-z0-9]+)*$/.test(to)) throw new LocalizeError(`--to '${to}' is not a locale code (expected e.g. 'zh', 'pt-BR')`);
|
|
178
|
+
const { ids: messageIds, tIds, doc } = await harvestMessageIds(modulePath);
|
|
179
|
+
const scriptPath = scriptPathFor(modulePath);
|
|
180
|
+
const baseTimingPath = timingPathFor(modulePath);
|
|
181
|
+
let baseScript;
|
|
182
|
+
let narrationSource = "none";
|
|
183
|
+
if (existsSync(scriptPath)) {
|
|
184
|
+
baseScript = JSON.parse(readFileSync(scriptPath, "utf8"));
|
|
185
|
+
narrationSource = "script";
|
|
186
|
+
} else if (baseTimingPath && existsSync(baseTimingPath)) {
|
|
187
|
+
baseScript = scriptFromTiming(JSON.parse(readFileSync(baseTimingPath, "utf8")));
|
|
188
|
+
narrationSource = "timing";
|
|
189
|
+
}
|
|
190
|
+
const forked = baseScript ? forkNarrationScript(baseScript, { keepVoice: opts.keepVoice ?? false }) : void 0;
|
|
191
|
+
const beatIds = baseScript ? scriptBeatIds(baseScript) : [];
|
|
192
|
+
const narrationPath = moduleStemOf(modulePath) + `.${to}.narration.json`;
|
|
193
|
+
let localeBeatIds = beatIds;
|
|
194
|
+
if (existsSync(narrationPath)) localeBeatIds = scriptBeatIds(JSON.parse(readFileSync(narrationPath, "utf8")));
|
|
195
|
+
const base = opts.from ? loadMessageTable(modulePath, opts.from) : void 0;
|
|
196
|
+
const messagesPath = messagesFileFor(modulePath, to);
|
|
197
|
+
const existingTable = existsSync(messagesPath) ? JSON.parse(readFileSync(messagesPath, "utf8")) : loadMessageTable(modulePath, to);
|
|
198
|
+
const stubTable = stubMessageTable(messageIds, {
|
|
199
|
+
...base ? { base } : {},
|
|
200
|
+
...existingTable ? { existing: existingTable } : {}
|
|
201
|
+
});
|
|
202
|
+
const preflight = runLocalizePreflight({
|
|
203
|
+
locale: to,
|
|
204
|
+
baseManifest: {
|
|
205
|
+
locale: opts.from ?? "base",
|
|
206
|
+
ids: beatIds
|
|
207
|
+
},
|
|
208
|
+
localeManifest: {
|
|
209
|
+
locale: to,
|
|
210
|
+
ids: localeBeatIds
|
|
211
|
+
},
|
|
212
|
+
doc,
|
|
213
|
+
stubTable,
|
|
214
|
+
consumedIds: tIds
|
|
215
|
+
});
|
|
216
|
+
const wrote = [];
|
|
217
|
+
if (opts.write) {
|
|
218
|
+
if (forked) {
|
|
219
|
+
writeFileSync(narrationPath, JSON.stringify(forked, null, 2) + "\n");
|
|
220
|
+
wrote.push(narrationPath);
|
|
221
|
+
}
|
|
222
|
+
writeFileSync(messagesPath, JSON.stringify(stubTable, null, 2) + "\n");
|
|
223
|
+
wrote.push(messagesPath);
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
locale: to,
|
|
227
|
+
messageIds: messageIds.sort(),
|
|
228
|
+
beatIds,
|
|
229
|
+
preflight,
|
|
230
|
+
wrote,
|
|
231
|
+
narrationPath,
|
|
232
|
+
messagesPath,
|
|
233
|
+
narrationSource
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
/** Human-readable report (migrate.ts style). */
|
|
237
|
+
function formatLocalizeReport(r) {
|
|
238
|
+
const lines = [];
|
|
239
|
+
lines.push(`gs localize → ${r.locale}`);
|
|
240
|
+
lines.push(` narration: ${r.narrationSource === "none" ? "none found" : `${r.beatIds.length} beat(s) from the ${r.narrationSource} (ids preserved)`}`);
|
|
241
|
+
lines.push(` messages: ${r.messageIds.length} id(s) harvested, ${r.preflight.untranslated} still untranslated`);
|
|
242
|
+
if (r.preflight.issues.length === 0) lines.push(" preflight: ✓ parity + localize clean (safe to translate + narrate)");
|
|
243
|
+
else {
|
|
244
|
+
lines.push(` preflight: ✗ ${r.preflight.issues.length} issue(s) — fix before narrating:`);
|
|
245
|
+
for (const i of r.preflight.issues) lines.push(` [${i.kind}] ${i.message.replace(/\n/g, "\n ")}`);
|
|
246
|
+
}
|
|
247
|
+
if (r.wrote.length) lines.push(` wrote: ${r.wrote.join(", ")}`);
|
|
248
|
+
else lines.push(` (dry run — re-run with --write to emit ${r.narrationPath} + ${r.messagesPath})`);
|
|
249
|
+
return lines.join("\n");
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
export { formatLocalizeReport, localizeCommand };
|
package/dist/render.js
CHANGED
|
@@ -334,9 +334,10 @@ function warnOnVersionSkew(scenePath) {
|
|
|
334
334
|
if (coreVer === void 0 || coreVer === cliVer) return;
|
|
335
335
|
process.stderr.write(`warning: @glissade version skew — gs (@glissade/cli@${cliVer}) is rendering a scene that resolves @glissade/core@${coreVer}.\n glissade is LOCKSTEP: subpath features register per-package-instance (the /expr sampler, Yoga layout), so under a skew a\n correctly-imported '@glissade/core/expr' or 'layout' can still fail with "need import" / "no LayoutEngine registered".\n Align every @glissade/* dependency to ${cliVer} (e.g. npm i @glissade/core@${cliVer} @glissade/scene@${cliVer}).\n`);
|
|
336
336
|
}
|
|
337
|
-
async function loadSceneModule(modulePath, locale) {
|
|
337
|
+
async function loadSceneModule(modulePath, locale, messageTableOverride) {
|
|
338
338
|
const { setMessageTable } = await import("@glissade/core/i18n");
|
|
339
|
-
if (
|
|
339
|
+
if (messageTableOverride !== void 0) setMessageTable(messageTableOverride);
|
|
340
|
+
else if (locale !== void 0 && locale !== "") {
|
|
340
341
|
const { loadMessageTable } = await import("./locale.js");
|
|
341
342
|
setMessageTable(loadMessageTable(modulePath, locale));
|
|
342
343
|
} else setMessageTable(void 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glissade/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0-pre.0",
|
|
4
4
|
"description": "glissade CLI: headless rendering via backend-skia (+ FFmpeg mux).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"@napi-rs/canvas": "^0.1.65",
|
|
29
29
|
"esbuild": "0.28.0",
|
|
30
30
|
"jiti": "^2.4.2",
|
|
31
|
-
"@glissade/backend-skia": "0.
|
|
32
|
-
"@glissade/core": "0.
|
|
33
|
-
"@glissade/interact": "0.
|
|
34
|
-
"@glissade/lottie": "0.
|
|
35
|
-
"@glissade/narrate": "0.
|
|
36
|
-
"@glissade/player": "0.
|
|
37
|
-
"@glissade/scene": "0.
|
|
38
|
-
"@glissade/sfx": "0.
|
|
39
|
-
"@glissade/svg": "0.
|
|
31
|
+
"@glissade/backend-skia": "0.42.0-pre.0",
|
|
32
|
+
"@glissade/core": "0.42.0-pre.0",
|
|
33
|
+
"@glissade/interact": "0.42.0-pre.0",
|
|
34
|
+
"@glissade/lottie": "0.42.0-pre.0",
|
|
35
|
+
"@glissade/narrate": "0.42.0-pre.0",
|
|
36
|
+
"@glissade/player": "0.42.0-pre.0",
|
|
37
|
+
"@glissade/scene": "0.42.0-pre.0",
|
|
38
|
+
"@glissade/sfx": "0.42.0-pre.0",
|
|
39
|
+
"@glissade/svg": "0.42.0-pre.0"
|
|
40
40
|
},
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|