@vosjs/cli 0.25.1 → 0.27.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/README.md +2 -2
- package/dist/{chunk-GHJ2BFQG.js → chunk-IJ5A4TL3.js} +77 -17
- package/dist/chunk-IJ5A4TL3.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/{run-NTVAMME2.js → run-XR464TW5.js} +2 -2
- package/package.json +7 -7
- package/schema/doc.schema.json +44 -1
- package/dist/chunk-GHJ2BFQG.js.map +0 -1
- /package/dist/{run-NTVAMME2.js.map → run-XR464TW5.js.map} +0 -0
package/README.md
CHANGED
|
@@ -89,11 +89,11 @@ vos plan take --reuse # re-time that cut onto
|
|
|
89
89
|
|
|
90
90
|
**Digest first.** `vos digest <take>` is how an agent sees a recording without reading the video. It writes `digest/digest.json`: one moment per thing the cursor track says mattered (click clusters, typing sessions, scroll runs, dwells, idle gaps, head, tail, and frame-diff scene changes), each with source and output extents, a normalized `focus` and `rect` you can copy into a zoom span, per-second `activity`, and the planners' `proposed` span ids; plus one footage frame and a crop around the target per moment, and `sheet.png`, the contact sheet. Read the JSON, then the sheet, then a crop only where you must decide. `vos validate` then warns when a zoom does not contain what was clicked under it, and `vos frames --at-moments` renders the composed output at every moment so a still and its footage crop share an id.
|
|
91
91
|
|
|
92
|
-
**Many media in one take (concat).** `doc.json` may carry `media: [{ id, videoKey, cursor, meta, … }]`, the take's OTHER recordings or uploads, each the `source` shape with an `id`; a segment on one (`{ in, out, media: "m1" }`) plays it, and a zoom, tilt, speed, freeze or cam-move span names the media its source seconds belong to (absent = the primary, `source`). The Video row shows the clips in order, a span is drawn where its media plays, `vos plan` proposes zoom and speed spans on every media from its own cursor track, `vos validate` measures each span against its own media's length, and `vos push` and `vos pull --media` carry every media through the recording door. A media wears its OWN card: `media[].frame` carries the card-owned fields (its placement and size as `inset`, the browser bar, the corner, the shadow, the border, the cover fit and its focus) over the take's frame while it plays; the bar names that media's recorded page, an upload with no page wears none, and the frame-wide fields (the aspect, the padding, the ground, the backdrop, the card's animation) stay the take's. Sound: the primary's tracks play at the primary's moments; another media's own audio is not spliced into the cut yet.
|
|
92
|
+
**Many media in one take (concat).** `doc.json` may carry `media: [{ id, videoKey, cursor, meta, … }]`, the take's OTHER recordings or uploads, each the `source` shape with an `id`; a segment on one (`{ in, out, media: "m1" }`) plays it, and a zoom, tilt, speed, freeze or cam-move span names the media its source seconds belong to (absent = the primary, `source`). The Video row shows the clips in order, a span is drawn where its media plays, `vos plan` proposes zoom and speed spans on every media from its own cursor track, `vos validate` measures each span against its own media's length, and `vos push` and `vos pull --media` carry every media through the recording door. A media wears its OWN card: `media[].frame` carries the card-owned fields (its placement and size as `inset`, the browser bar, the corner, the shadow, the border, the cover fit and its focus) over the take's frame while it plays; the bar names that media's recorded page, an upload with no page wears none, and the frame-wide fields (the aspect, the padding, the ground, the backdrop, the card's animation) stay the take's. Sound: the primary's tracks play at the primary's moments; another media's own audio is not spliced into the cut yet. **Many cards**: an image or video overlay may show a document media by reference (`key: "media:<id>"`, `media:` alone the primary; its cursor track and recorded page come with it) and wear a card (`frame`: `browserBar`, a `lean` `{rx, ry}` in degrees, `shadow`, `shadowContact`, `shadowColor`, `cursor`), drawn by the card painter on its own plane above the primary card with the media's cursor dot and click rings inside it; a layer without `frame` stays the flat picture. The primary card stays primary: the sequence, the camera and the cut are its.
|
|
93
93
|
|
|
94
94
|
**A series shares its look by data.** `vos plan <take> --style <seed doc.json | vosId>` copies the seed's `zoomStyle`, `zoomParams`, `speedParams`, `tiltStyle`, `frame`, `cursor`, `cam` and `export` onto a new take (never its spans, overlays or audio) and re-plans the automatic spans under them. A seed that is a POSTER carries its layout too: its card placement, its `stage-*` clips by id (with the release's words from LAUNCH.md's `headline` and `kicker` roles, BRAND.md's `wordmark`, or `--headline` and `--kicker` patched in; the brand's mark from BRAND.md `logoUrl` fetched into `<take>/brand/` for `stage-mark`), its rest lean, its trailing freeze. What could not follow is said in words.
|
|
95
95
|
|
|
96
|
-
**The cut's motion is the document's, in one vocabulary.** Every visual thing carries `anim` (`enter`, `exit`, `idle`; a kind, or a step with its seconds and, for words, `unit`, `direction`, `stagger`): the card (`frame.anim`, entering by `tilt-in`, `pull-out`, `rise` or `fade` and leaving by `recede` or `fade`), a text, image or video clip, a prop. The output lasts until the last clip ends; the card is on screen exactly while its clip runs (the footage, freezes included) and leaves at its end, so its `exit` plays over the clip's last seconds like every clip's; past the footage the clips play over the ground alone. A FREEZE (`freeze: [{id, at, seconds}]`, a source moment held for output seconds, beside the speed spans on the retime lane) freezes the footage anywhere, the middle of the take included; a segment's older `hold` is read as a freeze at its end. There is no end-card field and no entrance field. A COMPONENT is a TEMPLATE: a plain take on a shelf whose clips carry stable ids, laid onto a take at an anchor and stamped `from` with where its clips came from. A fresh `vos plan` proposes the card's enter, the templates the recipe names (`LAUNCH.md` `with: <ref>[@end|@start|@step:<id>|@<seconds>], …` or `--with`, repeatable; `endCard: <ref>` names one at the end), the END CARD when `endCard` is on or absent: the official `End card` template on vos.so (the platform's `Templates` project, promoted; any official template resolves by its title, `--with "End card"`, `--style "Split cover, landscape"`), laid at the end with the release's words and BRAND.md's mark, stamped `from: endcard`; offline, the house clips stand in (a freeze of the last frame for the card's seconds, the card receding over it, the headline, the release line, the wordmark and the mark as clips over the freeze), a caption per `actions.json` step, a music bed and click sounds, from LAUNCH.md's `entrance`, `endCard`, `with`, `captions`, `music` and `clicks` roles (or the flags), as data in doc.json with stable ids (`bed`, `click-<n>`, `caption-<step>`), so the studio shows what the kit will render; a refresh never re-proposes (a deleted clip stays deleted) and `--motion` re-proposes on purpose, replacing only its own work. A document written in the older spellings (`frame.entrance`, `endCard`, a clip's `enter`/`exit`/`fx`, a prop's `animation`) is read into the vocabulary and `vos validate` says so.
|
|
96
|
+
**The cut's motion is the document's, in one vocabulary.** Every visual thing carries `anim` (`enter`, `exit`, `idle`; a kind, or a step with its seconds and, for words, `unit`, `direction`, `stagger`): the card (`frame.anim`, entering by `tilt-in`, `pull-out`, `rise` or `fade` and leaving by `recede` or `fade`), a text, image or video clip, a prop. The output lasts until the last clip ends; the card is on screen exactly while its clip runs (the footage, freezes included) and leaves at its end, so its `exit` plays over the clip's last seconds like every clip's; past the footage the clips play over the ground alone. A FREEZE (`freeze: [{id, at, seconds}]`, a source moment held for output seconds, beside the speed spans on the retime lane) freezes the footage anywhere, the middle of the take included; a segment's older `hold` is read as a freeze at its end. **The frame that STANDS for a take** is `still` (output seconds; `vos plan --still <t>`, LAUNCH.md `still:`), else the take's own last freeze (a poster's rest; a template's freezes, stamped `from`, never count), else the hero moment after the card and the opening clips have entered: the shelf's cover, the kit's card stills and `vos frames --at-still` all read that one derivation, and a plan never moves a still the author set. There is no end-card field and no entrance field. A COMPONENT is a TEMPLATE: a plain take on a shelf whose clips carry stable ids, laid onto a take at an anchor and stamped `from` with where its clips came from. A fresh `vos plan` proposes the card's enter, the templates the recipe names (`LAUNCH.md` `with: <ref>[@end|@start|@step:<id>|@<seconds>], …` or `--with`, repeatable; `endCard: <ref>` names one at the end), the END CARD when `endCard` is on or absent: the official `End card` template on vos.so (the platform's `Templates` project, promoted; any official template resolves by its title, `--with "End card"`, `--style "Split cover, landscape"`), laid at the end with the release's words and BRAND.md's mark, stamped `from: endcard`; offline, the house clips stand in (a freeze of the last frame for the card's seconds, the card receding over it, the headline, the release line, the wordmark and the mark as clips over the freeze), a caption per `actions.json` step, a music bed and click sounds, from LAUNCH.md's `entrance`, `endCard`, `with`, `captions`, `music` and `clicks` roles (or the flags), as data in doc.json with stable ids (`bed`, `click-<n>`, `caption-<step>`), so the studio shows what the kit will render; a refresh never re-proposes (a deleted clip stays deleted) and `--motion` re-proposes on purpose, replacing only its own work. A document written in the older spellings (`frame.entrance`, `endCard`, a clip's `enter`/`exit`/`fx`, a prop's `animation`) is read into the vocabulary and `vos validate` says so.
|
|
97
97
|
|
|
98
98
|
**A fresh take opens on a backdrop.** `create`, `record` and `plan` put the first ready loop from `GET /api/backdrops` behind the card (its ground colour as `frame.background`); `--background <slug|url|none>` overrides it, and offline the frame stays bare with a note.
|
|
99
99
|
|
|
@@ -203,6 +203,7 @@ import {
|
|
|
203
203
|
ZOOM_LEVEL_MIN,
|
|
204
204
|
ZOOM_SPAN_MIN,
|
|
205
205
|
docCardLayout,
|
|
206
|
+
outputEnd,
|
|
206
207
|
ratedSegments,
|
|
207
208
|
recommendedExportResolution,
|
|
208
209
|
spanOutputExtent,
|
|
@@ -456,6 +457,22 @@ function lintDoc(docIn) {
|
|
|
456
457
|
);
|
|
457
458
|
}
|
|
458
459
|
}
|
|
460
|
+
if (recording && doc.still !== void 0) {
|
|
461
|
+
const st = doc.still;
|
|
462
|
+
if (!isNum(st) || st < 0) {
|
|
463
|
+
problems.push("still must be a number \u2265 0 (OUTPUT seconds)");
|
|
464
|
+
} else {
|
|
465
|
+
const rated = ratedSegments(doc);
|
|
466
|
+
const end = outputEnd(
|
|
467
|
+
doc,
|
|
468
|
+
rated.reduce((a, s) => a + (s.out - s.in) / (s.rate ?? 1), 0)
|
|
469
|
+
);
|
|
470
|
+
if (st > end + 1e-6)
|
|
471
|
+
problems.push(
|
|
472
|
+
`still=${String(st)} is past the output's end (${end.toFixed(2)}s)`
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
459
476
|
for (const [i, seg] of (Array.isArray(doc.segments) ? doc.segments : []).entries()) {
|
|
460
477
|
const hold = seg.hold;
|
|
461
478
|
if (hold === void 0) continue;
|
|
@@ -971,6 +988,39 @@ function lintDoc(docIn) {
|
|
|
971
988
|
if (o.fx !== void 0) {
|
|
972
989
|
problems.push(`${name}.fx is text-only (media clips have enter/exit)`);
|
|
973
990
|
}
|
|
991
|
+
if (typeof o.key === "string" && o.key.startsWith("media:")) {
|
|
992
|
+
const ref = o.key.slice("media:".length);
|
|
993
|
+
const ids = new Set(
|
|
994
|
+
(Array.isArray(doc.media) ? doc.media : []).map((m) => typeof m.id === "string" ? m.id : "")
|
|
995
|
+
);
|
|
996
|
+
if (ref !== "" && !ids.has(ref))
|
|
997
|
+
problems.push(
|
|
998
|
+
`${name}.key names media "${ref}", which is not one of media[].id (media: alone is the primary)`
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
const lcf = o.frame;
|
|
1002
|
+
if (lcf !== void 0) {
|
|
1003
|
+
if (!isObj(lcf)) {
|
|
1004
|
+
problems.push(`${name}.frame must be an object (the layer's card)`);
|
|
1005
|
+
} else {
|
|
1006
|
+
const LCF = [
|
|
1007
|
+
"browserBar",
|
|
1008
|
+
"lean",
|
|
1009
|
+
"shadow",
|
|
1010
|
+
"shadowContact",
|
|
1011
|
+
"shadowColor",
|
|
1012
|
+
"cursor"
|
|
1013
|
+
];
|
|
1014
|
+
for (const k of Object.keys(lcf))
|
|
1015
|
+
if (!LCF.includes(k))
|
|
1016
|
+
problems.push(
|
|
1017
|
+
`${name}.frame.${k}: not a layer card field (${LCF.join(", ")})`
|
|
1018
|
+
);
|
|
1019
|
+
const lean = lcf.lean;
|
|
1020
|
+
if (lean !== void 0 && (!isObj(lean) || !isNum(lean.rx) || !isNum(lean.ry)))
|
|
1021
|
+
problems.push(`${name}.frame.lean must be { rx, ry } in degrees`);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
974
1024
|
if (typeof o.key !== "string" || o.key.length === 0) {
|
|
975
1025
|
problems.push(
|
|
976
1026
|
`${name}.key must be a non-empty media URL or take-dir file (e.g. "/logo.png")`
|
|
@@ -1419,6 +1469,7 @@ import { existsSync as existsSync4 } from "fs";
|
|
|
1419
1469
|
import { join as join4, resolve as resolve2 } from "path";
|
|
1420
1470
|
import { compileVosConfig } from "@vosjs/core";
|
|
1421
1471
|
import {
|
|
1472
|
+
docStillTime,
|
|
1422
1473
|
lowerToComposition,
|
|
1423
1474
|
momentsFromDoc as momentsFromDoc2,
|
|
1424
1475
|
planForDigest as planForDigest2,
|
|
@@ -2751,10 +2802,12 @@ async function framesTake(browser, dir, opts) {
|
|
|
2751
2802
|
shots.push({ time: clamp(m.outputAt), kind: "moment", momentId: m.id });
|
|
2752
2803
|
}
|
|
2753
2804
|
}
|
|
2805
|
+
if (opts.atStill)
|
|
2806
|
+
shots.push({ time: clamp(docStillTime(doc)), kind: "still" });
|
|
2754
2807
|
shots.sort((a, b) => a.time - b.time);
|
|
2755
2808
|
if (!shots.length)
|
|
2756
2809
|
throw new Error(
|
|
2757
|
-
"no frame times \u2014 pass --times/--frame, --at-zooms or --at-
|
|
2810
|
+
"no frame times \u2014 pass --times/--frame, --at-zooms, --at-moments or --at-still"
|
|
2758
2811
|
);
|
|
2759
2812
|
const outDir = resolve2(opts.outDir ?? join4(dir, "stills"));
|
|
2760
2813
|
await mkdir3(outDir, { recursive: true });
|
|
@@ -3625,15 +3678,15 @@ function proposeMotion(input, opts) {
|
|
|
3625
3678
|
const endStart = outputLength(doc);
|
|
3626
3679
|
const lastSeg = doc.segments.at(-1);
|
|
3627
3680
|
if (lastSeg) {
|
|
3628
|
-
const
|
|
3629
|
-
|
|
3630
|
-
);
|
|
3681
|
+
const atEnd = (f) => Math.abs(f.at - lastSeg.out) <= 1e-9 && sameMedia(f.media, lastSeg.media);
|
|
3682
|
+
const kept2 = (doc.freeze ?? []).find((f) => atEnd(f) && !f.from);
|
|
3683
|
+
const own = (doc.freeze ?? []).filter((f) => !atEnd(f));
|
|
3631
3684
|
const taken = new Set(own.map((f) => f.id));
|
|
3632
3685
|
let n = 0;
|
|
3633
3686
|
while (taken.has(`f${n}`)) n++;
|
|
3634
3687
|
doc.freeze = [
|
|
3635
3688
|
...own,
|
|
3636
|
-
{
|
|
3689
|
+
kept2 ? { ...kept2, seconds: Math.max(kept2.seconds, END_CARD_SECONDS) } : {
|
|
3637
3690
|
id: `f${n}`,
|
|
3638
3691
|
at: lastSeg.out,
|
|
3639
3692
|
seconds: END_CARD_SECONDS,
|
|
@@ -3800,13 +3853,11 @@ function isLightHexGround(hex2) {
|
|
|
3800
3853
|
import { existsSync as existsSync5 } from "fs";
|
|
3801
3854
|
import { readFile as readFile5 } from "fs/promises";
|
|
3802
3855
|
import { isAbsolute, join as join6, resolve as resolve3 } from "path";
|
|
3803
|
-
import { totalDuration } from "@vosjs/timeline";
|
|
3804
3856
|
import {
|
|
3805
3857
|
computeCardLayout,
|
|
3806
|
-
|
|
3858
|
+
docStillTime as docStillTime2,
|
|
3807
3859
|
migrateHostedDoc,
|
|
3808
3860
|
overlayRect,
|
|
3809
|
-
ratedSegments as ratedSegments5,
|
|
3810
3861
|
resolveOverlayStyle
|
|
3811
3862
|
} from "@vosjs/studio-core";
|
|
3812
3863
|
|
|
@@ -4046,11 +4097,7 @@ async function findPosterDocs(takeDir, launchRoles) {
|
|
|
4046
4097
|
return out;
|
|
4047
4098
|
}
|
|
4048
4099
|
function posterStillTime(doc, duration) {
|
|
4049
|
-
|
|
4050
|
-
if (rest != null) return rest;
|
|
4051
|
-
const footage = totalDuration(ratedSegments5(doc));
|
|
4052
|
-
const end = footage > 0 ? Math.min(duration, footage) : duration;
|
|
4053
|
-
return Math.max(0, end - 1 / 30);
|
|
4100
|
+
return Math.max(0, Math.min(duration, docStillTime2(doc)));
|
|
4054
4101
|
}
|
|
4055
4102
|
var DESIGN_H = 1080;
|
|
4056
4103
|
function designFrame(px) {
|
|
@@ -6245,6 +6292,8 @@ async function planTake(dir, opts = {}) {
|
|
|
6245
6292
|
if (prev.objects?.length) doc.objects = prev.objects;
|
|
6246
6293
|
if (prev.audio.length) doc.audio = prev.audio;
|
|
6247
6294
|
if (prev.camMotion?.length) doc.camMotion = prev.camMotion;
|
|
6295
|
+
if (prev.still !== void 0) doc.still = prev.still;
|
|
6296
|
+
if (opts.still != null) doc.still = opts.still;
|
|
6248
6297
|
await writeJson(take.paths.doc, doc, true);
|
|
6249
6298
|
return {
|
|
6250
6299
|
doc,
|
|
@@ -6323,6 +6372,7 @@ async function planTake(dir, opts = {}) {
|
|
|
6323
6372
|
doc = proposed.doc;
|
|
6324
6373
|
motion = { notes: proposed.notes, skipped: proposed.skipped };
|
|
6325
6374
|
}
|
|
6375
|
+
if (opts.still != null) doc.still = opts.still;
|
|
6326
6376
|
await writeJson(take.paths.doc, doc, true);
|
|
6327
6377
|
return {
|
|
6328
6378
|
doc,
|
|
@@ -6364,7 +6414,7 @@ var KEYS = [
|
|
|
6364
6414
|
{ key: "camKey", file: CAM_NAME }
|
|
6365
6415
|
];
|
|
6366
6416
|
function isTakeRelativeKey(key) {
|
|
6367
|
-
return !!key && !/^(https?:|blob:|data:|\/\/)/.test(key) && !key.startsWith("/api/");
|
|
6417
|
+
return !!key && !/^(https?:|blob:|data:|media:|\/\/)/.test(key) && !key.startsWith("/api/");
|
|
6368
6418
|
}
|
|
6369
6419
|
var takeRelativeFile = (key) => key.replace(/^\/+/, "");
|
|
6370
6420
|
function docMediaRefs(doc, keep = isTakeRelativeKey) {
|
|
@@ -8969,6 +9019,7 @@ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set([
|
|
|
8969
9019
|
"draft",
|
|
8970
9020
|
"at-zooms",
|
|
8971
9021
|
"at-moments",
|
|
9022
|
+
"at-still",
|
|
8972
9023
|
"no-frames",
|
|
8973
9024
|
"media",
|
|
8974
9025
|
"print",
|
|
@@ -8983,9 +9034,9 @@ var HELP = `vos \u2014 record a browser flow, plan effects, render a product vid
|
|
|
8983
9034
|
Take pipeline
|
|
8984
9035
|
vos create --actions actions.json [--url <url>] [--out take] [out.webm] [--strict] [--max-duration <s>] [--background <slug|url|none>] [render flags] [--json]
|
|
8985
9036
|
vos record --actions actions.json [--url <url>] [--out take] [--strict] [--max-duration <s>] [--background <slug|url|none>] [--json]
|
|
8986
|
-
vos plan <take> [--fresh] [--reuse [--from <doc.json>]] [--style <doc.json|vosId>] [--with <doc.json|vosId>[@end|@start|@step:<id>|@<s>]]... [--background <slug|url|none>] [--motion] [--headline "\u2026"] [--kicker "\u2026"] [--launch LAUNCH.md] [--brand BRAND.md] [--music <slug|mood|none>] [--entrance tilt-in|pull-out|rise|fade|none] [--end-card on|none|<doc.json|vosId>] [--captions none] [--clicks none] [--release v2.1] [--json]
|
|
9037
|
+
vos plan <take> [--fresh] [--reuse [--from <doc.json>]] [--style <doc.json|vosId>] [--with <doc.json|vosId>[@end|@start|@step:<id>|@<s>]]... [--background <slug|url|none>] [--motion] [--headline "\u2026"] [--kicker "\u2026"] [--launch LAUNCH.md] [--brand BRAND.md] [--music <slug|mood|none>] [--entrance tilt-in|pull-out|rise|fade|none] [--end-card on|none|<doc.json|vosId>] [--captions none] [--clicks none] [--still <t>] [--release v2.1] [--json]
|
|
8987
9038
|
vos render <take> [out.webm] [--width] [--height] [--fps] [--format webm|mp4] [--parallel N] [--range a..b] [--draft] [--frame <kind>] [--background <url|slug>] [--set <path=value>]... [--json]
|
|
8988
|
-
vos frames <take> [--times 0,25%,50%,75%,100%] [--frame <t>] [--at-zooms] [--at-moments] [--size WxH] [--out dir] [--background <url|slug>] [--set <path=value>]... [--json]
|
|
9039
|
+
vos frames <take> [--times 0,25%,50%,75%,100%] [--frame <t>] [--at-zooms] [--at-moments] [--at-still] [--size WxH] [--out dir] [--background <url|slug>] [--set <path=value>]... [--json]
|
|
8989
9040
|
vos deliver <take> --to cws,producthunt,x,linkedin,og,github,youtube (or all) [--launch LAUNCH.md] [--look plate|gradient|dark|none] [--brand BRAND.md] [--composed] [--set path=value] [--release v2.1] [--out dir] [--times a,b] [--range a..b] [--parallel N] [--json]
|
|
8990
9041
|
vos digest <take> [--out dir] [--full 960] [--crop 640] [--no-frames] [--transcript <file.json>] [--style <doc.json|vosId>] [--json]
|
|
8991
9042
|
vos brand <url> [--out BRAND.md] [--json]
|
|
@@ -9477,12 +9528,19 @@ async function cmdPlan(argv) {
|
|
|
9477
9528
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
9478
9529
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
9479
9530
|
const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
|
|
9531
|
+
const stillRaw = strFlag(flags, "still") ?? release.launchRoles.still;
|
|
9532
|
+
const still = stillRaw === void 0 ? null : Number(stillRaw);
|
|
9533
|
+
if (still !== null && !(Number.isFinite(still) && still >= 0))
|
|
9534
|
+
throw new UsageError(
|
|
9535
|
+
`--still expects output seconds \u2265 0, got "${stillRaw}"`
|
|
9536
|
+
);
|
|
9480
9537
|
const s = await planTake(dir, {
|
|
9481
9538
|
...style ? { style } : {},
|
|
9482
9539
|
...reuse ? { reuse } : {},
|
|
9483
9540
|
backdrop,
|
|
9484
9541
|
words: release.words,
|
|
9485
9542
|
mark: release.mark,
|
|
9543
|
+
...still !== null ? { still } : {},
|
|
9486
9544
|
...motionWanted ? {
|
|
9487
9545
|
motion: {
|
|
9488
9546
|
words: release.words,
|
|
@@ -9730,6 +9788,7 @@ async function cmdFrames(argv) {
|
|
|
9730
9788
|
const timesRaw = strFlag(flags, "times");
|
|
9731
9789
|
const atZooms = flags["at-zooms"] === true;
|
|
9732
9790
|
const atMoments = flags["at-moments"] === true;
|
|
9791
|
+
const atStill = flags["at-still"] === true;
|
|
9733
9792
|
let times;
|
|
9734
9793
|
try {
|
|
9735
9794
|
times = frameRaw !== void 0 ? parseTimes(frameRaw, duration) : timesRaw !== void 0 ? parseTimes(timesRaw, duration) : atZooms || atMoments ? [] : parseTimes("0,25%,50%,75%,100%", duration);
|
|
@@ -9743,6 +9802,7 @@ async function cmdFrames(argv) {
|
|
|
9743
9802
|
times,
|
|
9744
9803
|
atZooms,
|
|
9745
9804
|
atMoments,
|
|
9805
|
+
atStill,
|
|
9746
9806
|
width: size?.width,
|
|
9747
9807
|
height: size?.height,
|
|
9748
9808
|
outDir: strFlag(flags, "out"),
|
|
@@ -10361,4 +10421,4 @@ export {
|
|
|
10361
10421
|
convertAgentBrowser,
|
|
10362
10422
|
run
|
|
10363
10423
|
};
|
|
10364
|
-
//# sourceMappingURL=chunk-
|
|
10424
|
+
//# sourceMappingURL=chunk-IJ5A4TL3.js.map
|