Turn content into a finished 9:16 short deck. The look is fixed and lives in
this skill; the only thing that changes per short is a content file.
-
Get the content. The user gives the message/steps. Map it to scenes —
one idea per scene. For each scene decide: kicker (mono label), headline
(short, Bricolage), optional supporting visual (code block, feature list,
panel, screenshot), a duration in seconds, and the teleprompter note (one
"now" beat + 1–2 bullets). If the user didn't specify length, target ~120s
total and split proportionally. Ask only about content gaps, never style.
-
Write a content module. Copy assets/content.example.mjs to a working
content.mjs and replace the scenes. Import helpers from
assets/helpers.mjs. Schema per scene:
{ dur: 20,
res: "head off · full-bleed",
frame: "<...raw HTML...>",
notes: { now:"the beat", beats:["bullet","bullet"] } }
Layout convention: split scenes (content top, webcam bottom) end their
frame with talkingHead(); full-bleed scenes wrap content in
<div class="full">…</div> and add pip() for the corner head bubble.
See assets/STYLE.md for the full class + helper reference and palette.
-
Screenshots (optional). If a scene shows a captured web page, use the
shot("__SHOT__", "https://the.url") helper in the frame and provide a
shot.png next to the content file — the builder inlines it. To capture one
live, drive a browser (e.g. the browser-api service) and save its
/screenshot PNG as shot.png. With no shot.png, a gradient placeholder
is used so the deck still builds.
-
Build.
node <path-to-skill>/assets/render.mjs ./content.mjs --shot ./shot.png --out ./short.html
It pre-renders every scene (so the output needs no build-time helpers),
inlines the screenshot, bakes scene 1 into static HTML (shows even where
inline scripts are blocked), and writes a self-contained file.
-
Verify before delivering. Open short.html headless, confirm no page
errors, that the countdown ticks down during playback, and screenshot scene 1
(teleprompter) + record-mode to eyeball the layout. Example:
node -e 'const{chromium}=require("playwright");(async()=>{const b=await chromium.launch({headless:true,args:["--no-sandbox"]});const p=await(await b.newContext({viewport:{width:1440,height:900}})).newPage();const e=[];p.on("pageerror",x=>e.push(""+x));await p.goto("file://"+process.cwd()+"/short.html");await p.waitForTimeout(700);await p.keyboard.press(" ");await p.waitForTimeout(2500);console.log("errors:",e.length?e:"none","cd:",await p.$eval("#cd",n=>n.textContent));await p.screenshot({path:"verify.png"});await b.close();})()'
-
Deliver short.html (and keep content.mjs + shot.png so the short can
be iterated later — this skill is meant to be built on).