Communitygithub.com

product-video

Enregistrez et produisez la vidéo de démonstration d'un site web, d'une application ou d'une fonctionnalité avec l'outil CLI vos — l'agent scripte le chemin de clics (actions.json), l'enregistrement planifie automatiquement les zooms, et chaque décision de montage est une donnée dans doc.json, donc les corrections sont des modifications et des nouveaux rendus, jamais de nouveaux enregistrements. Les rendus sont déterministes ; l'exportation est gratuite jusqu'en 4K sans filigrane.

Qu'est-ce que product-video ?

Ce skill, `product-video`, permet à un agent IA de produire de bout en bout une vidéo de démonstration professionnelle d'un site web, d'une application ou d'une fonctionnalité, en utilisant l'outil CLI `vos`. L'agent orchestre tout le processus : exploration de la page, écriture d'un script de clics (`actions.json`), enregistrement, puis réglage précis du montage via un fichier `doc.json`. La grande force de ce skill est sa nature déterministe et non destructive : les corrections de rythme, de zoom ou de cadrage se font en éditant le fichier `doc.json` et en relançant le rendu, sans jamais avoir à ré-enregistrer la vidéo originale. Cela fait gagner un temps considérable et garantit une qualité constante. Le skill couvre également des cas complexes, comme les produits derrière une authentification, en guidant l'agent à travers une procédure de session en escalier pour obtenir les credentials de test avant de commencer l'enregistrement. Les sorties incluent des vidéos (WebM, MP4) et des images fixes aux dimensions exactes, le tout exportable sans filigrane jusqu'en 4K. Il s'intègre parfaitement au workflow du développeur, avec des commandes de répétition (`--dry-run`) pour valider le script avant l'enregistrement final, et des outils de relecture (`vos frames`) pour inspecter les images clés avant le rendu final.

Compatible avec~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/vosjs/skills/tree/main/skills/product-video

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Vidéo produit (et les assets qui l'entourent), de bout en bout

Vous produisez un asset produit expédiable — une vidéo soignée, un ensemble d'images fixes aux dimensions exactes, ou les deux — à partir d'une page web en direct, avec l'interface en ligne de commande vos. Tout est une donnée : vous écrivez un script de flux, le CLI enregistre et planifie, vous ajustez du JSON, vous refaites le rendu. Ne ré-enregistrez jamais pour corriger le rythme ou les zooms — modifiez doc.json et refaites le rendu. Barre de qualité : references/taste.md — suivez sa boucle de qualité et jugez les images fixes de manière multimodale.

Configuration

npm i -D @vosjs/cli

Une commande, un paquet : @vosjs/cli est le binaire open source (MIT) vos avec les verbes du moteur, le pipeline de prise utilisé ici (record / plan / frames / render sur les enregistrements d'écran) et les verbes de la plateforme vos.so. (Jusqu'à la version 0.9, le pipeline de prise était distribué séparément sous le nom @vosso/vos-plugin ; un projet qui le liste encore peut le supprimer.) Prérequis :

  • Un Chromium : le Chrome système est trouvé automatiquement ; sinon npx playwright install chromium ou pointez VOS_BROWSER_PATH vers un. Le code de sortie 3 signifie qu'aucun navigateur n'a été trouvé.
  • Réseau au moment du rendu : la page de rendu charge three/mediabunny depuis esm.sh. L'enregistrement a également besoin d'atteindre l'URL cible. Les bacs à sable hors ligne ne peuvent pas faire de rendu — dites-le plutôt que de ne rien livrer.

Conventions : logs → stderr, résultats → stdout ; --json diffuse du NDJSON se terminant par {"event":"done",…} ; codes de sortie 0 ok / 1 erreur / 2 utilisation ou échec strict / 3 pas de navigateur / 4 l'enregistreur a rencontré une page de connexion au lieu de la page (un SESSION manquant ou expiré, jamais un bug de script : references/sessions.md). vos <verbe> --help affiche les flags de ce verbe (@vosjs/cli 0.41.1 et ultérieur).

Étape 0 — choisissez la destination (elle décide de tout)

DestinationViewportSortieExtras
Clip pour page d'accueil (intégration hero/section)2560×1440 (footage natif 2K)webm → re-encodage VP9 + afficheboucle silencieuse ; voir references/destinations.md
Vidéo de lancement (PH, social, promo store)2560×1440 ou 1280×720mp4 (--format mp4, nécessite Chrome système)fond musical via doc.audio
Images fixes du kit de lancement (captures d'écran store, tuiles, OG)dimensionnées pour l'assetPNGs frames --frame <t> --size LxH à partir de la même priseune prise → chaque asset
Démo rapide (issue, PR, chat)1280×720webm, valeurs par défautrapidité avant le polissage ; les brouillons sont acceptables UNIQUEMENT ici

Dimensions par canal et budgets d'octets : references/destinations.md.

La boucle principale (chaque destination)

  1. Explorez la page cible avec vos propres outils (fetch HTML / Playwright). Identifiez les 3 à 6 moments qui racontent UNE histoire. Collectez des sélecteurs STABLES (a[href='…'], ids, rôles — pas des chaînes nth-child). Mettez le contenu en scène comme un plateau : le script doit laisser le produit dans l'état qu'une fière capture d'écran montrerait — étiquettes tapées, données réalistes, la fonctionnalité en plein récit. Un canevas vide s'enregistre vite et ne fait pas de démo, et aucune composition en aval ne le sauve.

    Derrière une connexion ? Réglez la session avant le script. Un enregistreur sans session enregistre le mur (la page de connexion, ou la page publique que le site envoie à un inconnu) et le seul symptôme est un sélecteur sauté. Parcourez l'échelle dans references/sessions.md de haut en bas et arrêtez-vous au premier barreau qui tient : pas de mur (un mode démo, un serveur local avec auth désactivée) → CRÉEZ une session à partir de l'auth de test que le projet a déjà (playwright/.auth, un auth.setup.ts, un script d'amorçage : regardez avant de demander à qui que ce soit) → connectez-vous hors caméra avec setup dans actions.json (le mot de passe depuis { "env": "NOM" }, jamais un littéral) → l'humain se connecte une fois (vos session open <url> --name <app>, puis --session <app> sur record) → l'humain enregistre avec l'extension depuis la liste de plans vos actions script actions.json imprime, et vous le montez. Chaque barreau se termine par setup, un fichier d'état pour --storage-state, ou une session nommée pour --session. Ne tapez jamais ni n'acceptez un mot de passe de production, gardez le fichier d'état en dehors du répertoire de prise et de git, et enregistrez à partir d'un compte de démo : ce que le compte montre est livré dans la vidéo.

    Vous avez déjà vérifié la fonctionnalité avec agent-browser ? Gardez cette navigation et sautez le second script. Le résultat --json d'agent-browser ne dit pas ce qui a été exécuté (scroll répond {scrolled:true}), donc enveloppez chaque appel pour que la commande chevauche son résultat, puis convertissez :

    ab() { agent-browser "$@" --json | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const r=JSON.parse(s);process.stdout.write(JSON.stringify({command:process.argv.slice(1),...r})+"\n")})' -- "$@" >> steps.jsonl; }
    ab open https://target.example; ab snapshot -i -u; ab click @e27
    ab wait 800; ab snapshot -i          # la page a changé : les refs sont renumérotées
    ab fill @e2 query; ab press Enter
    vos actions from-agent-browser steps.jsonl --out actions.json
    

    (un chemin entier exécuté comme un seul agent-browser batch … --json > steps.jsonl a déjà cette forme). Le journal est steps.jsonl dans le répertoire où vous vous tenez, donc naviguez depuis un seul répertoire. Les refs se résolvent via la dernière snapshot -i avant elles, et elles sont RENUMÉROTÉES après une navigation et à nouveau dans une boîte de dialogue : refaites un snapshot après tout ce qui change la page et lisez les refs avant d'en nommer une (-u donne aux liens leur href). Cliquez sur le contrôle, n'utilisez pas son raccourci : ⌘K ouvre la boîte de dialogue pour un humain, mais une frappe est la seule étape que l'enregistreur ne peut pas rejouer. Tout ce qu'il ne peut pas suivre (une touche de raccourci, un glisser-déposer, un second open) est NOMMÉ dans la sortie, jamais supprimé : lisez les notes, écrivez ces étapes à la main, puis enregistrez.

  2. Écrivez actions.json :

    {
      "url": "https:
      "viewport": { "width": 1280, "height": 720 },
      "steps": [
        { "do": "wait", "ms": 800 },
        { "do": "hover", "selector": "a[href='/pricing']", "ms": 700 },
        { "do": "click", "selector": "#cta" },
        { "do": "wait", "ms": 1500 },
        { "do": "scroll", "dy": 400 },
        { "do": "move", "x": 640, "y": 320 },
        { "do": "wait", "ms": 900 }
      ]
    }
    

    Verbes : wait hover click type scroll move drag (type = {do:'type', selector, text, delayMs?, ms?, focus?} : il clique sur le champ, puis tape text ; focus:false tape dans ce qui est déjà focus, pour un Entrée de soumission) (drag = modifications réelles : {do:'drag', selector|x,y, tx, ty, ms} — glissez un curseur de plage, faites glisser un élément canvas, déplacez un clip de timeline). Le RYTHME EST le plan de zoom : ouvrez wait ≥700ms ; survolez ce qui compte 700–900ms (les temps de pause deviennent des zooms) ; le ms d'un clic est le temps de LECTURE, mesuré à partir du dernier changement de la page (@vosjs/cli 0.47 et ultérieur ; l'enregistreur paie le stabilisateur lui-même), donc dimensionnez-le comme un temps : environ 1000ms après une navigation, 600ms après un contrôle, jamais prolongé pour une page lente ; terminez stable. Éloignez le curseur des menus déclenchés au survol (taste.md, règles de flux). Vérifiez avec vos validate actions.json.

    Ensuite, RÉPÉTEZ-LE (@vosjs/cli 0.39 et ultérieur) : vos record --actions actions.json --out take --dry-run. Chaque étape s'exécute sur la vraie page, dans l'ordre, car un sélecteur ultérieur n'existe généralement qu'après un clic précédent, mais rien n'est capturé et rien n'est écrit : un sélecteur manqué est nommé en secondes (exit 2) au lieu d'être après une prise en temps réel et son encodage, et une prise déjà dans --out conserve ses images et son montage. Il imprime le rect de chaque étape en px de capture, ce qui est ce qu'une couche épinglée lit. Répétez après chaque modification du script, et n'enregistrez qu'un script qui réussit. Un produit connecté se répète de la même manière : --storage-state et --browser-arg= s'y appliquent aussi, et la répétition se termine en listant ce que le cadre EXPOSE (une adresse, une clé, une carte). Masquez-les avec mask avant d'enregistrer : references/sessions.md.

  3. Enregistrez : vos record --actions actions.json --out take --strict --json --strict toujours : sélecteur sauté / timeout networkidle → exit 2 avec skipped[] dans l'événement done. Un saut signifie que le flux est cassé — corrigez-le, ne le contournez jamais. La prise s'auto-encode et s'auto-planifie. (vos create --actions actions.json out.webm --strict est le verbe enregistrer+rendu en un coup — bon pour un premier passage rapide, mais la boucle DE CE skill examine les images avant le rendu, donc préférez les verbes séparés ici.)

  4. Ajustez doc.json (le schéma JSON est livré dans le paquet npm @vosjs/cli : schema/doc.schema.json) :

    • zoom : [{in, out, level, cx, cy, source}], SOURCE en secondes ; niveaux 1.4–2.8 ; cx/cy NORMALISÉS [0..1] (0.5,0.5 = centre) — PAS des pixels ; définissez "source": "manual" sur les plages que vous touchez (survit à un re-plan).
    • segments (recadrages) · speed (rate 0.1–16) · frame.* · cursor.
    • tilt : [{in, out, rx, ry, source}], SOURCE en secondes — la carte 3D s'incline dans la pose lorsqu'elle est active, revient au repos entre les deux. DEGRÉS (±5..18 se lit premium) : +rx = bord supérieur plus proche, +ry = bord gauche plus proche (s'incliner vers un focus à droite = ry négatif). Plages ≥ 0,8 s ; associez à des moments de zoom (les mêmes entrées/sorties enchaînent les mouvements), un changement de pose par ~5 s de temps. "source": "manual" sur les plages que vous touchez ; tiltStyle: "subtle"|"medium"|"strong" enregistre la baguette automatique.
    • frame.backgroundMedia : une boucle vidéo / image derrière la carte — {"kind":"video","key":"/bg.webm","duration":10,"dim":0.2}. key = un fichier déposé dans le répertoire de prise ("/bg.webm") ou une URL de média ; la vidéo a besoin de duration (ancré à la SORTIE modulo boucle) ; dim 0..1 écran. Ambiance, pas un sujet — atténuez-le derrière une UI dense.
    • audio : clips ancrés à la SORTIE ; key peut être un fichier déposé dans le répertoire de prise ("/music.mp3") ; gain/fades/boucle. Mixé sur les rendus complets (Opus/AAC) ; --range reste silencieux ; force le vol simple.
    • export : {"resolution": "720p|1080p|2k|4k", "fps": 30} — jamais au-dessus du footage (validate avertit). Ensuite vos validate take --json — les vérifications lint doivent réussir.
  5. Regardez avant de rendre (la boucle de qualité taste.md) :

    • vos frames take --at-zooms --times 0,25%,50%,75%,100% --json → jugez chaque image fixe par rapport à taste.md, les apex de zoom le plus sévèrement.
    • Itérez : modifiez doc.json → vos render take check.webm --range a..b --draft (secondes, demi-résolution — ne livrez jamais de brouillons) → recadrez la région modifiée.
    • Vous essayez une présentation ? Utilisez un flag, pas un script scratch. render/frames prennent des overrides de doc — --set <chemin>=<valeur> (répétable ; JSON-ou-chaîne), --frame <macos|windows|minimal|none> (render), --background <url> — qui patchent le doc en mémoire (doc.json intact) et sont validés par lint. Donc vos frames take --frame 2.0 --set frame.browserBar.kind=mac-light --set tilt[0].rx=8 prévisualise une carte encadrée et inclinée sans toucher au fichier.
  6. Rendu final : vos render take out.webm --json (ou --format mp4). Re-cadrez le résultat final (frames --at-zooms) par rapport à taste.md avant de déclarer terminé. Les rendus sont déterministes — seules vos modifications changent la sortie.

6b. Tour de révision humaine (lorsque la demande en implique une) : vos open take sert la prise dans le studio — vos modifications de doc.json arrivent intactes et

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

launch-kit

Ship the media with the release — one take of the real product becomes YouTube demo, Chrome Web Store screenshots/tiles, Product Hunt gallery, social cuts, and OG cards; verified kit.json manifest.

vos-authoring

Author a vos animation program (VosConfigJson) from scratch or debug one — declarative configs compiling into deterministic Three.js + GSAP-dialect animations on the MIT vos engine (@vosjs/core), validated locally with compileVosConfig. Covers the schema, dialect rules, 2D overlay elements, shaders, and params/presets knobs. Use when asked to write a vos animation program, create a VosConfigJson, make a programmatic motion graphic or logo animation, or fix a config that fails to compile or lint.

vos-create

Create vos programs in the user

vosjs/vos-cut

Cut a screen recording (a vosso take) into the product video it was recorded for, from its evidence, with the vos CLI — read the take's digest (the moments the cursor track says mattered, each with a footage frame and a crop), narrate beats, edit doc.json by exception over the planners, verify with stills, and push an attributed version the human fine-tunes at vos.so; every edit is a data patch, so a re-cut never re-records. Use when asked to edit or cut a recording, make a product video or what's-new clip from a take, cut it like the last one, or cut a series of recordings in one style.

vosjs/vos-footage

Hand a Remotion, HyperFrames, or any video composition a clean captured clip of the real product — recorded and auto-zoomed with the vos CLI, delivered as full-bleed footage with no chrome, and always backed by an editable take on the maker's shelf, which the handoff says. Use when a composition needs real product footage, app or site b-roll, "capture our app for the video", or a screen-recorded segment to drop into another tool's timeline.

vosjs/vos-migrate

Turn an existing Loom, Screen Studio, Cap, or plain mp4/webm screen demo into an editable vosso take — re-encode the file, synthesize the take's metadata, plan, and push, so the old demo becomes a living document you re-cut instead of a file you re-record. Use when asked to "convert this Loom", "migrate our old demos", "re-edit this mp4", "make our Screen Studio recording editable", or to bring any already-recorded demo into vosso.

vos-remix

Remix a vos.so gallery program into your own — fetch its config, edit the declared knobs or code locally, validate with vos check, and push a private copy back with lineage that iterates as versions. Carries the params/Looks doctrine and the GLB 3D-showcase recipe. Use when asked to remix, customize or personalize a gallery animation, swap a 3D model into a showcase, or iterate a fetched program as versions.

Skills associés