agentsclimarketplace

Launch video

Skill modem-dev/sideshow/skills/launch-video

Produces sideshow release/feature videos by driving the real viewer in a recording Chromium against a live server — 1920x1080 stage with window chrome, captions, and title cards, encoded with ffmpeg. Use for release roundups, single-feature demos, PR walkthroughs, and social announcements.From its SKILL.md

Install
npx -y skills add modem-dev/sideshow --skill launch-video

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

8.8 KB, as published. Nobody here has run it

Sideshow video pipeline

Maintainer-only: requires a sideshow source checkout (the pipeline lives in scripts/launch-video/, which never ships to npm).

Generates product videos where every app frame is the real sideshow viewer talking to a real server — no screen recording, no mockups. Unlike hunk's keyframe-compositing pipeline (skills/launch-video in the hunk repo), sideshow's product IS live motion — cards streaming in over SSE, sandboxed iframes resizing, the comment loop — so this pipeline records one real-time pass instead of compositing stills:

stage.html    a 1920x1080 HTML stage: window chrome + caption lower-third +
              full-screen title cards, with the live viewer in an iframe
record.mjs    boots a fresh server, seeds demo content, drives the storyboard
              with Playwright while recording video, prints the raw webm path
ffmpeg        re-encodes the raw webm to mp4 (h264) and webm (vp9)

Two halves live in record.mjs: reusable machinery (boot, seed, CSP strip, stage resolution, browser/recording setup) and the storyboard — the scene sequence, captions, and title cards. The storyboard is editorial content for one video; rewrite it per video. As of this writing the checked-in reference storyboard is the 0.13.0 release video.

Creating a video

Expect a run to take roughly the video's length plus ~20s boot; encoding adds a couple of minutes. Total output should stay near 40–60s.

# 0. one-time work-dir setup (fonts are optional but much nicer than DejaVu)
mkdir -p .video-work && cd .video-work
printf '{"name":"sideshow-video-work","private":true}\n' > package.json
npm i @fontsource-variable/inter @fontsource/jetbrains-mono
cd ..

# 1. record (server boot + seed + storyboard, prints the raw webm path)
node scripts/launch-video/record.mjs

# 2. encode both deliverables
cd .video-work
RAW=$(ls page@*.webm)
ffmpeg -y -i "$RAW" -vf "fps=30,format=yuv420p" \
  -c:v libx264 -preset slow -crf 18 -movflags +faststart sideshow-X.Y.Z.mp4
ffmpeg -y -i "$RAW" -vf "fps=30,format=yuv420p" \
  -c:v libvpx-vp9 -b:v 0 -crf 32 -row-mt 1 sideshow-X.Y.Z.webm

Choosing a recipe

  • Full release: distill 3–5 user-visible headlines from the release's CHANGELOG.md section (per-PR entries are too granular to shoot; confirm a non-obvious shortlist with the user). Lead with what sideshow is (the publish → live render → comment → revise loop) before the release-specific scenes — a social audience hasn't seen it before. End on an install card.
  • Single feature / PR: intro card → one or two scenes demonstrating the change → outro card. Name the output after the feature (sideshow-0.13-sidebar-rail.mp4), keep it 15–30s, and keep the canonical release storyboard in record.mjs intact — do the trim as a local edit and revert, or copy record.mjs to a scratch sibling (imports keep working) and delete it after.
  • Custom: any scene set works — tutorials, comparisons, announcements. Whatever runs in the viewer can be driven: publish over the API mid-recording and the cards stream in on camera; that's the money shot, use it.

Storyboard model (record.mjs + stage.html)

  • The driver calls window.stage on the stage page between Playwright actions: stage("caption", html) swaps the lower-third (slide out/in), stage("card", html) shows a full-screen title card, stage("hideCard") fades it out. Pacing is plain sleep(ms) between beats.
  • Caption vocabulary: <span class="badge">NEW</span> amber pill, <span class="hl"> amber highlight, <span class="dim"> muted. A NEW badge is a claim about this release — drop or move badges as features age.
  • Card vocabulary: badge, h1 (+ span.ver for the amber version), sub, cmds/cmd (+ span.p for the prompt $), foot.
  • Interact with the viewer through page.frameLocator("#app"). Useful selectors: aside .sess-title (session rows), .sidebar-toggle (collapse/expand rail), .card:not(#whatsNew) (post cards — the update-notes card is also a .card), button.act.comment (the icon-only trigger that unfolds the composer; it has no text, so getByText won't find it), then .composer input.
  • Publish content via the HTTP API while recording: POST /api/sessions, POST /api/posts ({session, title, surfaces: [{kind, …}]}), PUT /api/posts/:id to revise (bumps the version pill live), and POST /api/comments ({surface: postId, author, text}) for agent replies. Seed background sessions before opening the page; save the live publishes for on-camera.
  • Target pacing: money shots hold 2.5–4s after content settles, transitions ~1s, typing at pressSequentially(..., { delay: 34 }). Intro card ~3s, outro ~4s.

Environment gotchas (each cost real debugging time)

  • The viewer refuses to be framed. Since 0.12.0 the viewer document sends Content-Security-Policy: frame-ancestors 'self', so the file:// stage's iframe would be blocked. record.mjs strips that header with a Playwright route on exactly the viewer document URL. Never widen the route pattern: intercepting /api/events buffers the SSE stream forever and live updates stop.
  • The title-card overlay must keep pointer-events: none. Playwright's hit-target check runs in the top frame; an overlay that intercepts clicks aimed into the app iframe times every action out — even actions "behind" an intro card.
  • Wait for iframes after a session switch. Opening a session re-renders each sandboxed surface from /s/:id; cut away too early and the last shot shows empty card shells. waitFor a .card iframe and hold ~2–3s before the outro (this is also why "publish on camera" shots need their settle time).
  • Park the mouse after sidebar clicks (page.mouse.move(...) toward the content) or the hovered session row shows its delete "×" in every following frame.
  • Sandbox Chromium/driver mismatch. In the Anthropic sandbox the pinned @playwright/test may expect a newer browser build than /opt/pw-browsers provides; record.mjs falls back to /opt/pw-browsers/chromium (override with CHROMIUM_PATH). Driving a slightly older Chromium works.
  • mp4 needs a real ffmpeg with libx264 (apt-get install ffmpeg; brew install ffmpeg on macOS) — Playwright's bundled ffmpeg records the raw webm (VP8) but cannot produce h264. Verify with ffmpeg -encoders | grep -E 'libx264|libvpx-vp9'.
  • Give .video-work/ its own package.json before npm i or the fonts land in the repo's package.json (revert with git checkout package.json package-lock.json if that happens).
  • The recorder spawns server/index.ts with PORT=0 and SIDESHOW_DB in the work dir — every run is a fresh workspace, nothing touches ~/.sideshow. The version being recorded matches latest on npm, so the #whatsNew update card stays away on its own; scope card selectors with :not(#whatsNew) anyway.
  • A failed run can orphan the spawned server; kill it before rerunning (pkill -f "[s]erver/index.ts").

Content accuracy

  • Verify install commands against reality: npm view sideshow dist-tags. The outro card's commands are npm i -g sideshow + sideshow serve --open (or npx sideshow serve --open) — check they still match the README.
  • Perf/number claims must come from the changelog entry, phrased no stronger ("up to 95% lighter" for the 0.13.0 hydrate change, not "95% faster").
  • The window chrome's URL pill shows the real server host:port — decorative but it must not lie; record.mjs fills it from the actual base URL.
  • Demo content is bin/demoData.js (the sideshow demo sessions) — label anything invented beyond it honestly, and keep agent names real (claude-code, pi).
  • The video is silent — never imply audio in the video or announcement copy.

Verification and delivery

  • After encoding, extract spot frames at each scene boundary and mid-scene: ffmpeg -y -ss <t> -i sideshow-X.Y.Z.mp4 -frames:v 1 check.png (Read renders PNGs). Look specifically for: blank surface iframes (cut too early), hover artifacts in the sidebar, captions overlapping scene changes, and the intro/outro cards fully faded. Check duration with ffprobe -show_entries format=duration.
  • Outputs land in .video-work/ (gitignored — never commit videos or the raw recording). Send both files to the user (mp4: social/Slack; webm: web embeds), report duration and sizes, and flag if the mp4 exceeds ~10 MB (Slack) or ~15 MB (X). Copy elsewhere only if the user names a destination.

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.