@vosjs/cli 0.20.0 → 0.22.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 +3 -3
- package/dist/{chunk-ZONOZZZY.js → chunk-CRZTGWF3.js} +96 -17
- package/dist/chunk-CRZTGWF3.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +0 -18
- package/dist/index.js +1 -1
- package/dist/{run-ZIMJOQRN.js → run-IRE2RO5J.js} +2 -2
- package/package.json +6 -6
- package/schema/doc.schema.json +55 -2
- package/dist/chunk-ZONOZZZY.js.map +0 -1
- /package/dist/{run-ZIMJOQRN.js.map → run-IRE2RO5J.js.map} +0 -0
package/README.md
CHANGED
|
@@ -89,9 +89,9 @@ 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
|
-
**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
|
|
92
|
+
**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.
|
|
93
93
|
|
|
94
|
-
**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;
|
|
94
|
+
**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 house end card when `endCard` is on or absent (a freeze of the last frame for the card's seconds, the card receding over it, and the headline, the release line, the wordmark and BRAND.md's mark as clips over the freeze, every one `from: endcard`), 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.
|
|
95
95
|
|
|
96
96
|
**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.
|
|
97
97
|
|
|
@@ -186,7 +186,7 @@ vos brand https://your.app --out BRAND.md # the brand kit,
|
|
|
186
186
|
|
|
187
187
|
[`schema/channel-specs.json`](./schema/channel-specs.json) holds per-channel launch-asset specs: dimensions, byte and duration ceilings, and a genre per image destination (`screenshot` is the real page from the take, full bleed; `card` is a composed cover). Channels: `cws`, `producthunt` (`ph`), `x`, `linkedin` (`li`), `og`, `github` (`gh`), `youtube` (`yt`), `shorts-linkedin` (`shorts`), or `all`. `vos deliver <take> --to <channels>` loops them in one pass and writes `kit.json`, the manifest the `launch-kit` skill builds the rest of the release around; an asset that misses its spec lands in `skipped[]` with the reason, and the verb exits 1 when nothing was produced. Flags: `--release <tag>`, `--out <take>/kit`, `--times`, `--range`, `--parallel`, `--launch LAUNCH.md`, `--look`, `--brand`, `--composed` (keep the cut's camera and chrome on screenshot stills instead of the full-bleed page), `--set`, `--background`. `vos validate` reads a kit back from its bytes (a `.png` that is WebP, a lying size or duration, a set under its count, a byte ceiling).
|
|
188
188
|
|
|
189
|
-
**A poster is a document, and deliver renders it.** A card-genre destination (OG, LinkedIn, X, the YouTube thumbnail, the CWS tile and marquee, the GitHub social preview) renders from the poster document of its aspect class (`landscape`, `square`, `portrait`, `tile`), found beside the take as `poster/<class>/doc.json` (`poster/doc.json` serves every class) or named in LAUNCH.md (`poster: <path>`, `poster-<class>: <path>`, a path to a doc.json or to a pulled poster take), at the document's REST (
|
|
189
|
+
**A poster is a document, and deliver renders it.** A card-genre destination (OG, LinkedIn, X, the YouTube thumbnail, the CWS tile and marquee, the GitHub social preview) renders from the poster document of its aspect class (`landscape`, `square`, `portrait`, `tile`), found beside the take as `poster/<class>/doc.json` (`poster/doc.json` serves every class) or named in LAUNCH.md (`poster: <path>`, `poster-<class>: <path>`, a path to a doc.json or to a pulled poster take), at the document's REST (where its last freeze begins, the composed frame before nothing moves). The poster is a plain take document: the card placed by `frame.inset`, leaned by the tilt track, the words and the mark as `stage-*` clips, a trailing freeze; an agent writes it with `vos plan --style <poster>` from a poster on a shelf, or by hand, and pushes it like any take. `kit.json` records `source: "poster"`, the class, the file, the vos it tracks, the shot rect and the text boxes read from the document. A class with no document is the take's own frame, said once. Deliver composes nothing; it applies each video destination's mechanics (the README loop drops the card's motion, every clip a template placed, the captions and the sound; a channel that autoplays muted drops the bed; the 9:16 cut reframes and follows the camera) and verifies.
|
|
190
190
|
|
|
191
191
|
`vos brand <url>` reads the site's `/design.md` first (the convention beside `/llms.txt`), then `/llms.txt`, then witnesses one page, and writes `BRAND.md`: the palette, faces, marks and the avoid list, with the provenance of every value, so a brand is resolved before any asset is authored.
|
|
192
192
|
|
|
@@ -188,6 +188,8 @@ import {
|
|
|
188
188
|
TEXT_ENTER_KINDS,
|
|
189
189
|
TEXT_EXIT_KINDS,
|
|
190
190
|
EXPORT_RESOLUTION_OPTIONS,
|
|
191
|
+
FREEZE_SECONDS_MAX,
|
|
192
|
+
FREEZE_SECONDS_MIN,
|
|
191
193
|
SPEED_RATE_MAX,
|
|
192
194
|
SPEED_RATE_MIN,
|
|
193
195
|
TILT_DEG_MAX,
|
|
@@ -398,9 +400,37 @@ function lintDoc(docIn) {
|
|
|
398
400
|
}
|
|
399
401
|
for (const [i, seg] of (Array.isArray(doc.segments) ? doc.segments : []).entries()) {
|
|
400
402
|
const hold = seg.hold;
|
|
401
|
-
if (hold
|
|
403
|
+
if (hold === void 0) continue;
|
|
404
|
+
if (!isNum(hold) || hold < 0 || hold > FREEZE_SECONDS_MAX) {
|
|
402
405
|
problems.push(
|
|
403
|
-
`segments[${i}].hold must be 0
|
|
406
|
+
`segments[${i}].hold must be 0..${FREEZE_SECONDS_MAX} output seconds (got ${String(hold)})`
|
|
407
|
+
);
|
|
408
|
+
} else if (hold > 0) {
|
|
409
|
+
warnings.push(
|
|
410
|
+
`segments[${i}].hold is a legacy spelling, read as a freeze at ${String(seg.out)}s (doc.freeze); vos plan writes that shape`
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (doc.freeze !== void 0 && !Array.isArray(doc.freeze)) {
|
|
415
|
+
problems.push("freeze must be an array of {id, at, seconds}");
|
|
416
|
+
}
|
|
417
|
+
const freezes = Array.isArray(doc.freeze) ? doc.freeze : [];
|
|
418
|
+
const freezeIds = /* @__PURE__ */ new Set();
|
|
419
|
+
for (const [i, raw] of freezes.entries()) {
|
|
420
|
+
const f = raw;
|
|
421
|
+
const name = `freeze[${i}]${typeof f.id === "string" ? ` (${f.id})` : ""}`;
|
|
422
|
+
if (typeof f.id !== "string" || !f.id)
|
|
423
|
+
problems.push(`${name}: id must be a string`);
|
|
424
|
+
else if (freezeIds.has(f.id)) problems.push(`${name}: duplicate id`);
|
|
425
|
+
else freezeIds.add(f.id);
|
|
426
|
+
if (!isNum(f.at) || f.at < 0 || f.at > duration + EPS) {
|
|
427
|
+
problems.push(
|
|
428
|
+
`${name}: at must be a SOURCE moment inside the recording (0..${duration.toFixed(2)}s, got ${String(f.at)})`
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
if (!isNum(f.seconds) || f.seconds < FREEZE_SECONDS_MIN - EPS || f.seconds > FREEZE_SECONDS_MAX + EPS) {
|
|
432
|
+
problems.push(
|
|
433
|
+
`${name}: seconds must be ${FREEZE_SECONDS_MIN}..${FREEZE_SECONDS_MAX} output seconds (got ${String(f.seconds)})`
|
|
404
434
|
);
|
|
405
435
|
}
|
|
406
436
|
}
|
|
@@ -3399,7 +3429,6 @@ function pickMoments(measured, opts = {}) {
|
|
|
3399
3429
|
// src/plugin/motionPlan.ts
|
|
3400
3430
|
import {
|
|
3401
3431
|
END_CARD_FROM,
|
|
3402
|
-
END_CARD_RECEDE,
|
|
3403
3432
|
END_CARD_SECONDS,
|
|
3404
3433
|
applyTemplate,
|
|
3405
3434
|
docOutputDuration,
|
|
@@ -3526,13 +3555,32 @@ function proposeMotion(input, opts) {
|
|
|
3526
3555
|
if (sub && sub !== headline) card.sub = sub;
|
|
3527
3556
|
if (brand) card.wordmark = brand;
|
|
3528
3557
|
if (opts.mark) card.mark = opts.mark;
|
|
3558
|
+
const endStart = outputLength(doc);
|
|
3559
|
+
const lastSeg = doc.segments.at(-1);
|
|
3560
|
+
if (lastSeg) {
|
|
3561
|
+
const own = (doc.freeze ?? []).filter(
|
|
3562
|
+
(f) => Math.abs(f.at - lastSeg.out) > 1e-9
|
|
3563
|
+
);
|
|
3564
|
+
const taken = new Set(own.map((f) => f.id));
|
|
3565
|
+
let n = 0;
|
|
3566
|
+
while (taken.has(`f${n}`)) n++;
|
|
3567
|
+
doc.freeze = [
|
|
3568
|
+
...own,
|
|
3569
|
+
{
|
|
3570
|
+
id: `f${n}`,
|
|
3571
|
+
at: lastSeg.out,
|
|
3572
|
+
seconds: END_CARD_SECONDS,
|
|
3573
|
+
from: END_CARD_FROM
|
|
3574
|
+
}
|
|
3575
|
+
].sort((a, b) => a.at - b.at);
|
|
3576
|
+
}
|
|
3529
3577
|
doc.overlays = [
|
|
3530
3578
|
...doc.overlays ?? [],
|
|
3531
|
-
...endCardClips(card, doc,
|
|
3579
|
+
...endCardClips(card, doc, endStart)
|
|
3532
3580
|
];
|
|
3533
3581
|
doc.frame.anim = {
|
|
3534
3582
|
...doc.frame.anim ?? {},
|
|
3535
|
-
exit: { kind: "recede", seconds:
|
|
3583
|
+
exit: { kind: "recede", seconds: END_CARD_SECONDS }
|
|
3536
3584
|
};
|
|
3537
3585
|
notes.push("end card");
|
|
3538
3586
|
} else {
|
|
@@ -3593,7 +3641,7 @@ function proposeMotion(input, opts) {
|
|
|
3593
3641
|
fadeIn: 0.6,
|
|
3594
3642
|
fadeOut,
|
|
3595
3643
|
loop: track.duration < length,
|
|
3596
|
-
loopLen: track.duration < length ? length : void 0,
|
|
3644
|
+
loopLen: track.duration < length ? Math.round(length * 1e3) / 1e3 : void 0,
|
|
3597
3645
|
duck: hasMic
|
|
3598
3646
|
});
|
|
3599
3647
|
notes.push(`bed ${track.slug}`);
|
|
@@ -3649,6 +3697,11 @@ function destinationMechanics(d, doc) {
|
|
|
3649
3697
|
notes.push(loop ? "no template clips, no captions" : "no captions");
|
|
3650
3698
|
}
|
|
3651
3699
|
}
|
|
3700
|
+
if (loop) {
|
|
3701
|
+
const keptFreezes = (doc.freeze ?? []).filter((f) => !f.from);
|
|
3702
|
+
if (keptFreezes.length !== (doc.freeze ?? []).length)
|
|
3703
|
+
set.push(`freeze=${JSON.stringify(keptFreezes)}`);
|
|
3704
|
+
}
|
|
3652
3705
|
if (portrait) {
|
|
3653
3706
|
set.push("frame.fit=cover");
|
|
3654
3707
|
set.push('frame.inset={"left":0.06,"right":0.06,"top":0.17,"bottom":0.17}');
|
|
@@ -3679,11 +3732,13 @@ function isLightHexGround(hex2) {
|
|
|
3679
3732
|
import { existsSync as existsSync5 } from "fs";
|
|
3680
3733
|
import { readFile as readFile5 } from "fs/promises";
|
|
3681
3734
|
import { isAbsolute, join as join6, resolve as resolve3 } from "path";
|
|
3735
|
+
import { totalDuration } from "@vosjs/timeline";
|
|
3682
3736
|
import {
|
|
3683
3737
|
computeCardLayout,
|
|
3684
3738
|
docRestTime,
|
|
3685
3739
|
migrateHostedDoc,
|
|
3686
3740
|
overlayRect,
|
|
3741
|
+
ratedSegments as ratedSegments5,
|
|
3687
3742
|
resolveOverlayStyle
|
|
3688
3743
|
} from "@vosjs/studio-core";
|
|
3689
3744
|
|
|
@@ -3925,7 +3980,9 @@ async function findPosterDocs(takeDir, launchRoles) {
|
|
|
3925
3980
|
function posterStillTime(doc, duration) {
|
|
3926
3981
|
const rest = docRestTime(doc);
|
|
3927
3982
|
if (rest != null) return rest;
|
|
3928
|
-
|
|
3983
|
+
const footage = totalDuration(ratedSegments5(doc));
|
|
3984
|
+
const end = footage > 0 ? Math.min(duration, footage) : duration;
|
|
3985
|
+
return Math.max(0, end - 1 / 30);
|
|
3929
3986
|
}
|
|
3930
3987
|
var DESIGN_H = 1080;
|
|
3931
3988
|
function designFrame(px) {
|
|
@@ -5789,6 +5846,7 @@ import {
|
|
|
5789
5846
|
} from "@vosjs/studio-core";
|
|
5790
5847
|
|
|
5791
5848
|
// src/plugin/reuse.ts
|
|
5849
|
+
import { docFreezes } from "@vosjs/studio-core";
|
|
5792
5850
|
var MIN_SPAN = 0.15;
|
|
5793
5851
|
function matchStep(old, newSteps) {
|
|
5794
5852
|
const usable = (s) => !!s && s.skipped !== true;
|
|
@@ -5950,6 +6008,30 @@ function retimeCut(prev, newSteps, newDurationMs) {
|
|
|
5950
6008
|
newDuration,
|
|
5951
6009
|
report
|
|
5952
6010
|
);
|
|
6011
|
+
const freeze = [];
|
|
6012
|
+
for (const f of docFreezes(prev)) {
|
|
6013
|
+
let at2 = null;
|
|
6014
|
+
if (f.anchor) {
|
|
6015
|
+
at2 = resolveAnchor2(f.anchor, newSteps);
|
|
6016
|
+
if (at2 === null) {
|
|
6017
|
+
report.flagged.push(
|
|
6018
|
+
`freeze ${f.id}: its anchored step (${String(f.anchor.step)}) is missing or skipped in the new recording \u2014 fell back to the step map`
|
|
6019
|
+
);
|
|
6020
|
+
} else report.anchored++;
|
|
6021
|
+
}
|
|
6022
|
+
if (at2 === null) {
|
|
6023
|
+
at2 = stepMap.map(f.at);
|
|
6024
|
+
report.mapped++;
|
|
6025
|
+
}
|
|
6026
|
+
if (at2 < 0 || at2 > newDuration) {
|
|
6027
|
+
report.flagged.push(
|
|
6028
|
+
`freeze ${f.id}: lands outside the new recording (${at2.toFixed(2)}s) \u2014 dropped`
|
|
6029
|
+
);
|
|
6030
|
+
continue;
|
|
6031
|
+
}
|
|
6032
|
+
freeze.push({ ...f, at: +at2.toFixed(3) });
|
|
6033
|
+
}
|
|
6034
|
+
freeze.sort((a, b) => a.at - b.at);
|
|
5953
6035
|
const rejected = [];
|
|
5954
6036
|
for (const lane of ["zoom", "tilt", "speed"]) {
|
|
5955
6037
|
rejected.push(
|
|
@@ -5963,7 +6045,7 @@ function retimeCut(prev, newSteps, newDurationMs) {
|
|
|
5963
6045
|
)
|
|
5964
6046
|
);
|
|
5965
6047
|
}
|
|
5966
|
-
return { segments, zoom, speed, tilt, rejected, report };
|
|
6048
|
+
return { segments, zoom, speed, freeze, tilt, rejected, report };
|
|
5967
6049
|
}
|
|
5968
6050
|
|
|
5969
6051
|
// src/plugin/plan.ts
|
|
@@ -5992,7 +6074,7 @@ function patchStageWords(doc, words) {
|
|
|
5992
6074
|
}
|
|
5993
6075
|
function applyStyle(seed, doc, opts) {
|
|
5994
6076
|
const parts = layoutOf(seed);
|
|
5995
|
-
const carries = parts.clips.length > 0 || parts.lean || parts.
|
|
6077
|
+
const carries = parts.clips.length > 0 || parts.lean || parts.freeze;
|
|
5996
6078
|
if (!carries) return { doc: copyStyle(seed, doc), layout: void 0 };
|
|
5997
6079
|
const keys = opts.mark ? { "stage-mark": opts.mark.key } : void 0;
|
|
5998
6080
|
const { doc: next, notes } = copyLayout(seed, copyStyle(seed, doc), { keys });
|
|
@@ -6018,10 +6100,7 @@ async function planTake(dir, opts = {}) {
|
|
|
6018
6100
|
doc = copyStyle(prev, doc);
|
|
6019
6101
|
const rt = retimeCut(prev, meta.steps ?? [], meta.durationMs);
|
|
6020
6102
|
doc.segments = rt.segments;
|
|
6021
|
-
|
|
6022
|
-
const last = doc.segments.at(-1);
|
|
6023
|
-
if (typeof prevHold === "number" && prevHold > 0 && last)
|
|
6024
|
-
last.hold = prevHold;
|
|
6103
|
+
if (rt.freeze.length) doc.freeze = rt.freeze;
|
|
6025
6104
|
if (rt.rejected.length) doc.rejected = rt.rejected;
|
|
6026
6105
|
const manualZoom = rt.zoom;
|
|
6027
6106
|
const autoZoom = planAutoZoom(doc.source.cursor, {
|
|
@@ -8855,7 +8934,7 @@ Screenshot-genre stills never take a look.
|
|
|
8855
8934
|
A POSTER is a document, never a template: a plain take whose card sits
|
|
8856
8935
|
where the poster wants it (frame.inset), leans (the tilt track), carries
|
|
8857
8936
|
the words and the mark as clips (ids stage-title, stage-kicker,
|
|
8858
|
-
stage-brand, stage-mark) and ends on a trailing
|
|
8937
|
+
stage-brand, stage-mark) and ends on a trailing freeze whose start is the
|
|
8859
8938
|
still. Card-genre destinations (OG, LinkedIn, X, YouTube thumbnail, the
|
|
8860
8939
|
CWS tile + marquee, GitHub social preview) render from the poster
|
|
8861
8940
|
document of their aspect CLASS (landscape, square, portrait, tile), found
|
|
@@ -8868,7 +8947,7 @@ deliver renders and verifies; it composes nothing. The composition is
|
|
|
8868
8947
|
made with plan --style <poster>, which copies a poster's layout onto a
|
|
8869
8948
|
take (its card placement, its stage clips with the release's words
|
|
8870
8949
|
patched in from LAUNCH.md's headline and kicker roles or --headline and
|
|
8871
|
-
--kicker, its rest lean, its
|
|
8950
|
+
--kicker, its rest lean, its freeze), or by hand in doc.json.
|
|
8872
8951
|
The cut's MOTION is the document's too, in ONE vocabulary: every visual
|
|
8873
8952
|
thing (the card, a text, image or video clip, a prop) carries anim.enter,
|
|
8874
8953
|
anim.exit and anim.idle; the output lasts until the last clip ends, and
|
|
@@ -9256,7 +9335,7 @@ async function cmdPlan(argv) {
|
|
|
9256
9335
|
layout from ${s.styleFrom}: ${[
|
|
9257
9336
|
s.layout.clips.length ? `${s.layout.clips.length} stage clip(s)` : "",
|
|
9258
9337
|
s.layout.lean ? "the rest lean" : "",
|
|
9259
|
-
s.layout.
|
|
9338
|
+
s.layout.freeze ? "the freeze" : ""
|
|
9260
9339
|
].filter(Boolean).join(", ")}` + (s.layout.notes.length ? `
|
|
9261
9340
|
${s.layout.notes.join("\n ")}` : "") : "";
|
|
9262
9341
|
const motionLines = s.motion ? (s.motion.notes.length ? `
|
|
@@ -10085,4 +10164,4 @@ export {
|
|
|
10085
10164
|
convertAgentBrowser,
|
|
10086
10165
|
run
|
|
10087
10166
|
};
|
|
10088
|
-
//# sourceMappingURL=chunk-
|
|
10167
|
+
//# sourceMappingURL=chunk-CRZTGWF3.js.map
|