demo-video
Skill12 starsChanged 2 months agoMITView on GitHub
Make a demo video of a piece of software: drive the app on screen while narrating what it does, generate an AI voiceover and optional on-camera presenter, and assemble everything into a finished MP4. Use when the user asks to "make a demo video", "record a demo", "create a product video", "show off this app", "make a walkthrough video", or runs /create-demo-video. Handles web apps, dashboards, websites, macOS desktop apps, browser extensions, and CLI/terminal programs (including demos of Claude Code plugins).
- Reads credentials
27 other projects use a version of this.
Adopted by
Most recently taken up by
- SaudSatopay/bullseyetheir own version, first seen Nov 8, 2026
- dxdleady/playwright-demo-videotheir own version, first seen Nov 1, 2026
- yzhao062/agent-configtheir own version, first seen Nov 1, 2026
- Kewton/CommandMatetheir own version, first seen Oct 30, 2026
- liaohch3/claude-taptheir own version, first seen Oct 25, 2026
- ooiyeefei/ccctheir own version, first seen Oct 25, 2026
Used with
Projects with it also use karpathy-coder, ai-act-readiness and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
csiddhant796-blipSkillkarpathy-coder
Use when writing, reviewing, or committing code to enforce Karpathy's 4 coding principles — surface assumptions before coding, keep it simple, make surgical changes, define verifiable goals. Triggers on "review my diff", "check complexity", "am I overcomplicating this", "karpathy check", "before I commit", or any code quality concern where the LLM might be overcoding.
Also in 4 projects that use this
Hussain-ElfalahSkillai-act-readiness
Also in 3 projects that use this
Hussain-ElfalahSkillc-level-agents
Also in 3 projects that use this
csiddhant796-blipSkillself-eval
Honestly evaluate AI work quality using a two-axis scoring system. Use after completing a task, code review, or work session to get an unbiased assessment. Detects score inflation, forces devil's advocate reasoning, and persists scores across sessions.
Also in 4 projects that use this
- +8 more from Hussain-Elfalah
Other versions27 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 27
- liaohch3/claude-tap★ 3.3ksame name
- microsoft/hve-core★ 1.6ksame name
- alinaqi/maggy★ 711same name
- alinaqi/claude-bootstrap★ 708same name
- ooiyeefei/ccc★ 497same name
- getsentry/junior★ 409same name
- hmislk/hmis★ 244same name
- Kewton/CommandMate★ 44same name
- Hassaan146/claude-skills★ 18same name
- yzhao062/agent-config★ 16same name
17 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository5 other files it gives its agents.
- demodaySkill
- demo-assemblySkill
- demo-captureSkill
- demo-scriptSkill
- demo-shortsSkill
The file
We split this skill into the rules it gives an agent
11 rules. 0 are common, 7 are distinctive, and 4 are very specific to this project.
0
Common
Most of the 25 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 72
Read the codebase you were pointed at.
- Distinctive: line 82
Use AskUserQuestion (or however your agent asks the user a question).
- Distinctive: line 339
If the user chose a custom character voice in Direction, design it after the script is written (previews audition with the real first line) …
- Very specific: line 392
Start a session with the MCP tools — demo_open for web, demo_open_app for a macOS app, demo_open_cli for a terminal program, …
- Distinctive: line 401
Every successful action is recorded automatically.
- Distinctive: line 428
If it warns that the steps overrun the narration, fix it in the script — either cut steps or lengthen that line.
- Very specific: line 444
If it warns that the retime factor was clamped, the take and the narration are too far apart — shorten the prompt or rewrite the line, then …
- Very specific: line 529
Every Short carries a cover — a hook card baked into frame 0, since that frame is the thumbnail on every vertical platform (the skill's …
- Distinctive: line 539
Narration before capture: Always.
- Very specific: line 542
Everything goes in
demo.json: If it only exists in your context, it is lost on the next run and nothing can be resumed or partially … - Distinctive: line 544
Report what you actually did: If a scene failed, say so and say which.
“Common” is measured: kept by at least 6 in 10 of the 25 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Making a demo video
You are producing a finished video of someone's software. Not a screen recording — a demo: narrated, paced, with an intro, transitions and a point.
$CLAUDE_PLUGIN_ROOT is the plugin root (outside Claude Code: the folder DemoDay
is installed in — two directories above this file, the one holding scripts/,
mcp/ and the top-level SKILL.md). Every command below runs from there unless
stated. Each video is its
own project directory under <repo>/demo/, named with a short kebab-case
description of that video:
demo/project-overview/ for a generic overview, demo/onboarding-flow/,
demo/v2-launch/. A repo accumulates one subfolder per video. Pick the folder
name when you pick the slug (they should match) and pass it as --project
demo/<slug> on every script call — never bare --project demo, and never
rely on the default project dir. The examples below write demo/<slug>; always
substitute the real folder.
The one thing to understand first
Two passes. Never record yourself exploring.
- Rehearsal — you drive the app through the
demo_*MCP tools, taking a screenshot after each action, working out what is worth showing. Nothing is recorded. The result is an action script. - Performance — a runner replays that script deterministically, with eased cursor motion and human typing, while recording. No model in the loop, so the footage is smooth and has no dead air.
A recording of you thinking is unwatchable. This is why the split exists.
Order of operations
Narration is generated before any capture. Once a line is spoken you know exactly how long it takes, so the capture can be paced to land on it. Doing it the other way round produces rushed voiceover or silence at the end of every scene.
recon → direction → script → narration → rehearse → perform → presenter/b-roll → render → QA0. Preflight
node scripts/doctor.mjs --installInstalls missing Node packages and Chromium, then checks keys, ffmpeg and macOS
permissions, printing the exact fix for anything it cannot do itself. Do this
before the first video on a machine and again whenever something fails
mysteriously. If the demo_* tools are missing from your tool list even though
the server is configured, the MCP server was started before its packages
existed — reload MCP servers or restart the agent after --install, or use
node scripts/stage.mjs (see §5).
1. Recon
Read the codebase you were pointed at. You need to be able to say what the product is, who it is for, and what its two or three best moments are. Look at the README, the routes or entrypoints, the data model, and any tests that read like user journeys.
Then find out how to run it. Ask the user for the dev-server URL, or the app name if it is a desktop app. Do not guess a port.
2. Direction — ask, don't assume
Use AskUserQuestion (or however your agent asks the user a question). The answers change the whole shape of the video:
Style — "which of these is it most like?" Show the catalog and let the user pick; each name is a complete look with sensible defaults (
plan.mjs --init --style <name>applies them):style aspect feels like launch16:9 Classic product demo: presenter intro/outro, narrated capture, b-roll anchor16:9 Avatar-led: the presenter is always on screen — full-frame between demos, corner bubble over them tutorial16:9 Step-by-step walkthrough: the full workflow on screen, the presenter riding along as a corner bubble dynamic16:9 Dynamic tutorial: one continuous presenter take re-framed every 4–6s (full-face / side panel / corner card) over zoomed-in screen beats, captions always on explainer16:9 No face: motion-graphic cards + voiceover over demos listicle9:16 "5 plugins that fix X" — numbered rundown, a cut every ~1.5s cohost9:16 Screenshare: demo on top, person talking below throughout flashcard9:16 No face: big text cards alternate with UI clips on fast cuts glide9:16 One immersive capture, the camera gliding to each click The 16:9 styles run on this skill directly (they are presenter-mode + transition presets). The 9:16 styles are Shorts — hand off to the demo-shorts skill for their recipes.
- Goal and audience — a launch trailer, an onboarding walkthrough, and an investor demo are different videos.
- Length — 30s, 60s, 2min. Default to 60s; tutorials default to ~60–90s, dynamic tutorials to ~120s. Length is the cost driver: narration, avatar and b-roll all bill per second, and a continuous-take style bills avatar-seconds for the whole runtime. Say so, default short, and let the user override — a 5-minute walkthrough is fine if that is what they want. (Shorts: 15–45s.)
- Presenter mode — see below; the style already picked a default.
- Voice — only if doctor showed
ELEVENLABS_API_KEYset: offer a custom character voice designed from a prose description ("weathered New England lobster-boat captain, gravelly, thick coastal accent") — great for themed or parody demos. Otherwise use the fal.ai stock voice and do not mention this. - What to show — offer your two or three candidate flows from recon.
Presenter modes
| Mode | What it means | When |
hybrid (default) | On-camera presenter for intro/outro/cutscenes; voiceover only over the screen | Almost always. A face over the UI is what amateur demos do. |
none | No human at all; motion-graphics cards instead | Dev tools, infra, anything where a stock-looking person undercuts credibility |
always | Presenter also appears as a corner bubble over the demo | Tutorials and walkthroughs, personality-led brands, founder-led launches |
In always mode every plain demo scene gets a lip-synced corner bubble from its
own presenterVideo clip (generated by the normal gen/presenter.mjs --all —
no extra command). The bubble's look is configured once in the manifest:
"presenter": { "mode": "always", "pip": { "shape": "circle", "position": "bottom-left", "sizePct": 22 } }shape is "circle" (default) or "square" (rounded corners); position is any
of the four corners; sizePct is the bubble's width as % of frame width (10–40).
A scene can override with its own pip: { ... }, or opt out entirely with
pip: false when the bubble would cover the UI the narration is pointing at.
One voice throughout. The narration and the presenter use the same voice, because the presenter is animated to the narration audio. Never generate a separate voice for the on-camera segments.
3. Script
node scripts/plan.mjs --project demo/<slug> --init --slug <slug> --name "<Product>"Then write demo/<slug>/demo.json. See the demo-script skill for the schema and how
to write narration that fits a demo. Sketch of a 60s hybrid video:
| id | kind | ~sec | purpose |
hook | presenter | 7 | The problem, in one sentence |
feature-1 | demo | 14 | The core action |
broll-1 | broll | 4 | Human context beat |
feature-2 | demo | 16 | The payoff |
outro | presenter | 8 | What to do next |
The tutorial recipe (--style tutorial)
A tutorial is the how-to alternative to the promotional styles: the screen is the
hero the whole way through, with the presenter riding along as a corner bubble.
Init with plan.mjs --init --style tutorial and follow these rules:
What the style seeds (all overridable in demo.json):
presenter.pip = { shape: "circle", position: "bottom-right", sizePct: 18 }— bottom-right because most apps keep navigation and primary content top-left.presenter.continuousPip = true— the bubble is one continuous lip-synced take for the whole video (gen/presenter.mjs --alldoes this automatically for the style; it is the same as--take). Every scene's narration is padded to its scene length and concatenated, then animated once, and the renderer plays that clip straight through underneath the cuts. No pop-in/pop-out at every step, no frozen bubble at scene tails, same avatar-seconds as per-scene clips. The take is cut into one chunk per scene (--take-chunk scene, the default; a scene under 4s rides with its neighbour), each chunk named after its first scene, so re-voicing one line regenerates only that scene's chunk — not the whole runtime (a one-word hook change on a 44s video used to re-bill the full take). Every chunk but the last ends in a 0.3s silent tail (--take-overlap) that the renderer fades the next chunk in over, so the avatar's re-pose at a seam is a short cross-dissolve, not a snap. An existing take whose chunks are all fresh is left alone whatever the rule (--rechunkre-cuts it, re-billing once);--take --dry-runprints which chunks a run would generate and the avatar-seconds it would bill — use it before any narration edit on a finished video.--take-chunk noneis the old greedy packing up to--take-max-sec(120); a refused long chunk automatically retries as 60s chunks.--take falsegives the old per-scene clips.--take --only <sceneId> [--engine <name>]generates just that scene's chunk asclips/take-test-<engine>-<scene>.mp4and leaves the manifest alone — the way to audition another engine on one scene before committing a take. Engines:kling-avatar(default),omnihuman, andseedance-2.5(reference-to-video; tested 2026-09-16 — great motion but it re-performs the narration at its own pace, so the lips drift off the audio track; see the registry note before using it).zoomToClick = falsemanifest-wide — the 1.18× push-in crops the sidebar, and in a walkthrough the whole UI is the point. Set it per scene to re-enable.- Short by default: ~60–90s. Avatar-seconds bill for the entire runtime in this style, so tell the user what a longer cut costs and let them choose.
Then follow these rules:
- One scene per step, numbered in the narration ("Step two: paste your API
key"), ~5–9s each — short steps, quick cuts. No presenter scenes, no b-roll —
demo scenes back to back, hard cuts (the style seeds an empty
transitionslist; keep it that way), then a card with the CTA. The bubble stays up through the card;pip: falseon a scene hides it there. - Capture per step with the normal rehearse/perform flow (default), or
record one continuous screen take of the whole workflow and chop it: give
every scene the same
videoand a scene-levelvideoStartSecmarking where its step begins in the take. - Terminal steps (a Claude Code session, a CLI) can be self-playing HTML
replay pages captured as
target: webwhen a real terminal cannot be driven — feed them the real output, never invented results. - The plan gate shows the bubble as its own "corner pip" line. Approve the estimate before generating.
Existing projects keep their scaffolded Remotion app: an older anchor/always
project only gains the corner bubble once its remotion/src matches the
template — render.mjs syncs it on its own when the project lacks files the
template has, or pass --sync-template (both overwrite local Remotion edits —
say so first) — plus gen/presenter.mjs --all.
The dynamic tutorial recipe (--style dynamic)
The engaging cousin of tutorial, measured from the best creator tutorials
(48 shots in 4:28, 2026-09-13): the presenter is still one continuous
lip-synced take, but instead of sitting in a corner it is re-framed every
4–6 seconds — full-frame face, a tall side panel next to the screen, a small
corner card over it — and every change is a ~0.3s ease-out move of the
frame with the screen content fading in or out beneath it. The screen is never
the whole window: each beat zooms 2–3× into the element being talked about.
Captions are always on: a bottom phrase box whose words appear as spoken, one
word per phrase in an accent box.
What the style seeds (plan.mjs --init --style dynamic):
presenter.mode = "always",continuousPip = true,takeAspect = "16:9"— the take is shot wide because face beats fill the frame; panel and card are crops of the same clip.gen/presenter.mjs --allusesassets/presenter-16x9.png(or the manifest'scharacterImagewhen that is the 16:9 file). For a kit character make it once withstill.mjs --edit --from <9x16 portrait> --aspect 16:9("same person, head and shoulders centred, eyes on the upper third, background continuing on both sides") so the face stays the same; a description-only project gets one generated. The take comes back at the engine's resolution (~1280×720 for kling): a full-frame face on 1080p is a 1.5× upscale, which is the reference look too.presenter.frame = { morphMs: 300, pace: "lively", faceFit: "auto" }—morphMsis the move duration (0= hard cuts; the reference tutorial measured ~200 but that reads too fast).paceis a direction question — ask it:"lively"is the creator grammar below (a move every 4–6s, the rules measure it);"calm"(plan.mjs --init --style dynamic --pace calm) is a plain step-by-step for people who find the jumping TikTok-coded:facefor the intro and outro, ONE panel or card layout per step, moves only at step boundaries, focus zooms still welcome. validate() then only caps a hold at 30s.faceFit"auto"letterboxes a square or 9:16 take (centred, full height, background either side) for the full-frame layouts instead of cropping it into a giant face;"cover"crops anyway. The side panel is a plain cover-fit of the take (panelZoom1–1.6 pushes in, but that magnifies the presenter's own movement and the face drifts off-centre — leave it alone).captions.style = "buildup",zoomToClick = false,transitions = [](a transition is an error in this style: overlaps drift the take's lip-sync),targetLengthSec 120.
Then write the manifest like this:
- ~120s ≈ 300 words at 2.5 wps. One scene per tutorial step, 10–15s each,
demo scenes back to back (no presenter scenes, no b-roll). A closing card is
optional; if you keep one give it
"layout": "none"(scene-level) — the take keeps running underneath, neverpip: false. - 2–3 beats per scene, each
{ "atSec", "layout"?, "videoStartSec"?, "focus"?, "cut"? }.layoutis one offace | face-band | panel-left | panel-right | card-tl | card-tr | card-bl | card-br | none; a beat without one inherits the previous layout, so a beat can be a content-only change.shotis optional (screenby default;insertstill works;face/split/cardare rejected — the presenter is framed bylayout). TimeatSecfrom the.words.jsontimestamps so moves land on clause boundaries. - The first beat of the first scene declares a layout (usually
face, ≤3s, the hook/proof) and the first move happens inside 3s. - Frame 0 is a hook band, not a blank frame. The style scaffolds
cover: { kind: "overlay", hook, kicker, accent?, portrait? }— the band over the real first frame (the face), held 0.5s then slid away. Write the hook (≤ 60 chars, the claim) and a short kicker.portrait(a square still of the presenter) is only for a video whose frame 0 has no presenter on it; build-props drops it when the presenter is already on frame 0 (afaceopening beat, an anchored split, a corner bubble), so the face is not shown twice. This is the poster of every README / embedded player, which otherwise shows whatever frame 0 happens to be. Delete the block to opt out. - Mix ≈ 40% face / 40% panel / 20% card, 20–28 layout shots at 120s,
never one layout for more than 12s. validate() warns on all of these; the
plan gate and
qa.mjsprint the layout stats. focusis{ x, y, w, h }as fractions of the capture frame — the box around the field/button the narration names,w0.3–0.5 (tighter than 0.3 is mush). A focus change on the same running clip glides there over 0.4s; avideoStartSecjump (or"cut": "dissolve") is amorphMs-long zoom-dissolve to the new moment. Whole-window beats (no focus) are for when the layout is the point;"framing": "pan" | "cover"on a beat opts into DemoClip's click-following pan instead of the focus box.- Pick the card corner away from the UI element being shown;
panel-rightwhen the interesting UI is on the left. validate() warns when a card sits in the watermark's corner. - Close with ONE spoken CTA (one ask per video): keep a
cardscene withlogo,title,cta(the URL) and give it"layout": "face-band"— the presenter fills the top 68% of the frame while the card draws as a band along the bottom (logo left of the title, the URL button under them). The band's crop also hides the stray hand gestures avatar engines put at the bottom of a take. A plainfacecard hides the URL;nonedrops the face. - Captions: keep the narration text clean (it goes to TTS); the emphasis word
is auto-picked per phrase. Add
captionEmphasis: [{ match, tone }]on a scene only to override;captions.autoEmphasis: falseturns the auto pick off. - Generate in this order: TTS → captures →
gen/presenter.mjs --all(once; one chunk per scene, seams cross-dissolved — a later narration edit re-runs it and only the changed scene's chunk is billed; batch wording changes anyway, and--dry-runfirst) → render. The plan gate shows the take as one "continuous take" line (~$0.056/s).
Renderer pieces, for the assembly guide: PresenterFrame.jsx (the moving
frame), DynamicScene.jsx (the content pane + focus/dissolve), lib/layouts.js
(the geometry), build-props (presenter.layoutTrack, per-beat resolved
layout, prevLayout).
Show the user the plan and the cost before spending anything:
node scripts/plan.mjs --project demo/<slug>Get explicit approval of the estimate before step 4. That is the point at which real money starts being spent.
3.5 Character voice (optional — needs ELEVENLABS_API_KEY)
If the user chose a custom character voice in Direction, design it after the script is written (previews audition with the real first line) and before any narration is generated (every scene uses it):
node scripts/gen/voice-design.mjs --project demo/<slug> \
--describe "Weathered 60-year-old New England lobster-boat captain, gravelly, thick coastal Maine accent" \
--name "Captain"That designs ~3 previews, auto-accepts the first, writes
voice.provider/voiceId into demo.json, and keeps all previews in
demo/<slug>/audio/voice-previews/. Tell the user to listen (afplay
demo/<slug>/audio/voice-previews/preview-1.mp3) and, if a different candidate is
better, run --pick 2 / --pick 3 promptly — un-accepted previews expire.
To hear candidates before anything is saved, add --audition and then --pick N.
Know these three behaviours:
- Same description = same voice, free. Designs are cached globally, so a re-run or a v2 of the video reuses the account voice with zero design spend.
- Voice slots are quota-limited on the ElevenLabs account.
--listshows what exists;--delete <voice_id>frees a slot when a character is retired. --use <voice_id>adopts an existing account voice with no design spend.
3.6 Sound effects (opt-in only — never add them unless the user asks)
Sound effects are off by default. Do not scaffold, generate, or propose an
sfx pack unless the user explicitly asks for sound effects. When they do,
plan.mjs --init --style <name> --sfx (or gen/sfx.mjs --init on an existing
manifest) adds the pack, the estimate shows a sound effects line (~$0.02 per
take, 3 takes per cue), and after the script is final:
node scripts/gen/sfx.mjs --project demo/<slug> --all # generate, accept take #1 of each
node scripts/gen/sfx.mjs --project demo/<slug> --cue whoosh --pick 2 # prefer another takeThe renderer then places cues on the events the style wires (sfx.auto), and
any scene/transition/beat can say "sfx": false or name a different cue.
Details in the demo-assembly skill § Audio.
4. Narration first
node scripts/gen/tts.mjs --project demo/<slug> --allWrites an mp3 and a .words.json per scene, and records the measured duration
back into demo.json. Every later step reads those durations.
5. Rehearse
Start a session with the MCP tools — demo_open for web, demo_open_app for a
macOS app, demo_open_cli for a terminal program, demo_open_browser for a
browser extension (it needs the toolbar and side panel in frame, which a web
scene never records). (No demo_* tools in your
tool list? node scripts/stage.mjs <name> drives the same server from the
shell — node scripts/stage.mjs tools lists them; see the top-level SKILL.md.)
demo_inspectbefore clicking. It returns real selectors ranked by durability; reading a selector off a screenshot is guessing, and guesses break on replay.- Every successful action is recorded automatically. Failed ones are not.
demo_undo_stepdrops an action that worked but does not belong in the video.demo_save_actions --file demo/<slug>/actions/<scene>.jsonwhen the flow is right.
While rehearsing, tell the user what part of the app you are exercising and what you found. That running commentary is half the value of this whole process.
See the demo-capture skill for staging, desktop coordinates and permissions, and for the setup-then-frozen browser profile an extension demo depends on.
6. Perform
Pass the narration duration so the footage lands on the voiceover:
node scripts/capture/web-perform.mjs \
--actions demo/<slug>/actions/feature-1.json \
--out demo/<slug>/clips/feature-1.mp4 \
--timestamps demo/<slug>/audio/feature-1.words.json \
--target-duration 14.0Desktop scenes use mac-perform.mjs --app "<App Name>" instead, and browser
extension scenes use browser-perform.mjs (the script carries its own url,
extension and profile). Then record the clip and its event log in demo.json
(video, events).
If it warns that the steps overrun the narration, fix it in the script — either cut steps or lengthen that line. Do not ignore it; the scene will overrun.
CLI scenes are different: the real program (e.g. a live claude session) sets
the pace, so cli-perform.mjs records at natural speed and retimes the take
in post to the narration duration (kept within 0.5x–2x; the raw take is saved
beside the clip):
node scripts/capture/cli-perform.mjs \
--actions demo/<slug>/actions/feature-1.json \
--cwd /path/to/demo-project \
--out demo/<slug>/clips/feature-1.mp4 \
--target-duration 14.0If it warns that the retime factor was clamped, the take and the narration are
too far apart — shorten the prompt or rewrite the line, then re-retime with
scripts/edit/retime.mjs (no new live take needed). See the demo-capture
skill's CLI section for staging, waitStable and pre-approved permissions.
7. Presenter and b-roll
node scripts/gen/presenter.mjs --project demo/<slug> --all # face generated once, reused
node scripts/gen/broll.mjs --project demo/<slug> --all # still → video, with model fallbackThese two are safe to run in parallel — manifest saves merge instead of clobbering each other.
Iterating on a hard shot
A composite shot (a specific character, in a specific place, doing a specific thing) rarely lands in one prompt. Iterate on the still before animating — a still costs cents, a video costs dollars:
node scripts/gen/still.mjs --project demo/<slug> --out assets/shot.png \
--prompt "wide shot on the deck of a trawler at golden hour…"
node scripts/gen/still.mjs --project demo/<slug> --out assets/shot-v2.png \
--edit "give each creature a soft contact shadow on the wet deck" \
--from assets/shot.png --ref assets/presenter.pngRead the image file after every step and edit what is actually wrong.
--ref passes identity references — pass the presenter portrait so the same
character appears in b-roll shots. --scene <id> attaches the result as that
scene's still (broll.mjs animates a supplied still instead of generating
one); --character records it as presenter.characterImage, which is how a
themed character (a ship captain on a headland) gets a portrait that
presenter.mjs's corporate-headshot prompt would fight. Version the filenames
(-v2, -v3) so you can compare takes and keep the best; identical re-runs
are cache hits and cost nothing.
For edits, pass --aspect whenever the output shape matters: without it the
model infers the aspect from the source images, and a portrait-format --ref
photo can drag a 9:16 --from down to 3:4.
A reusable character kit may ship a wardrobe/ of premade looks (same face,
different outfit/background — often edited from the canonical portrait with a
photo of a real garment as --ref). When one exists, pick a look the previous
video didn't use and copy it in under the canonical assets/presenter* names
— outfit variation without touching the manifest.
8. Render
node scripts/render/render.mjs --project demo/<slug>First run scaffolds a Remotion app into demo/<slug>/remotion/ and installs it. The user
can open --studio to tweak anything and their edits survive re-renders.
9. QA — actually look at it
node scripts/qa.mjs --project demo/<slug>Then read a sample of the extracted frames. There is no automatic grader. You are checking: is text legible, does the cursor go where the narration says, is anything sensitive on screen, does it look like something a company would publish.
The secret scanner only sees text — narration and typed values. Anything merely visible on screen (a real email in a sidebar, a live API key in a settings page) is only caught by looking at the frames.
Re-running regenerates only what changed, so fixing one scene is cheap.
10. Optional: a vertical Short
Once the demo is done, a 15–45s vertical cut for YouTube Shorts / Reels / TikTok can be made from the same project — reusing the captures, voice and best narration lines for pennies. See the demo-shorts skill; it starts with:
node scripts/plan.mjs --project demo/<slug> --init --manifest shorts.json --from demo.json --format 9:16Every Short carries a cover — a hook card baked into frame 0, since that
frame is the thumbnail on every vertical platform (the skill's §2b).
Offer this when the demo wraps; do not build it unasked.
Rules
- Never spend before showing the estimate and getting a yes.
- Narration before capture. Always.
- One voice. Set it once in
demo.json. - Demo scenes get voiceover, not a face — unless the mode is
always. - Everything goes in
demo.json. If it only exists in your context, it is lost on the next run and nothing can be resumed or partially regenerated. - Report what you actually did. If a scene failed, say so and say which. A video with a broken scene is worse than one with a missing scene.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

