Launch kit — ship the media with the release
You are producing a RELEASE's media, not a video: one take of the shipped feature becomes every asset the release needs, composed, sized and verified per destination, kept as editable documents so the NEXT release is a re-render, not a re-shoot. Everything is data; the preview is the render; export is free at every resolution up to 4K, no watermark; the engine is MIT.
The kit is RENDERED in one verb, vos deliver, from documents that carry
the taste: every card is a frame of a POSTER document (a plain take whose
card sits where the poster wants it, with the words and the mark as clips),
every cut plays the motion vos plan proposed into its document (an
entrance, an end card, captions, a bed), the still moments come from the
story, and two verifiers say what is wrong in words. deliver composes
nothing. Your judgment goes into three files (BRAND.md, LAUNCH.md,
actions.json), one pick (which poster on the shelf the cards follow) and
one decision (which moments are the story), never into hand-cropping.
Setup
npm i -D @vosjs/cli # the vos CLI (take pipeline included)
ffmpeg on PATH covers what the CLI does not emit (the PH hover-GIF) and
lets vos validate --picture read a video's first and last frame. MP4
renders need system Chrome (--format mp4).
1. Establish the release
Five facts before any recording:
-
What shipped — the feature, the version string, the URL where it runs.
-
Which destinations — the per-channel spec table ships as data:
node_modules/@vosjs/cli/schema/channel-specs.json(CWS, Product Hunt, X, LinkedIn, GitHub, OG, YouTube; sizes, counts, byte and duration ceilings, the word policy and the safe rect per destination, and each image's GENRE:screenshotis the real page,cardis a frame of a poster document;references/channel-specs.mdis the same data as a table). Loop over it, never hand-type dimensions. Ask which channels this release ships to; default to last release's set. The JSON carries averifieddate; if it is more than a quarter old, spot-check the channel docs before shipping. -
The brand — resolve it BEFORE authoring any asset, and never default to a layout's own palette. The project folder's
BRAND.mdis the brand kit (frontmatter carries the colour rolesbgA bgB bgC ink accent, the face rolesfontDisplay fontBody,logoUrl(a bare mark, never a tiled icon),wordmark, andlook, the presentation the site's own ground asks for:platefor a paper site,darkfor a dark one, elsegradient). Absent one,vos brand <url>witnesses it from the site's/design.md,/llms.txtand the page itself, and writes every role with its provenance; read it, correct what a page cannot say, and file it withvos recipe push BRAND.md --folder <slug>. Place it BESIDE the take (or in the take's parent folder):plananddeliverread it there with no flag. -
The words —
LAUNCH.mdbeside the take carries the release's roles in its frontmatter, read with no flag:headline: "Two to six words\nover up to three lines" # the posters and the end card kicker: "PRODUCT V2.1" # absent = the wordmark plus --release music: upbeat # a catalog slug or mood; none = silent entrance: tilt-in # tilt-in | pull-out | rise | none endCard: on # the official End card template; none switches it off; a title, vos id or doc.json names another with: "Split cover, landscape@end" # optional: any template laid at an anchor (@end | @start | @step:<id> | @<seconds>) captions: on # none switches the beat captions off poster: poster/landscape # optional: the document every card renders from poster-tile: poster/tile # optional: one class named on its ownA headline is the ONE line the release says; write it over its lines with
\n.vos planreads the motion roles when it proposes the cut's motion andplan --styletypes the words into a poster;deliverreads only theposterroles, and with none it looks forposter/<class>/doc.jsonbeside the take. -
The layout — a poster the cards will follow, on a shelf. The official
Poster familiesproject on vos.so holds one exemplar per aspect class (landscape, square, portrait, tile) beside itsPOSTER.md, which says when each class is the one; a maker's own project is the same shape.vos folder pull poster-familieslists them with their vos ids. There is no layout name and no--layoutflag: the exemplar IS the layout, copied by data.
The destinations decide the VIEWPORT, before anything records: footage resolution = viewport, and a 1280×720 take cannot honestly fill a 1920×1080 video spec. Record at 1920×1080 for a 1080p kit, 2560×1440 when a destination is larger.
If the work lands in a vos.so project (folder), pull it first and read every
.md recipe in it — LAUNCH.md binds this loop the way CUT.md binds a
cut, and a POSTER.md binds the posters. Recipes override this skill's
defaults.
2. Source: one take of the real thing
The kit is made FROM the product, never from a mockup (store policy agrees: misleading listing images are a removal-grade violation).
Stage the content like a set before recording. Half of what separates a
premium launch image from a screen grab is what is ON the screen. The
actions.json must leave the product in the state a proud screenshot would
show — labels typed, real-looking data, the feature mid-story — before any
poster or store still is cut. deliver drops a blank moment (a wallpaper,
an empty canvas) and says so, but it cannot stage the set for you.
Write the story into actions.json. Give steps an id (the moments
and the re-render loop address them by it) and a caption where a beat
deserves one (two to eight words; plan proposes it as a lower-third at
that step's moment on the cuts that take words). After a click that
navigates, put a wait for the load: the still is read at the END of that
wait, so the frame shows the page, never the spinner.
- Fresh recording: the
product-videoskill's loop (explore →actions.json→vos record --strict→ tunedoc.json). Keepactions.jsonin the repo — it is the next release's script. - The shipped feature is behind a login: settle the session before
the script, by the
product-videoskill's ladder (in full at https://vos.so/llms-full.txt, "Sessions"): mint one from the test auth the repo already has, else script the form off camera, else the human signs in once (vos session open <url> --name <app>, then--session <app>), else they record with the extension and you cut it. Record with--storage-state <file>. A release re-records every version, so prefer the rung that needs no human: it is the one that still works next release. Never type or accept a production password; keep the state file out of the take and out of git; record from a demo account, because a store listing showing a real customer's data is a removal-grade mistake. - Existing take: cut it with the
vos-cutskill. A hosted take comes home withvos fetch <vosId|watch-url> --out dir --media. - New version of a shot product: re-record with
vos recordinto the SAME take (the footage is replaced, the cut survives asdoc.prev.json), thenvos plan take --reusere-times the cut onto the new recording and names what could not follow. Never start from scratch; every fix is an edit todoc.json.
A motion-graphic segment rendered elsewhere is an INPUT: it drops in as a media overlay clip or a backdrop in the document, never the other way round.
3. The posters and the motion, as documents
The cut moves by data. A fresh vos plan proposes the cut's motion into
doc.json from LAUNCH.md's roles: the card's entrance, the END CARD (the
official End card template on vos.so, laid at the end: the card recedes
over a one-second freeze of its last frame, then the mark, the headline
arriving word by word, the release line and the URL settle on the ground;
its clips are stamped from: endcard), any template with: names at its
anchor, a caption per step, a music bed and a click sound on every press
when the take has no mic; every proposal carries a stable id (bed,
click-<n>, caption-<step>). On an existing cut --motion re-proposes;
a refresh never does, so a deleted end card stays deleted. A template is a
plain take on a shelf whose clips carry stable ids; a ref is a title on the
official shelf ("End card", "Split cover, square"), a vos id, or a
document on disk. Open the take in the studio and what you see is what the
kit renders.
vos plan take --motion --release v2.1
A poster is a DOCUMENT, a plain take: the card placed by frame.inset
(a negative side bleeds it off the edge), leaned by the tilt track's rest
pose, the words and the mark as overlay clips with stable ids
(stage-title, stage-kicker, stage-brand, stage-mark), and a
trailing hold on the last segment whose START is the still. Make one per
aspect class the release needs (landscape, square, portrait, tile), each
from the take's own footage:
cp -r take poster/landscape # or vos duplicate <take vosId>, then fetch --media
vos plan poster/landscape --style <poster vosId|doc.json> --headline "…" --kicker "…"
vos frames poster/landscape --frame <rest>; vos validate poster/landscape
vos push poster/landscape --folder <project-slug> --label "poster, landscape"
plan --style <poster> copies the LAYOUT (the card's placement and
presentation, the stage clips with the release's words patched in from
LAUNCH.md or the flags, the rest lean, the hold) onto the take and keeps
the take's own aspect, chrome and cut; the brand's mark from BRAND.md
logoUrl is fetched into brand/ for stage-mark, and what could not
follow is said. Narrow the segments to the moment (a zoom apex, the settled
response after a click) so the rest is the feature, never the cold open;
the product may keep PLAYING inside the card until the hold. Then look at
the rest frame: a poster is judged by eye before it is pushed. A human
opens it in the studio and drags the card, retypes the words in place,
moves the hold; vos pull --media brings that back down, and the next
release re-words it with the same plan --style from its own pushed
document.
4. Deliver
vos deliver take --to cws,producthunt,x,linkedin,og,github,youtube --release v2.1
One pass, and the verb decides what you used to decide by hand:
- The moments. Still times come from the STORY: every step's end plus a
settle (the end of the wait that follows a click), then the zoom apexes,
then a spread. Each candidate is read once as the real page; blanks are
dropped, two of one frame collapse to one, every drop said in
skipped[].--times step:<id>[+offset]names one. - Screenshots are the real page, full bleed: the store still and the
gallery drop the cut's zoom, tilt and chrome by default (
--composedkeeps them, and the picture pass refuses