<< All versions

Skill v1.0.0

currentTrusted Publisher100/100
microsoft/vscode-team-kit/generate-video
──Details
PublishedOctober 22, 2026 at 03:36 PM
Content Hashsha256:dc655614414aefc8...
Git SHA4ee7a1f23b12
──Files
Files (1 file, 9.9 KB)
SKILL.md9.9 KBactive
SKILL.md · 150 lines · 9.9 KB

version: "1.0.0" name: generate-video description: 'Make the shortest narrated video that fully explains a GitHub pull request (at most 90 seconds, captions, diagrams chosen for the PR, and real footage of the app, before and after side by side, when the change is visible) in one white Microsoft look. USE FOR: "/generate-video 12345", "make a video of this PR", "explain PR <url> in a video", "a video for my manager about this PR". DO NOT USE FOR: a screen recording on its own (no PR to explain), editing existing videos, slide decks (use generate-presentation).' argument-hint: PR number or URL


Generate a PR video

The shortest narrated video that fully explains one pull request: at most 90 seconds, captioned, with a diagram for each idea and, when the change is visible, the real app doing it. You write the story and fill the diagrams from the PR; the engine fetches, voices, renders, and checks every word on screen against the PR. First read contract.md.

Needs: a terminal that runs commands for minutes, and file tools (reading images, subagents and chat artifacts help). macOS or Linux with Node.js 20+, Python 3.11–3.13, and access to github.com and PyPI. Commands install what they need into ~/.cache/ on first use. gh, signed in, is optional: public PRs work without it.

The fast path: setup.mjs → prs new → storyboard.json and prs check → prs direct → footage, in a subagent if you have one (prs app, the capture kit) → prs voice in the background while you fill scenes.js → prs preview until lint is clean → prs publish → prs review-pack and the review → fixes, prs publish, prs review-pack, until signed off → deliver.

1. Find the PR and the engine

  • The PR:
  • a URL or <owner>/<repo>#<n>: use it;
  • a number alone: a PR of the workspace's GitHub repo;
  • nothing: ask.

A calling skill may pass a brief (a code walkthrough's groups): follow it as the contract says. For a brief about a branch, use its PR (gh pr view <branch> --json url, in that repository); if it has none, say that a video needs a pull request, and stop.

  • The engine: run node <plugin>/scripts/setup.mjs by absolute path; <plugin> is two folders above this file.
  • Its last line is STUDIO=<folder>. Below, prs <x> means node <studio>/cli/prs.mjs <x>, and prs help lists

every command.

  • If something can't be installed (no Python 3.11–3.13), stop and say what to install.
  • The voice is MAI-Voice-2 when AZURE_SPEECH_KEY is set or ~/.cache/pr-studio/config.json names an Azure

resource (voice.mai.azResource), otherwise the offline Kokoro; prs doctor says which.

2. Make the video

About 10 minutes, or 25 with footage, reviews included. Post a one-line update after each step.

  1. Fetch. prs new <url> writes <studio>/videos/<slug>/ (the slug is <owner>-<repo>-<n>; pass it to every

command): brief.md, pr.diff, the changed files, and a storyboard skeleton. If the change is visible in VS Code, start prs app <slug> --before in the background now: the builds download while you write the story.

  1. Story. Write storyboard.json (below). Run prs check <slug> until it passes, then apply the cut test.
  2. Direct. prs direct <slug> picks a diagram treatment for each beat, different from recent videos. It scaffolds

scenes.js with each pick's fields and a note on how to narrate it ("names the aspects in order"): fit each say to its pick.

  • Keep the picks.
  • To re-pick one that can't show its beat: prs direct <slug> --use <beat>=<treatment> --reason "…", then

prs direct <slug> --force to rewrite the scaffold (before you fill it; the picks stay). prs catalog lists the treatments. If none fits, say so in your answer.

  1. Footage, when the PR changes something a user sees or does: capture.md. It needs only

the storyboard. With subagents, hand it to one now (capture.md, the slug, <studio>, and the footage beat's say and cues), and go on with the next steps while it records.

  1. Voice and scenes. Start prs voice <slug> in the background, and fill every TODO of scenes.js meanwhile

(below). The voice prints what a listener hears in each beat. Fix a word "heard differently" with pronounce or other words, then run prs voice <slug> --redo <beat>.

  1. Preview. prs preview <slug> renders key frames and build/stills/contact.png, then lints. Look at the sheet,

then the frames that matter, and fix until lint reports 0 problems. Lint times the screen too: text up too briefly to read is a problem (give the beat a hold, or say less), and an element named before it shows is a warning worth a look.

  1. Publish. prs publish <slug> renders, encodes, and checks the audio against the captions (the sync gate; a

failure says what to fix). It then delivers the video.

The storyboard

A beat is one idea, in one to three sentences, with one diagram. Merge or drop the skeleton's beats that add no answer: a before and after can show both what changes and why.

  • `id`: a short word.
  • `need`: the kind of diagram.
  • concept: a problem, or ideas side by side;
  • exchange: messages between parties;
  • flow: steps;
  • rules: a rule applied to cases;
  • compare: before and after;
  • architecture: where it reaches;
  • code, numbers, state, ui, status.
  • `say`: plain sentences. The voice says why and how; numbers, names and lists go on screen. A number it must say

is a placeholder: {{facts.additions}}.

  • `cues`: names for the phrases where things appear: "step2": "Two", or { "phrase", "nth", "offset" } (nth

counts from 0: a phrase said twice cues the first time unless nth is 1).

  • `claims`: every factual statement, as { "text": "…", "evidence": [ … ] }. prs check verifies each piece of

evidence: { "file", "anchor" } (text or a regex at the head commit; "removed": true for a removed line), { "body" }, { "commit" } or { "review" } (exact words), or { "fact": "additions" }. A count you make is a claim: anchor each thing counted.

  • `"footage": true`: on the beat that shows the real app.
  • `"hold": 1.5`: seconds (up to 5) the beat stays after its last word, when its screen needs time to be read.

The first beat (title) says what the PR does in one sentence; its card shows the number, author, size and state. The last (status) says what matters most before review or merge; its screen lists scope, tests and where to start reading.

Pronunciation. The voice splits camelCase, spells short capitals and says "dot". Anything else goes in the top-level pronounce ({ "scm": "S C M", "mcumming": "M Cumming" }).

  • Don't say a code name alone (start() → "the start method"); name a file in words and show its path on screen.
  • Don't respell what the voice says well (OK, UI). A one-word entry also works inside names; add plurals you say.
  • Use commas only for real pauses: captions break there, and the gate checks that the voice pauses too.

scenes.js

Beat keys are the storyboard ids. The engine lays everything out. Never open another video's scenes.js.

  • Text: every string on screen says where it comes from, and the engine checks it:
  • label('…'): your words (numbers in it are flagged);
  • fact('additions', { format: 'n' }): from pr.json (formats n, date, state, review, lower);
  • quote('…'): exact PR text (the body, commits, review, any diff line);
  • ident('name'): a name in the changed files;
  • path(file): a changed file.

Mix them in an array.

  • Code: code(file, { from, to }), { anchor } (one line), { anchor, block: true } (the function), or

{ diff: true, anchor } (its hunk); add occurrence: n when the anchor matches several lines. Avoid long lines: the font fits the longest.

  • Time: an at is a cue name, cue('step2', 0.4), word('401', { offset: -0.2 }), or seconds into the beat.

Without one, items spread over the beat.

  • Icons: prs catalog --icons lists the names.
  • Footage: a "footage": true beat gets ui.footage.
  • after: { src: 'footage/after.webm', marks: { open: 'open', click: 'click' } } plays each action marked in the

recording (k.mark('click')) at the cue it maps to, at real speed, and holds its result until the next; before is the same for the app without the change. Optional: crop: [x, y, w, h], label, note, and layout: 'rows' for a wide, short part. A clip without marks takes from, to, at (its cue) and speed.

  • Narrate what happens as it happens, with a cue on each action and its result. A before and after is one beat: say

the action once, then the difference ("press Save: the old build drops the selection, the new one keeps it").

  • Voicing again moves the cues, and the actions follow them: record once.

3. Review

Follow review.md, with prs review-pack <slug> before each round.

  • Reviewer inputs:
  • the PR URL, the slug and <studio>;
  • the pack's pack.md (prs review-pack prints its path);
  • from <studio>/videos/<slug>/: brief.md, pr.diff, storyboard.json, scenes.js and footage/;
  • the delivered mp4.
  • Review file: build/review.md.
  • After fixes: run prs publish and prs review-pack again.

4. Deliver

prs publish prints where it delivered the mp4 (~/Downloads/pr-videos/<slug>/ by default). That folder holds the mp4, a webm (VS Code's chat plays it in place of the mp4), the captions and contact.png.

  • Called by another skill or agent: don't end your turn: give it the paths and what it asked for. It records the

artifacts.

  • With a chat-artifact tool: record the mp4 (Video: #<n> <PR title>, plus (self-reviewed) if it was) and

contact.png (Key frames: #<n>), by absolute path. End your turn there.

  • Otherwise: end with the mp4's path and length, a line per beat, the verdict, and what you couldn't check.
All versions