@vosjs/cli 0.25.1 → 0.26.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 +1 -1
- package/dist/{chunk-GHJ2BFQG.js → chunk-I3UUIBSH.js} +43 -16
- package/dist/chunk-I3UUIBSH.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-VSENMRFF.js} +2 -2
- package/package.json +7 -7
- package/schema/doc.schema.json +5 -0
- package/dist/chunk-GHJ2BFQG.js.map +0 -1
- /package/dist/{run-NTVAMME2.js.map → run-VSENMRFF.js.map} +0 -0
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ vos plan take --reuse # re-time that cut onto
|
|
|
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;
|
|
@@ -1419,6 +1436,7 @@ import { existsSync as existsSync4 } from "fs";
|
|
|
1419
1436
|
import { join as join4, resolve as resolve2 } from "path";
|
|
1420
1437
|
import { compileVosConfig } from "@vosjs/core";
|
|
1421
1438
|
import {
|
|
1439
|
+
docStillTime,
|
|
1422
1440
|
lowerToComposition,
|
|
1423
1441
|
momentsFromDoc as momentsFromDoc2,
|
|
1424
1442
|
planForDigest as planForDigest2,
|
|
@@ -2751,10 +2769,12 @@ async function framesTake(browser, dir, opts) {
|
|
|
2751
2769
|
shots.push({ time: clamp(m.outputAt), kind: "moment", momentId: m.id });
|
|
2752
2770
|
}
|
|
2753
2771
|
}
|
|
2772
|
+
if (opts.atStill)
|
|
2773
|
+
shots.push({ time: clamp(docStillTime(doc)), kind: "still" });
|
|
2754
2774
|
shots.sort((a, b) => a.time - b.time);
|
|
2755
2775
|
if (!shots.length)
|
|
2756
2776
|
throw new Error(
|
|
2757
|
-
"no frame times \u2014 pass --times/--frame, --at-zooms or --at-
|
|
2777
|
+
"no frame times \u2014 pass --times/--frame, --at-zooms, --at-moments or --at-still"
|
|
2758
2778
|
);
|
|
2759
2779
|
const outDir = resolve2(opts.outDir ?? join4(dir, "stills"));
|
|
2760
2780
|
await mkdir3(outDir, { recursive: true });
|
|
@@ -3625,15 +3645,15 @@ function proposeMotion(input, opts) {
|
|
|
3625
3645
|
const endStart = outputLength(doc);
|
|
3626
3646
|
const lastSeg = doc.segments.at(-1);
|
|
3627
3647
|
if (lastSeg) {
|
|
3628
|
-
const
|
|
3629
|
-
|
|
3630
|
-
);
|
|
3648
|
+
const atEnd = (f) => Math.abs(f.at - lastSeg.out) <= 1e-9 && sameMedia(f.media, lastSeg.media);
|
|
3649
|
+
const kept2 = (doc.freeze ?? []).find((f) => atEnd(f) && !f.from);
|
|
3650
|
+
const own = (doc.freeze ?? []).filter((f) => !atEnd(f));
|
|
3631
3651
|
const taken = new Set(own.map((f) => f.id));
|
|
3632
3652
|
let n = 0;
|
|
3633
3653
|
while (taken.has(`f${n}`)) n++;
|
|
3634
3654
|
doc.freeze = [
|
|
3635
3655
|
...own,
|
|
3636
|
-
{
|
|
3656
|
+
kept2 ? { ...kept2, seconds: Math.max(kept2.seconds, END_CARD_SECONDS) } : {
|
|
3637
3657
|
id: `f${n}`,
|
|
3638
3658
|
at: lastSeg.out,
|
|
3639
3659
|
seconds: END_CARD_SECONDS,
|
|
@@ -3800,13 +3820,11 @@ function isLightHexGround(hex2) {
|
|
|
3800
3820
|
import { existsSync as existsSync5 } from "fs";
|
|
3801
3821
|
import { readFile as readFile5 } from "fs/promises";
|
|
3802
3822
|
import { isAbsolute, join as join6, resolve as resolve3 } from "path";
|
|
3803
|
-
import { totalDuration } from "@vosjs/timeline";
|
|
3804
3823
|
import {
|
|
3805
3824
|
computeCardLayout,
|
|
3806
|
-
|
|
3825
|
+
docStillTime as docStillTime2,
|
|
3807
3826
|
migrateHostedDoc,
|
|
3808
3827
|
overlayRect,
|
|
3809
|
-
ratedSegments as ratedSegments5,
|
|
3810
3828
|
resolveOverlayStyle
|
|
3811
3829
|
} from "@vosjs/studio-core";
|
|
3812
3830
|
|
|
@@ -4046,11 +4064,7 @@ async function findPosterDocs(takeDir, launchRoles) {
|
|
|
4046
4064
|
return out;
|
|
4047
4065
|
}
|
|
4048
4066
|
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);
|
|
4067
|
+
return Math.max(0, Math.min(duration, docStillTime2(doc)));
|
|
4054
4068
|
}
|
|
4055
4069
|
var DESIGN_H = 1080;
|
|
4056
4070
|
function designFrame(px) {
|
|
@@ -6245,6 +6259,8 @@ async function planTake(dir, opts = {}) {
|
|
|
6245
6259
|
if (prev.objects?.length) doc.objects = prev.objects;
|
|
6246
6260
|
if (prev.audio.length) doc.audio = prev.audio;
|
|
6247
6261
|
if (prev.camMotion?.length) doc.camMotion = prev.camMotion;
|
|
6262
|
+
if (prev.still !== void 0) doc.still = prev.still;
|
|
6263
|
+
if (opts.still != null) doc.still = opts.still;
|
|
6248
6264
|
await writeJson(take.paths.doc, doc, true);
|
|
6249
6265
|
return {
|
|
6250
6266
|
doc,
|
|
@@ -6323,6 +6339,7 @@ async function planTake(dir, opts = {}) {
|
|
|
6323
6339
|
doc = proposed.doc;
|
|
6324
6340
|
motion = { notes: proposed.notes, skipped: proposed.skipped };
|
|
6325
6341
|
}
|
|
6342
|
+
if (opts.still != null) doc.still = opts.still;
|
|
6326
6343
|
await writeJson(take.paths.doc, doc, true);
|
|
6327
6344
|
return {
|
|
6328
6345
|
doc,
|
|
@@ -8969,6 +8986,7 @@ var BOOLEAN_FLAGS5 = /* @__PURE__ */ new Set([
|
|
|
8969
8986
|
"draft",
|
|
8970
8987
|
"at-zooms",
|
|
8971
8988
|
"at-moments",
|
|
8989
|
+
"at-still",
|
|
8972
8990
|
"no-frames",
|
|
8973
8991
|
"media",
|
|
8974
8992
|
"print",
|
|
@@ -8983,9 +9001,9 @@ var HELP = `vos \u2014 record a browser flow, plan effects, render a product vid
|
|
|
8983
9001
|
Take pipeline
|
|
8984
9002
|
vos create --actions actions.json [--url <url>] [--out take] [out.webm] [--strict] [--max-duration <s>] [--background <slug|url|none>] [render flags] [--json]
|
|
8985
9003
|
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]
|
|
9004
|
+
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
9005
|
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]
|
|
9006
|
+
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
9007
|
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
9008
|
vos digest <take> [--out dir] [--full 960] [--crop 640] [--no-frames] [--transcript <file.json>] [--style <doc.json|vosId>] [--json]
|
|
8991
9009
|
vos brand <url> [--out BRAND.md] [--json]
|
|
@@ -9477,12 +9495,19 @@ async function cmdPlan(argv) {
|
|
|
9477
9495
|
const backdrop = hasDoc ? null : await takeBackdrop(flags, r);
|
|
9478
9496
|
const release = await releaseInputs(dir, flags, r, multi.with ?? []);
|
|
9479
9497
|
const motionWanted = !hasDoc || flags.motion === true || flags.fresh === true;
|
|
9498
|
+
const stillRaw = strFlag(flags, "still") ?? release.launchRoles.still;
|
|
9499
|
+
const still = stillRaw === void 0 ? null : Number(stillRaw);
|
|
9500
|
+
if (still !== null && !(Number.isFinite(still) && still >= 0))
|
|
9501
|
+
throw new UsageError(
|
|
9502
|
+
`--still expects output seconds \u2265 0, got "${stillRaw}"`
|
|
9503
|
+
);
|
|
9480
9504
|
const s = await planTake(dir, {
|
|
9481
9505
|
...style ? { style } : {},
|
|
9482
9506
|
...reuse ? { reuse } : {},
|
|
9483
9507
|
backdrop,
|
|
9484
9508
|
words: release.words,
|
|
9485
9509
|
mark: release.mark,
|
|
9510
|
+
...still !== null ? { still } : {},
|
|
9486
9511
|
...motionWanted ? {
|
|
9487
9512
|
motion: {
|
|
9488
9513
|
words: release.words,
|
|
@@ -9730,6 +9755,7 @@ async function cmdFrames(argv) {
|
|
|
9730
9755
|
const timesRaw = strFlag(flags, "times");
|
|
9731
9756
|
const atZooms = flags["at-zooms"] === true;
|
|
9732
9757
|
const atMoments = flags["at-moments"] === true;
|
|
9758
|
+
const atStill = flags["at-still"] === true;
|
|
9733
9759
|
let times;
|
|
9734
9760
|
try {
|
|
9735
9761
|
times = frameRaw !== void 0 ? parseTimes(frameRaw, duration) : timesRaw !== void 0 ? parseTimes(timesRaw, duration) : atZooms || atMoments ? [] : parseTimes("0,25%,50%,75%,100%", duration);
|
|
@@ -9743,6 +9769,7 @@ async function cmdFrames(argv) {
|
|
|
9743
9769
|
times,
|
|
9744
9770
|
atZooms,
|
|
9745
9771
|
atMoments,
|
|
9772
|
+
atStill,
|
|
9746
9773
|
width: size?.width,
|
|
9747
9774
|
height: size?.height,
|
|
9748
9775
|
outDir: strFlag(flags, "out"),
|
|
@@ -10361,4 +10388,4 @@ export {
|
|
|
10361
10388
|
convertAgentBrowser,
|
|
10362
10389
|
run
|
|
10363
10390
|
};
|
|
10364
|
-
//# sourceMappingURL=chunk-
|
|
10391
|
+
//# sourceMappingURL=chunk-I3UUIBSH.js.map
|