@vosjs/cli 0.67.6 → 0.69.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 +10 -13
- package/dist/{assetManifest-DU5ZEIDE.js → assetManifest-3QYCLT2H.js} +3 -3
- package/dist/{chunk-AUFY3M22.js → chunk-2KEQ3LKH.js} +2 -2
- package/dist/chunk-2KEQ3LKH.js.map +1 -0
- package/dist/{chunk-42ZU5XUW.js → chunk-5DUXN3RX.js} +1077 -2165
- package/dist/chunk-5DUXN3RX.js.map +1 -0
- package/dist/{chunk-MDRYSHOF.js → chunk-5GZ3GPAK.js} +2 -2
- package/dist/{chunk-C5VKACGQ.js → chunk-FL3E27WE.js} +13 -2
- package/dist/{chunk-C5VKACGQ.js.map → chunk-FL3E27WE.js.map} +1 -1
- package/dist/{chunk-OFTRK3Y3.js → chunk-Y5E672GT.js} +23 -4
- package/dist/chunk-Y5E672GT.js.map +1 -0
- package/dist/cli.js +7 -7
- package/dist/index.d.ts +17 -1
- package/dist/index.js +5 -5
- package/dist/manifest-QLQKVSML.js +8 -0
- package/dist/{run-4VSB2XHR.js → run-NDBUFOIG.js} +5 -5
- package/package.json +7 -7
- package/schema/channel-specs.json +5 -233
- package/schema/doc.schema.json +3 -3
- package/skills/VERSION +1 -1
- package/skills/launch-kit/SKILL.md +101 -223
- package/skills/launch-kit/references/channel-specs.md +14 -44
- package/skills/product-video/SKILL.md +9 -14
- package/skills/product-video/references/destinations.md +12 -23
- package/skills/vos-footage/SKILL.md +1 -1
- package/skills/vos-migrate/SKILL.md +3 -3
- package/dist/chunk-42ZU5XUW.js.map +0 -1
- package/dist/chunk-AUFY3M22.js.map +0 -1
- package/dist/chunk-OFTRK3Y3.js.map +0 -1
- package/dist/manifest-ZBK6IERM.js +0 -8
- /package/dist/{assetManifest-DU5ZEIDE.js.map → assetManifest-3QYCLT2H.js.map} +0 -0
- /package/dist/{chunk-MDRYSHOF.js.map → chunk-5GZ3GPAK.js.map} +0 -0
- /package/dist/{manifest-ZBK6IERM.js.map → manifest-QLQKVSML.js.map} +0 -0
- /package/dist/{run-4VSB2XHR.js.map → run-NDBUFOIG.js.map} +0 -0
package/schema/doc.schema.json
CHANGED
|
@@ -526,7 +526,7 @@
|
|
|
526
526
|
"fit": {
|
|
527
527
|
"type": "string",
|
|
528
528
|
"enum": ["contain", "cover"],
|
|
529
|
-
"description": "How footage meets an off-ratio frame. contain (default) letterboxes the card onto the background; cover makes the padded area the card and fills it with footage, cropped around `focus` \u2014 what a
|
|
529
|
+
"description": "How footage meets an off-ratio frame. contain (default) letterboxes the card onto the background; cover makes the padded area the card and fills it with footage, cropped around `focus` \u2014 what a 9:16 cut of 16:9 footage demands"
|
|
530
530
|
},
|
|
531
531
|
"camera": {
|
|
532
532
|
"type": "string",
|
|
@@ -696,7 +696,7 @@
|
|
|
696
696
|
"still": {
|
|
697
697
|
"type": "number",
|
|
698
698
|
"minimum": 0,
|
|
699
|
-
"description": "The frame that stands for this take, in OUTPUT seconds: the cover the shelf shows
|
|
699
|
+
"description": "The frame that stands for this take, in OUTPUT seconds: the cover the shelf shows (vos plan --still <t>, LAUNCH.md still:). Absent, the take's own last freeze (the rest a closing hold ends on; a template's freezes never count), else the hero moment after the card and the opening clips have entered."
|
|
700
700
|
}
|
|
701
701
|
}
|
|
702
702
|
},
|
|
@@ -1613,7 +1613,7 @@
|
|
|
1613
1613
|
},
|
|
1614
1614
|
"freeze": {
|
|
1615
1615
|
"type": "array",
|
|
1616
|
-
"description": "Freezes (SOURCE moments, footage-anchored): the footage frozen on the frame just before `at` for `seconds` of output, anywhere in the take (a pause on a state while a caption reads, a beat before a cut, the rest a poster ends on). The retime primitive beside `speed`: a speed span is a source range with a rate, a freeze a source point with a length. A freeze whose frame is trimmed away has no effect and comes back when the trim does. The still every still-taking surface takes (the thumbnail,
|
|
1616
|
+
"description": "Freezes (SOURCE moments, footage-anchored): the footage frozen on the frame just before `at` for `seconds` of output, anywhere in the take (a pause on a state while a caption reads, a beat before a cut, the rest a poster ends on). The retime primitive beside `speed`: a speed span is a source range with a rate, a freeze a source point with a length. A freeze whose frame is trimmed away has no effect and comes back when the trim does. The still every still-taking surface takes (the thumbnail, the cover) is where the LAST freeze begins. Absent = none. The output ending past the footage needs no freeze: the card holds its last frame under the clips that outlast it.",
|
|
1617
1617
|
"items": {
|
|
1618
1618
|
"type": "object",
|
|
1619
1619
|
"required": ["id", "at", "seconds"],
|
package/skills/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.23.0
|
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: launch-kit
|
|
3
|
-
description: Ship the
|
|
3
|
+
description: Ship the video with the release. One take of the real product becomes the launch demo video and its social cuts (the X feed cut, the Shorts and LinkedIn vertical, the GitHub README loop), each cut to its channel's spec in the brand's look with the motion as data in the document, verified, and pushed as a version labelled for the release so the next release is a re-render, not a re-shoot. Use when asked "we're launching / shipping vN", "make the launch video", "cut a changelog / what's-new clip", "PR to video", "refresh the demo for the new version", "make the social cuts for the launch", or to produce a launch week's batch of clips in one style.
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# Launch kit
|
|
7
|
+
# Launch kit: ship the video with the release
|
|
8
8
|
|
|
9
|
-
You are producing a RELEASE's
|
|
10
|
-
feature becomes every
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
You are producing a RELEASE's video, not one clip: one take of the shipped
|
|
10
|
+
feature becomes every cut the release needs, sized and verified per
|
|
11
|
+
channel, kept as an editable document so the NEXT release is a re-render,
|
|
12
|
+
not a re-shoot. Everything is data; the preview is the render; export is
|
|
13
|
+
free at every resolution up to 4K, no watermark; the engine is MIT.
|
|
14
14
|
|
|
15
|
-
The kit is RENDERED in one verb, `vos deliver`, from
|
|
16
|
-
the taste: every
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
nothing. Your judgment goes into three files (`BRAND.md`, `LAUNCH.md`,
|
|
22
|
-
`actions.json`), one pick (which poster on the shelf the cards follow) and
|
|
23
|
-
one decision (which moments are the story), never into hand-cropping.
|
|
15
|
+
The kit is RENDERED in one verb, `vos deliver`, from a document that
|
|
16
|
+
carries the taste: every cut plays the motion `vos plan` proposed into it
|
|
17
|
+
(an entrance, an end card, captions, a bed), and `vos validate` says what
|
|
18
|
+
is wrong in words. `deliver` composes nothing. Your judgment goes into
|
|
19
|
+
three files (`BRAND.md`, `LAUNCH.md`, `actions.json`) and the cut itself,
|
|
20
|
+
never into hand-editing a video file.
|
|
24
21
|
|
|
25
22
|
## Setup
|
|
26
23
|
|
|
@@ -28,29 +25,25 @@ one decision (which moments are the story), never into hand-cropping.
|
|
|
28
25
|
npm i -D @vosjs/cli # the vos CLI (take pipeline included)
|
|
29
26
|
```
|
|
30
27
|
|
|
31
|
-
`ffmpeg` on PATH
|
|
32
|
-
|
|
33
|
-
renders need system Chrome (`--format mp4`).
|
|
28
|
+
`ffmpeg` on PATH lets `vos validate --picture` read a cut's first and last
|
|
29
|
+
frame. MP4 renders need system Chrome (`--format mp4`).
|
|
34
30
|
|
|
35
31
|
## 1. Establish the release
|
|
36
32
|
|
|
37
33
|
Five facts before any recording:
|
|
38
34
|
|
|
39
|
-
- **What shipped
|
|
40
|
-
- **Which
|
|
41
|
-
`node_modules/@vosjs/cli/schema/channel-specs.json` (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
poster document; `references/channel-specs.md` is the same data as a
|
|
35
|
+
- **What shipped**: the feature, the version string, the URL where it runs.
|
|
36
|
+
- **Which cuts**: the per-channel spec table ships as data:
|
|
37
|
+
`node_modules/@vosjs/cli/schema/channel-specs.json` (the YouTube main
|
|
38
|
+
demo, the X feed cut, the Shorts and LinkedIn vertical cut, the GitHub
|
|
39
|
+
README loop; sizes, duration and byte ceilings, the word policy and the
|
|
40
|
+
safe rect per cut; `references/channel-specs.md` is the same data as a
|
|
46
41
|
table). **Loop over it, never hand-type dimensions.** Ask which channels
|
|
47
|
-
this release ships to; default to last release's set.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
kit (frontmatter carries the colour roles `bgA bgB bgC ink accent`, the
|
|
53
|
-
face roles `fontDisplay fontBody`, `logoUrl` (a bare mark, never a tiled
|
|
42
|
+
this release ships to; default to last release's set.
|
|
43
|
+
- **The brand**: resolve it BEFORE cutting, and never default to a
|
|
44
|
+
template's own palette. The project folder's `BRAND.md` is the brand kit
|
|
45
|
+
(frontmatter carries the colour roles `bgA bgB bgC ink accent`, the face
|
|
46
|
+
roles `fontDisplay fontBody`, `logoUrl` (a bare mark, never a tiled
|
|
54
47
|
icon), `wordmark`, and `look`, the presentation the site's own ground
|
|
55
48
|
asks for: `plate` for a paper site, `dark` for a dark one, else
|
|
56
49
|
`gradient`). Absent one, `vos brand <url>` witnesses it from the site's
|
|
@@ -59,66 +52,51 @@ Five facts before any recording:
|
|
|
59
52
|
`vos recipe push BRAND.md --folder <slug>`. Place it BESIDE the take (or
|
|
60
53
|
in the take's parent folder): `plan` and `deliver` read it there with no
|
|
61
54
|
flag.
|
|
62
|
-
- **The words
|
|
55
|
+
- **The words**: `LAUNCH.md` beside the take carries the release's roles
|
|
63
56
|
in its frontmatter, read with no flag:
|
|
64
57
|
|
|
65
58
|
```yaml
|
|
66
|
-
headline: "Two to six words\nover up to three lines" # the
|
|
59
|
+
headline: "Two to six words\nover up to three lines" # the end card
|
|
67
60
|
kicker: "PRODUCT V2.1" # absent = the wordmark plus --release
|
|
68
61
|
music: upbeat # a catalog slug or mood; none = silent
|
|
69
62
|
entrance: tilt-in # tilt-in | pull-out | rise | none
|
|
70
63
|
endCard: on # the official End card template; none switches it off; a title, vos id or doc.json names another
|
|
71
|
-
with: "
|
|
64
|
+
with: "<template>@start" # optional: any template laid at an anchor (@end | @start | @step:<id> | @<seconds>)
|
|
72
65
|
captions: on # none switches the beat captions off
|
|
73
|
-
poster: poster/landscape # optional: the document every card renders from
|
|
74
|
-
poster-tile: poster/tile # optional: one class named on its own
|
|
75
66
|
```
|
|
76
67
|
|
|
77
68
|
A headline is the ONE line the release says; write it over its lines with
|
|
78
|
-
`\n`. `vos plan` reads
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`vos folder pull poster-families` lists them with their vos ids. There is
|
|
87
|
-
no layout name and no `--layout` flag: the exemplar IS the layout, copied
|
|
88
|
-
by data.
|
|
89
|
-
|
|
90
|
-
The destinations decide the VIEWPORT, before anything records: footage
|
|
91
|
-
resolution = viewport, and a 1280×720 take cannot honestly fill a 1920×1080
|
|
92
|
-
video spec. Record at 1920×1080 for a 1080p kit, 2560×1440 when a
|
|
93
|
-
destination is larger.
|
|
69
|
+
`\n`. `vos plan` reads these roles when it proposes the cut's motion.
|
|
70
|
+
- **The length**: each cut has a duration band in the specs. A story
|
|
71
|
+
shorter than a cut's floor is that cut skipped with its reason, never
|
|
72
|
+
padded.
|
|
73
|
+
|
|
74
|
+
The cuts decide the VIEWPORT, before anything records: footage resolution
|
|
75
|
+
= viewport, and a 1280×720 take cannot honestly fill a 1920×1080 cut.
|
|
76
|
+
Record at 1920×1080 for a 1080p kit, 2560×1440 when a cut is larger.
|
|
94
77
|
|
|
95
78
|
If the work lands in a vos.so project (folder), pull it first and read every
|
|
96
|
-
`.md` recipe in it
|
|
97
|
-
cut
|
|
98
|
-
defaults.
|
|
79
|
+
`.md` recipe in it: `LAUNCH.md` binds this loop the way `CUT.md` binds a
|
|
80
|
+
cut. Recipes override this skill's defaults.
|
|
99
81
|
|
|
100
82
|
## 2. Source: one take of the real thing
|
|
101
83
|
|
|
102
|
-
The kit is made FROM the product, never from a mockup
|
|
103
|
-
misleading listing images are a removal-grade violation).
|
|
84
|
+
The kit is made FROM the product, never from a mockup.
|
|
104
85
|
|
|
105
|
-
**Stage the content like a set before recording.** Half of what separates
|
|
106
|
-
premium launch
|
|
107
|
-
actions.json must leave the product in the state a proud
|
|
108
|
-
|
|
109
|
-
poster or store still is cut. `deliver` drops a blank moment (a wallpaper,
|
|
110
|
-
an empty canvas) and says so, but it cannot stage the set for you.
|
|
86
|
+
**Stage the content like a set before recording.** Half of what separates
|
|
87
|
+
a premium launch video from a screen grab is what is ON the screen. The
|
|
88
|
+
actions.json must leave the product in the state a proud demo would show:
|
|
89
|
+
labels typed, real-looking data, the feature mid-story.
|
|
111
90
|
|
|
112
|
-
**Write the story into `actions.json`.** Give steps an `id` (the
|
|
113
|
-
and the
|
|
114
|
-
deserves one (two to eight words; `plan` proposes it as a lower-third
|
|
115
|
-
that step's moment on the cuts that take words). After a click that
|
|
116
|
-
navigates, put a `wait` for the load
|
|
117
|
-
wait, so the frame shows the page, never the spinner.
|
|
91
|
+
**Write the story into `actions.json`.** Give steps an `id` (the re-render
|
|
92
|
+
loop and the template anchors address them by it) and a `caption` where a
|
|
93
|
+
beat deserves one (two to eight words; `plan` proposes it as a lower-third
|
|
94
|
+
at that step's moment on the cuts that take words). After a click that
|
|
95
|
+
navigates, put a `wait` for the load, so the cut never dwells on a spinner.
|
|
118
96
|
|
|
119
97
|
- **Fresh recording**: the `product-video` skill's loop (explore →
|
|
120
98
|
`actions.json` → `vos record --strict` → tune `doc.json`). Keep
|
|
121
|
-
`actions.json` in the repo
|
|
99
|
+
`actions.json` in the repo: it is the next release's script.
|
|
122
100
|
- **The shipped feature is behind a login**: settle the session before
|
|
123
101
|
the script, by the `product-video` skill's ladder
|
|
124
102
|
(in full at https://vos.so/llms-full.txt, "Sessions"): mint one from the test auth the repo
|
|
@@ -129,7 +107,7 @@ wait, so the frame shows the page, never the spinner.
|
|
|
129
107
|
the rung that needs no human: it is the one that still works next
|
|
130
108
|
release. Never type or accept a production password; keep the state file
|
|
131
109
|
out of the take and out of git; record from a demo account, because a
|
|
132
|
-
|
|
110
|
+
launch video showing a real customer's data is a removal-grade mistake.
|
|
133
111
|
- **Existing take**: cut it with the `vos-cut` skill. A hosted take comes
|
|
134
112
|
home with `vos fetch <vosId|watch-url> --out dir --media`.
|
|
135
113
|
- **New version of a shot product**: re-record with `vos record` into the
|
|
@@ -141,7 +119,7 @@ wait, so the frame shows the page, never the spinner.
|
|
|
141
119
|
A motion-graphic segment rendered elsewhere is an INPUT: it drops in as a
|
|
142
120
|
media overlay clip or a backdrop in the document, never the other way round.
|
|
143
121
|
|
|
144
|
-
## 3. The
|
|
122
|
+
## 3. The motion, as data
|
|
145
123
|
|
|
146
124
|
**The cut moves by data.** A fresh `vos plan` proposes the cut's motion into
|
|
147
125
|
`doc.json` from `LAUNCH.md`'s roles: the card's entrance, the END CARD (the
|
|
@@ -154,151 +132,67 @@ when the take has no mic; every proposal carries a stable id (`bed`,
|
|
|
154
132
|
`click-<n>`, `caption-<step>`). On an existing cut `--motion` re-proposes;
|
|
155
133
|
a refresh never does, so a deleted end card stays deleted. A template is a
|
|
156
134
|
plain take on a shelf whose clips carry stable ids; a ref is a title on the
|
|
157
|
-
official shelf (`"End card"
|
|
158
|
-
|
|
159
|
-
kit renders.
|
|
135
|
+
official shelf (`"End card"`), a vos id, or a document on disk. Open the
|
|
136
|
+
take in the studio and what you see is what the kit renders.
|
|
160
137
|
|
|
161
138
|
```bash
|
|
162
139
|
vos plan take --motion --release v2.1
|
|
140
|
+
vos frames take --at-zooms; vos validate take
|
|
163
141
|
```
|
|
164
142
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
pose, the words and the mark as overlay clips with stable ids
|
|
168
|
-
(`stage-title`, `stage-kicker`, `stage-brand`, `stage-mark`), and a
|
|
169
|
-
trailing `hold` on the last segment whose START is the still. Make one per
|
|
170
|
-
aspect class the release needs (landscape, square, portrait, tile), each
|
|
171
|
-
from the take's own footage:
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
cp -r take poster/landscape # or vos duplicate <take vosId>, then fetch --media
|
|
175
|
-
vos plan poster/landscape --style <poster vosId|doc.json> --headline "…" --kicker "…"
|
|
176
|
-
vos frames poster/landscape --frame <rest>; vos validate poster/landscape
|
|
177
|
-
vos push poster/landscape --folder <project-slug> --label "poster, landscape"
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
`plan --style <poster>` copies the LAYOUT (the card's placement and
|
|
181
|
-
presentation, the stage clips with the release's words patched in from
|
|
182
|
-
`LAUNCH.md` or the flags, the rest lean, the hold) onto the take and keeps
|
|
183
|
-
the take's own aspect, chrome and cut; the brand's mark from `BRAND.md`
|
|
184
|
-
`logoUrl` is fetched into `brand/` for `stage-mark`, and what could not
|
|
185
|
-
follow is said. Narrow the segments to the moment (a zoom apex, the settled
|
|
186
|
-
response after a click) so the rest is the feature, never the cold open;
|
|
187
|
-
the product may keep PLAYING inside the card until the hold. Then look at
|
|
188
|
-
the rest frame: a poster is judged by eye before it is pushed. A human
|
|
189
|
-
opens it in the studio and drags the card, retypes the words in place,
|
|
190
|
-
moves the hold; `vos pull --media` brings that back down, and the next
|
|
191
|
-
release re-words it with the same `plan --style` from its own pushed
|
|
192
|
-
document.
|
|
143
|
+
Look at the frames before delivering: the opening beat, the zoom apexes
|
|
144
|
+
and the end card are judged by eye.
|
|
193
145
|
|
|
194
146
|
## 4. Deliver
|
|
195
147
|
|
|
196
148
|
```bash
|
|
197
|
-
vos deliver take --to
|
|
149
|
+
vos deliver take --to youtube,x,shorts,github --release v2.1
|
|
198
150
|
```
|
|
199
151
|
|
|
200
|
-
One pass, and the verb
|
|
201
|
-
|
|
202
|
-
- **The moments.** Still times come from the STORY: every step's end plus a
|
|
203
|
-
settle (the end of the wait that follows a click), then the zoom apexes,
|
|
204
|
-
then a spread. Each candidate is read once as the real page; blanks are
|
|
205
|
-
dropped, two of one frame collapse to one, every drop said in
|
|
206
|
-
`skipped[]`. `--times step:<id>[+offset]` names one.
|
|
207
|
-
- **Screenshots** are the real page, full bleed: the store still and the
|
|
208
|
-
gallery drop the cut's zoom, tilt and chrome by default (`--composed`
|
|
209
|
-
keeps them, and the picture pass refuses it for the store).
|
|
210
|
-
- **The cards render from the posters.** Each card destination (the OG
|
|
211
|
-
card, the LinkedIn and X images, the YouTube thumbnail, the CWS tile and
|
|
212
|
-
marquee, the GitHub social preview, the PH thumbnail) renders from the
|
|
213
|
-
poster document of its aspect class beside the take
|
|
214
|
-
(`poster/<class>/doc.json`, or the document `LAUNCH.md`'s `poster` roles
|
|
215
|
-
name) at that document's rest, at the destination's exact pixels. A
|
|
216
|
-
class with no document is the take's own frame, said once in
|
|
217
|
-
`skipped[]`. Nothing is composed in memory.
|
|
218
|
-
- **The cuts play the document.** `deliver` keeps only each destination's
|
|
219
|
-
MECHANICS: a loop drops the entrance, the end card, the captions and the
|
|
220
|
-
sound; a silent channel mutes the bed; the 9:16 cut is a reframe whose
|
|
221
|
-
crop follows the camera, not a letterbox; a loop destination the take
|
|
222
|
-
outruns takes the take's first seconds up to its cap; a byte ceiling
|
|
223
|
-
becomes a bitrate budget.
|
|
224
|
-
- **The manifest.** `kit.json` beside the assets records every asset with
|
|
225
|
-
its destination, the moment it came from, and for every card the poster
|
|
226
|
-
it is a frame of (`source: "poster"`, the class, the file, the vos it
|
|
227
|
-
tracks, the shot rect and the text boxes read FROM the document), and
|
|
228
|
-
`skipped[]` with every reason.
|
|
229
|
-
|
|
230
|
-
## 5. Verify: the specs, then the picture
|
|
152
|
+
One pass, and the verb keeps only each cut's MECHANICS:
|
|
231
153
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
154
|
+
- **The main demo and the feed cut play the document** as planned, with
|
|
155
|
+
its entrance, end card, captions and bed.
|
|
156
|
+
- **The vertical cut** is a 9:16 reframe whose crop follows the camera, not
|
|
157
|
+
a letterbox, with the words inside the channel's safe rect.
|
|
158
|
+
- **The README loop** drops the entrance, the end card, the captions and
|
|
159
|
+
the sound; a take that outruns its cap gives its first seconds up to the
|
|
160
|
+
cap, and the byte ceiling becomes a bitrate budget.
|
|
161
|
+
- **A silent channel** mutes the bed.
|
|
162
|
+
- **The manifest.** `kit.json` beside the cuts records every asset with its
|
|
163
|
+
destination, and `skipped[]` with every reason (a cut whose floor the
|
|
164
|
+
story is under, a channel the take cannot serve).
|
|
235
165
|
|
|
236
|
-
|
|
237
|
-
count, a WebP under a `.png` name). The picture pass says what each asset
|
|
238
|
-
LOOKS like, every finding with a code, a severity, a fix hint and a box:
|
|
239
|
-
|
|
240
|
-
| code | what fires |
|
|
241
|
-
| --- | --- |
|
|
242
|
-
| `blank` | a card whose subject is under the ink floor: a wallpaper, an empty canvas |
|
|
243
|
-
| `duplicate` | cards of one frame (two is a note; three or more fails) |
|
|
244
|
-
| `subject` | a card off the 60 to 92% band, or a crop where a card was asked for |
|
|
245
|
-
| `separation` | a light card on a light ground with no shadow and no drawn edge |
|
|
246
|
-
| `halfsize` | a tile that loses its edges when the store shrinks it |
|
|
247
|
-
| `sliced` | a headline crossing the frame edge |
|
|
248
|
-
| `safe` | words outside the destination's safe rect, or words where none are wanted |
|
|
249
|
-
| `contrast` | a text box under APCA Lc 60 (headline) or 75 (body) |
|
|
250
|
-
| `firstlast` | a cut that opens or ends on nothing, or bled on all four sides |
|
|
251
|
-
|
|
252
|
-
A problem is redone by fixing the INPUT (a moment, a word, the set, the
|
|
253
|
-
poster document, a recipe line), never by hand-editing a PNG. Self-check by
|
|
254
|
-
these names before you render: a cold-open hero is `blank`, eight crops of
|
|
255
|
-
one frame is `duplicate`, white words on a paper ground is `contrast`. A
|
|
256
|
-
poster's card is judged by the shot rect the document carries, so a card
|
|
257
|
-
you dragged off the band is `subject` before anyone posts it.
|
|
258
|
-
|
|
259
|
-
## 6. Judge beside the references
|
|
166
|
+
## 5. Verify
|
|
260
167
|
|
|
261
168
|
```bash
|
|
262
|
-
vos
|
|
169
|
+
vos validate kit/kit.json --picture
|
|
263
170
|
```
|
|
264
171
|
|
|
265
|
-
The
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
`judge.json` with a slot per pair. Judge every pair BOTH ways, with the
|
|
270
|
-
rubric's numbered rules and the three positive tests (would you post it as
|
|
271
|
-
a still; does it read at half size; name three ways it acknowledges THIS
|
|
272
|
-
product), and write `win` true, false or null (a tie) with the rule
|
|
273
|
-
numbers. Parity with the references is 50%; a kit under 40% is not ready
|
|
274
|
-
to market, said in the handoff, never shipped around.
|
|
172
|
+
The spec pass re-measures every cut from its bytes (px, bytes, duration,
|
|
173
|
+
container and codec). The picture pass reads each cut's first and last
|
|
174
|
+
frame and fires `firstlast` on a cut that opens or ends on nothing, or one
|
|
175
|
+
bled on all four sides; every finding carries a fix hint.
|
|
275
176
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
the human asks.
|
|
177
|
+
A problem is redone by fixing the INPUT (a step, a word, the set, the cut
|
|
178
|
+
in `doc.json`, a recipe line), never by hand-editing a rendered file. Do
|
|
179
|
+
not re-run `validate` after a push unless the human asks.
|
|
280
180
|
|
|
281
|
-
##
|
|
181
|
+
## 6. Push the release
|
|
282
182
|
|
|
283
|
-
Push the
|
|
284
|
-
kit's stills into the release's project so the human can retrospect without
|
|
285
|
-
a terminal:
|
|
183
|
+
Push the take labelled for the release:
|
|
286
184
|
|
|
287
185
|
```
|
|
288
186
|
vos push take --folder <project-slug> --label "v2.1 launch" --note "<what shipped, one line>" \
|
|
289
187
|
--prompt "<the person's prompt, as they wrote it>"
|
|
290
|
-
vos push poster/landscape --folder <project-slug> --label "v2.1 poster, landscape"
|
|
291
|
-
vos asset push kit/*.png --folder <project-slug>
|
|
292
188
|
```
|
|
293
189
|
|
|
294
190
|
`--prompt` shows the person's prompt on the watch page by default: their words as they wrote them, never yours, with no file path, key or email they did not mean to publish. Say it is shown, and that they can take it off from the watch page.
|
|
295
191
|
|
|
296
192
|
End by handing the human the loop, not the files: the watch page plays the
|
|
297
|
-
latest version, the studio edits the cut
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
and re-word the posters with `plan --style` from their own pushed
|
|
301
|
-
documents.
|
|
193
|
+
latest version, the studio edits the cut (every zoom, caption and the end
|
|
194
|
+
card is a layer or a span they can drag), and `vos pull --media` brings
|
|
195
|
+
their edits back down. Next release, start at step 2's last bullet.
|
|
302
196
|
|
|
303
197
|
**Preserve the human's changes.** They edit the take in the studio outside
|
|
304
198
|
this conversation. If `vos pull --check` or the differ's `protected` set
|
|
@@ -315,44 +209,28 @@ by data. Never spread before the seed is signed off.
|
|
|
315
209
|
## Notes
|
|
316
210
|
|
|
317
211
|
- `deliver` is the procedure; this skill is the judgment around it (the
|
|
318
|
-
set, the words, the
|
|
319
|
-
|
|
320
|
-
|
|
212
|
+
set, the words, the story, the verdicts). If you find yourself editing a
|
|
213
|
+
rendered file by hand, the fix is the document, a recipe line or a
|
|
214
|
+
check, and you should say so in the handoff.
|
|
321
215
|
- Platform specs drift. The JSON carries a `verified` date; if it is more
|
|
322
216
|
than a quarter old, spot-check the channel docs before shipping.
|
|
323
|
-
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
cover, landscape"` carries a layout; a poster's still is where its
|
|
327
|
-
trailing freeze begins); a maker's own family is a project of their own
|
|
328
|
-
posters beside a `POSTER.md`. Applying one is `plan --style <vosId>`.
|
|
217
|
+
- Stills of the product (a cover, a frame for a post) are not this skill:
|
|
218
|
+
`vos push --still` sets the vos's cover, and `vos frames --frame <t>`
|
|
219
|
+
reads any frame of the take.
|
|
329
220
|
|
|
330
221
|
## Avoid (the traps that shipped)
|
|
331
222
|
|
|
332
|
-
- A 720p recording against a 1080p spec: the
|
|
333
|
-
|
|
334
|
-
- A
|
|
335
|
-
the site) before
|
|
336
|
-
- A cold
|
|
337
|
-
headline with the product nowhere;
|
|
338
|
-
|
|
339
|
-
-
|
|
340
|
-
|
|
341
|
-
-
|
|
342
|
-
|
|
343
|
-
poster document renders the take's own frame and says so.
|
|
344
|
-
- Eight crops of one frame (`duplicate`): a script with one moment. Give the
|
|
345
|
-
story steps, and waits after the clicks that navigate.
|
|
346
|
-
- A store screenshot under the frame chrome or the camera zoom: the store
|
|
347
|
-
still is the real page, full bleed (deliver's default, and `--composed`
|
|
348
|
-
is refused by the picture pass).
|
|
349
|
-
- The loading plane as the hero: a click that navigates settles when the
|
|
350
|
-
wait after it ends; a click with no wait after it is read 0.4 s later,
|
|
351
|
-
mid-load.
|
|
352
|
-
- White words on a paper ground (`contrast`): the end card takes the brand's
|
|
353
|
-
ink; a kicker softened too far reads under the floor.
|
|
354
|
-
- A card that is WebP under a `.png` name: `vos still` writes WebP; convert,
|
|
355
|
-
then `vos validate` reads the bytes and says so.
|
|
223
|
+
- A 720p recording against a 1080p spec: the cuts pick the viewport before
|
|
224
|
+
anything records. Cost a full re-record once.
|
|
225
|
+
- A template's own palette on a deliverable: resolve `BRAND.md` (or witness
|
|
226
|
+
the site) before cutting, and put it beside the take.
|
|
227
|
+
- A cold open (`firstlast`): the first frame is the marketing page's
|
|
228
|
+
headline with the product nowhere; trim to the story or let the entrance
|
|
229
|
+
carry it.
|
|
230
|
+
- The loading plane on screen: a click that navigates needs the `wait`
|
|
231
|
+
after it.
|
|
232
|
+
- White words on a paper ground: the end card takes the brand's ink; a
|
|
233
|
+
kicker softened too far reads under the floor.
|
|
356
234
|
- Padding a spec floor: a 36 s story is a skipped 60 s demo, with its reason.
|
|
357
235
|
- A hand-typed dimension: every size comes from `channel-specs.json`.
|
|
358
236
|
- The save beat on a demo instance that disables writes: say so in
|
|
@@ -1,56 +1,26 @@
|
|
|
1
|
-
# Channel specs
|
|
1
|
+
# Channel specs: readable mirror
|
|
2
2
|
|
|
3
3
|
Source of truth: `schema/channel-specs.json` in the `@vosjs/cli` npm
|
|
4
4
|
package (loop over the JSON, don't hand-type from this table). Verified
|
|
5
|
-
against official platform docs 2026-08-04
|
|
5
|
+
against official platform docs 2026-08-04. Platform specs drift, so
|
|
6
6
|
re-verify quarterly against the channels' current docs.
|
|
7
7
|
|
|
8
8
|
## Video (4 cuts from one document)
|
|
9
9
|
|
|
10
|
-
| Cut | Spec | Destinations |
|
|
11
|
-
| --- | --- | --- |
|
|
12
|
-
| Main demo | 16:9 1920×1080 MP4 H.264+AAC, 60–120s, captions burned in | YouTube (public)
|
|
13
|
-
| Feed cut | 16:9 or 1:1, 30–60s, ≤140s / 512MB free tier, **H.264+AAC only** (HEVC/VP9/AV1 rejected) | X native upload |
|
|
14
|
-
| Vertical cut | 9:16 1080×1920, 30–90s, critical text inside a centered ~900×1160 safe zone | YouTube Shorts + LinkedIn native vertical |
|
|
15
|
-
| README loop | 16:9, 10–20s, **≤10MB** MP4 (GitHub free-plan ceiling) | GitHub README |
|
|
16
|
-
|
|
17
|
-
## Images
|
|
18
|
-
|
|
19
|
-
| Asset | Exact spec |
|
|
20
|
-
| --- | --- |
|
|
21
|
-
| YouTube thumbnail | 1280×720, <2MB |
|
|
22
|
-
| CWS screenshots | 1–5 × **1280×800** (real UX only — misleading images are a removal-grade violation), full bleed, square corners |
|
|
23
|
-
| CWS small promo tile | 440×280 (listings without one rank lower), no text, fill the region |
|
|
24
|
-
| CWS marquee | 1400×560 (carousel eligibility) |
|
|
25
|
-
| CWS icon | 128×128 PNG, 96×96 art + 16px transparent padding |
|
|
26
|
-
| Product Hunt thumbnail | 240×240, GIF animates on hover only, first frame must stand alone, <3MB |
|
|
27
|
-
| Product Hunt gallery | 4–8 × 1270×760, first image is the hero, GIF allowed |
|
|
28
|
-
| X in-feed image | 1200×675 |
|
|
29
|
-
| LinkedIn feed image | 1200×627 (or 1080×1350 vertical) |
|
|
30
|
-
| OG card | 1200×630, <1MB, text in the center ~1080×600, explicit `twitter:card=summary_large_image` (og:image alone gets the small card) |
|
|
31
|
-
| GitHub social preview | 1280×640, <1MB, key text ≥50px from every edge |
|
|
10
|
+
| Cut | `--to` | Spec | Destinations |
|
|
11
|
+
| --- | --- | --- | --- |
|
|
12
|
+
| Main demo | `youtube` | 16:9 1920×1080 MP4 H.264+AAC, 60–120s, captions burned in | YouTube (public). The same upload serves the Chrome Web Store promo video and the Product Hunt video (both take YouTube URLs only) |
|
|
13
|
+
| Feed cut | `x` | 16:9 or 1:1, 30–60s, ≤140s / 512MB free tier, **H.264+AAC only** (HEVC/VP9/AV1 rejected) | X native upload |
|
|
14
|
+
| Vertical cut | `shorts` | 9:16 1080×1920, 30–90s, critical text inside a centered ~900×1160 safe zone | YouTube Shorts + LinkedIn native vertical |
|
|
15
|
+
| README loop | `github` | 16:9, 10–20s, **≤10MB** MP4 (GitHub free-plan ceiling) | GitHub README |
|
|
32
16
|
|
|
33
|
-
## Composition (per
|
|
17
|
+
## Composition (per cut)
|
|
34
18
|
|
|
35
|
-
The specs carry
|
|
36
|
-
read (loop over the JSON; this is the readable mirror)
|
|
37
|
-
the poster document of its aspect class beside the take
|
|
38
|
-
(`poster/<class>/doc.json`, or the document `LAUNCH.md`'s `poster` roles
|
|
39
|
-
name); the class is read from the destination's pixels (wider than 1.15:1 is
|
|
40
|
-
landscape, 0.87 to 1.15 square, narrower portrait, under 700 px on the long
|
|
41
|
-
side a tile):
|
|
19
|
+
The specs carry two more facts `vos deliver` and `vos validate --picture`
|
|
20
|
+
read (loop over the JSON; this is the readable mirror):
|
|
42
21
|
|
|
43
|
-
|
|
|
22
|
+
| Cut | Words | Safe rect (fractions) | Renders from |
|
|
44
23
|
| --- | --- | --- | --- |
|
|
45
|
-
|
|
|
46
|
-
|
|
|
47
|
-
| cws marquee | allowed | 5% / 8% inset | the landscape poster |
|
|
48
|
-
| og card | expected | 1080x600 centred | the landscape poster |
|
|
49
|
-
| linkedin feed-image | expected | 5% / 8% inset | the landscape poster |
|
|
50
|
-
| x feed-image | allowed | 5% / 8% inset | the landscape poster |
|
|
51
|
-
| youtube thumbnail | expected | 5% / 8% inset | the landscape poster |
|
|
52
|
-
| github social-preview | expected | 50 px from every edge | the landscape poster |
|
|
53
|
-
| producthunt thumbnail | none | 6% inset | the tile poster |
|
|
54
|
-
| shorts / vertical cut | expected | 900x1160 centred | the take, reframed |
|
|
55
|
-
| x feed-cut, youtube main-demo | allowed | 5% / 8% inset | the take, with its planned entrance and end card |
|
|
24
|
+
| youtube main-demo, x feed-cut | allowed | 5% / 8% inset | the take, with its planned entrance and end card |
|
|
25
|
+
| shorts-linkedin vertical-cut | expected | 900x1160 centred | the take, reframed |
|
|
56
26
|
| github readme-loop | none | | the take, motion and sound dropped |
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: product-video
|
|
3
|
-
description: Record and produce the demo video of a website, app, or feature with the vos CLI — the agent scripts the click path (actions.json), the recording auto-plans zooms, and every editing decision is data in doc.json, so fixes are edits and re-renders, never re-recordings. Renders are deterministic; export is free up to 4K with no watermark. Use when asked to make a product video, demo video, screen recording of a URL or feature, or a marketing clip, including a product behind a login (the session ladder: mint one from the project's own test auth before asking anyone), or when a feature was verified in agent-browser and that walk should become a take. A whole release's
|
|
3
|
+
description: Record and produce the demo video of a website, app, or feature with the vos CLI — the agent scripts the click path (actions.json), the recording auto-plans zooms, and every editing decision is data in doc.json, so fixes are edits and re-renders, never re-recordings. Renders are deterministic; export is free up to 4K with no watermark. Use when asked to make a product video, demo video, screen recording of a URL or feature, or a marketing clip, including a product behind a login (the session ladder: mint one from the project's own test auth before asking anyone), or when a feature was verified in agent-browser and that walk should become a take. A whole release's video set (the launch demo and its social cuts) is the launch-kit skill, which records through this one.
|
|
4
4
|
license: MIT
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Product video (and the assets around it), end to end
|
|
8
8
|
|
|
9
|
-
You are producing a shippable product
|
|
10
|
-
|
|
9
|
+
You are producing a shippable product video from a live web page, with
|
|
10
|
+
the `vos` CLI.
|
|
11
11
|
Everything is data: you write a flow script, the CLI records and plans, you
|
|
12
12
|
tune JSON, you re-render. **Never re-record to fix pacing or zooms — edit
|
|
13
13
|
`doc.json` and render again.** Quality bar: `references/taste.md` — follow
|
|
@@ -49,7 +49,6 @@ failure / 3 no browser / 4 the recorder met a sign-in instead of the page
|
|
|
49
49
|
|---|---|---|---|
|
|
50
50
|
| **Landing-page clip** (hero/section embed) | 2560×1440 (footage-native 2K) | webm → VP9 re-encode + poster | silent loop; see `references/destinations.md` |
|
|
51
51
|
| **Launch video** (PH, social, store promo) | 2560×1440 or 1280×720 | mp4 (`--format mp4`, needs system Chrome) | music bed via `doc.audio` |
|
|
52
|
-
| **Launch-kit stills** (store screenshots, tiles, OG) | sized to the asset | `frames --frame <t> --size WxH` PNGs from the same take | one take → every asset |
|
|
53
52
|
| **Quick demo** (issue, PR, chat) | 1280×720 | webm, defaults | speed over polish; drafts acceptable here ONLY |
|
|
54
53
|
|
|
55
54
|
Per-channel dimensions and byte budgets: `references/destinations.md`.
|
|
@@ -204,14 +203,14 @@ Per-channel dimensions and byte budgets: `references/destinations.md`.
|
|
|
204
203
|
|
|
205
204
|
7. **Package for the destination**: `references/destinations.md`.
|
|
206
205
|
|
|
207
|
-
## Launch kit (one take → every
|
|
206
|
+
## Launch kit (one take → every cut of a release)
|
|
208
207
|
|
|
209
208
|
The `launch-kit` skill owns this destination: it establishes the release,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
209
|
+
plans the cut's motion, delivers every video channel against
|
|
210
|
+
`channel-specs.json` (the main demo, the X feed cut, the vertical cut, the
|
|
211
|
+
README loop), verifies each cut, writes the `kit.json` manifest and pushes
|
|
212
|
+
labelled for the release. The recording it cuts is this skill's. Follow it
|
|
213
|
+
when the ask is a release, not one video.
|
|
215
214
|
|
|
216
215
|
## Gotchas
|
|
217
216
|
|
|
@@ -254,8 +253,6 @@ video. Follow it when the ask is a release, not one video.
|
|
|
254
253
|
- A first frame or a last frame that cannot stand alone as a poster.
|
|
255
254
|
- A frozen opening: a static landing page records as freeze-then-bang;
|
|
256
255
|
trim it or speed it, the story opens near the money shot.
|
|
257
|
-
- A store screenshot cut from the composed frame: real UX is the page, full
|
|
258
|
-
bleed (`deliver` does this; a text-heavy page also wants a store-size take).
|
|
259
256
|
- A sign-in in `steps`: every step there is in the footage and a typed
|
|
260
257
|
value is logged. It goes in `setup`, with the password from the shell
|
|
261
258
|
(`references/sessions.md`).
|
|
@@ -264,5 +261,3 @@ video. Follow it when the ask is a release, not one video.
|
|
|
264
261
|
`EXPOSED` list, and `mask` what is left.
|
|
265
262
|
- A `mask` with `as: "text"` over product copy or a number: that is no
|
|
266
263
|
longer a recording of the product.
|
|
267
|
-
- A `.png` name on `vos still`: it writes WebP; convert, and `vos validate
|
|
268
|
-
<kit.json>` reads the bytes.
|