Per-snippet flow โ€” record, manifest, storyboard review, concat, publish, cleanup

This is the execution reference for a polished demo. It assumes you already have the script approved (script-and-tts.md) and you know the capture mechanics (recording-mechanics.md).

The flow is:

  1. Verify your setup (Step 3 below โ€” ralph-loop yourself before recording)
  2. Record one section at a time, each as its own clip
  3. manifest add each clip with an INTENT description
  4. ๐Ÿ›‘ MANDATORY storyboard review with the user
  5. Surgical re-shoots based on feedback
  6. Concat โ†’ hero โ†’ wiki upload
  7. ๐Ÿงน MANDATORY workspace restore

Parent skill: SKILL.md. Read the "Ten failure modes" first โ€” modes 1, 2, 5, 6, 7, 10 are all about exactly this flow.

Quick recording (live narration, no per-snippet flow)

If the user picked "quick recording" in Step 1 of the parent skill, this whole file does not apply. Use:

adom-cli hydrogen recording start --reason "Descriptive reason here"
# User narrates and demonstrates live
adom-cli hydrogen recording stop   # saves to ~/project/recordings/

Done. Upload to wiki via adom-wiki asset upload. Skip the rest of this file.

๐ŸŽฌ Polished recording โ€” record sections INDIVIDUALLY (non-negotiable)

The rule: a polished demo is a sequence of separately-recorded clips, one per section / feature, each with its own TTS narration. adom-video-post concat stitches them together at the end. Do NOT record one long take covering every feature. Reasons:

  • A single long recording turns every mistake into a re-shoot of everything. One-take demos always have at least one mumbled line or a mis-click and then you re-record 4 minutes to fix a 5-second flub.
  • Per-clip TTS means Andrew-neural (or whatever voice) narrates each section cleanly. A single long TTS over a mixed recording loses the intentional pauses between features.
  • Hero image selection is trivial when each section is its own file โ€” just pick the best frame from clip #1 or #2.
  • Re-shoots are surgical: if the Measure tool scene is bad, re-record measure.webm, update the manifest entry, adom-video-post concat again. The other 12 clips are untouched.

Why the storyboard gate exists (read this before skipping it)

AI-made demos fail in specific, localized ways: "clip 5 measured the wrong pads," "clip 8 never clicked anything," "clip 11 walkthrough didn't advance past step 1." The human reviewer catches these instantly when clips are numbered + described + individually playable. On a 3โ€“5 minute uninterrupted video they can't โ€” they'd have to scrub to the minute:second timestamp and guess which segment you meant. Skipping storyboard forces the user to do something that's genuinely hard, and turns the feedback loop from "clip 5 is broken" (precise) into "something's wrong somewhere" (useless).

Every manifest add carries a --description so the user can read your INTENT per clip before hitting play. If your intent is wrong (e.g. you thought "measure tool = some clicks" instead of "measure tool = commit three pad-to-pad distances showing HUD readouts"), they can catch the intent bug without even watching the clip.

Step 3: Verify your setup (ralph loop yourself)

Before hitting record, screenshot the workspace and LOOK at it. Check:

  • Are the right panels visible and loaded? (not empty states, loading spinners, dead webviews, or cloud icons)
  • Is the content you're about to demo actually rendering?
  • Is the workspace layout clean โ€” no overlapping panels, no stale tabs?
  • Do all the tools/CLIs you need actually work? (test a command first)

If anything looks wrong, fix it before recording. Do NOT start recording and hope for the best. This is the #1 cause of wasted takes.

Common setup pitfalls:

  • Webview tabs showing blank/cloud icon โ†’ navigate with full DNS URL, not relative /proxy/ path
  • Shotlog server has stale VSCODE_IPC_HOOK_CLI โ†’ restart shotlog so it picks up the current socket
  • adom-vscode not installed โ†’ gh release download from adom-inc/adom-vscode
  • Panel not loading โ†’ check the server is running (health command)

๐ŸŽž Keep motion on screen โ€” no static panels

Any demo scene that lingers on a table, list, or panel needs visible action happening inside it, not a held still. Examples:

  • BOM / Parts list โ€” click through several rows, not just one. Each click swaps the detail view on the right and makes the scene feel alive. 3-4 part clicks over 15 seconds beats one click and dead air.
  • Components HUD โ€” toggle a couple of groups or individual chips on/off rather than staring at the list.
  • Schematic / PCB tabs โ€” pan or zoom so the artwork isn't frozen.
  • Walkthrough / tour โ€” let it auto-advance; don't pause on a step.

A frozen panel reads as "this tool is boring." Action โ€” even small clicks that add up to a few state changes โ€” reads as "this tool is responsive and worth learning." Every scene longer than 8 seconds needs at least one visible interaction.

๐Ÿ“ Frame the split at 30% AI / 70% feature โ€” don't maximize the feature pane

When recording adom-* demos the VS Code pane (showing Claude Code live in the chat) MUST stay meaningfully visible. The canonical ratio is 0.30 โ€” 30% of the width is VS Code / Claude chugging, 70% is the feature (adom-tsci, KiCad, Fusion, etc.). That's the Adom pitch: AI-driven EDA. The viewer needs to see Claude actually doing the thing they're watching in the feature pane. A full-width feature pane with no chat looks like any other tool. A split where Claude is chugging on the left and the feature is responding live on the right is what makes Adom Adom.

# Canonical: 30% AI / 70% feature
adom-cli hydrogen workspace resize --split-id "$SPLIT_ID" --ratio 0.30

# Wrong: feature pane maximized, AI hidden
adom-cli hydrogen workspace resize --split-id "$SPLIT_ID" --ratio 0.01
# Wrong: too much AI, feature squeezed
adom-cli hydrogen workspace resize --split-id "$SPLIT_ID" --ratio 0.50

Exception: if the demo is genuinely AI-free (a static pitch deck, a hero shot for thumbnails, a no-interaction explainer), maximizing the feature pane is fine. Default is 0.30 until you have a reason otherwise.

Step 4: Record section by section

For a polished / feature-tour demo, use the per-section flow. One clip per section, TTS per section, aggregated at the end.

๐Ÿ›‘ Screenshot-verify the target tab BEFORE recording start โ€” every clip, no exceptions

The rule: between opening/activating a tab and pressing recording start, take a screenshot of the tab and actually LOOK at it. If what you see isn't what you expected to record, you're about to capture that bad state for the entire clip duration โ€” and you won't notice until post-mux storyboard review (best case) or until the user plays the final and asks "why is every example black?" (worst case, cost = full re-shoot).

Why this breaks: adom-cli hydrogen workspace active-tab can silently miss. webview open-or-refresh returns 204 before the page has loaded its WASM / Babylon / whatever. A 3D viewer may need 5-15 seconds after --url lands before the board mesh is actually visible. Every second of recording start before the scene is visually ready = one second of black frames locked into the muxed clip.

The check, one-liner before each recording start:

# Activate, then SLEEP + screenshot + visual verify before recording
adom-cli hydrogen workspace active-tab --name "<tab>"
sleep 2
adom-cli hydrogen screenshot panel --name "<tab>" --reason "pre-record verify for <clip-id>"
# Read the saved file. If it's not showing what you intended โ€” DO NOT RECORD YET.
# Poll-and-retry, longer sleep, re-navigate, etc.

In a driver script the pattern is:

def wait_for_ready(tab_name, check_substring=None, timeout=15):
    for i in range(timeout):
        img = take_panel_screenshot(tab_name)
        if looks_ready(img, check_substring):
            return True
        time.sleep(1)
    raise RuntimeError(f'tab {tab_name} never rendered')

Where looks_ready() does one or more of:

  • Size/histogram check โ€” a black frame is low-variance; a board has mid-tones
  • OCR substring โ€” caption or chip label visible
  • DOM probe via adom-tsci eval โ€” window.viewer && viewer.getScene().meshes.length > 10

Cost of skipping this rule: past incident โ€” shot 36 scenes of a demo, every one of them a blank webview because active-tab missed. Full re-shoot. Same has happened on 18 of 20 scenes in the 1.3.8 tour. Don't be the next case study.

The record loop

MANIFEST=/tmp/<name>-manifest.json
CLIPS=/tmp/<name>-clips/
mkdir -p $CLIPS
adom-video-post manifest init --output $MANIFEST

for each section in script:
  # 1. Show caption (viewer-side context)
  adom-cli hydrogen caption show "<section title>" -d 0     # leave up for whole clip
  # 2. Activate the target tab + any CLI pre-positioning
  adom-cli hydrogen workspace active-tab --name "<feature tab>"
  adom-tsci view isometric --port <port>                    # example
  # 3. ๐Ÿ›‘ SCREENSHOT-VERIFY โ€” skip this and you're shooting blanks (see above)
  adom-cli hydrogen screenshot panel --name "<feature tab>" \
    --reason "pre-record verify <clip-id>"
  # Read the file. Confirm the board is visible. Retry if not.
  # 4. Start recording
  adom-cli hydrogen recording start --share tab --mic false --countdown 0 \
    --reason "<section title> โ€” <what you'll see>"
  # 5. Drive UI silently โ€” 8-25 seconds of focused action
  #    adom-tsci view top / hover / click / etc
  # 6. Stop
  adom-cli hydrogen recording stop
  # last recording is saved to ~/project/recordings/<timestamp>.webm
  CLIP=$(ls -t ~/project/recordings/*.webm | head -1)
  mv "$CLIP" "$CLIPS/<id>.webm"
  # 5. Generate TTS narration
  edge-tts --voice en-US-AndrewNeural \
    --text "<narration text for this section>" \
    --write-media "$CLIPS/<id>.mp3"
  # 6. Mux audio onto the video (replace the silent track)
  ffmpeg -y -i "$CLIPS/<id>.webm" -i "$CLIPS/<id>.mp3" \
    -map 0:v -map 1:a -c:v copy -c:a libopus -shortest \
    "$CLIPS/<id>-narrated.webm"
  # 7. Register in manifest โ€” --description is MANDATORY, see below
  adom-video-post manifest add \
    --id "<id>" --title "<short label>" \
    --description "<full intent: what this clip shows, which project, \
                   which features, what the viewer should notice>" \
    --raw "$CLIPS/<id>-narrated.webm" \
    $MANIFEST
  # 8. Hide caption before the next section
  adom-cli hydrogen caption hide

๐Ÿ“ --description on every manifest add โ€” not optional

Every clip registered in the manifest MUST carry a --description that says what you INTENDED the clip to show. Not just the feature name: the project, the interactions, the expected visible payoff. The storyboard UI (Step 5 below) renders this under each clip so the user can tell "did Claude even understand what this clip was supposed to do?" before watching it.

Without per-clip descriptions, the user watches a 3-5 minute video blind and has to guess which segment is broken. With descriptions, they look at clip N's intent, watch its 15-second snippet, and tell you exactly "clip 5 measured the wrong pads" or "clip 8 never clicked anything." That feedback loop is the whole reason this skill exists.

Rule of thumb: if a teammate reading just the description couldn't write the clip's ffmpeg filter / interaction script themselves, the description is too vague. Examples of GOOD descriptions:

  • โœ… "BME680 cinematic slow orbit for 15s. Camera starts iso, completes one full rotation. No HUDs, no tool activation โ€” just the board."
  • โœ… "iCE40-USB Measure: commit MP1โ†’MP3 (diagonal 181 mm), clear, commit U1โ†’J1 (chip to USB-C connector, ~50 mm), clear, commit MC_USB_DPโ†’DM. Each measurement's ฮ”X/ฮ”Y/distance HUD stays visible for 5s."
  • โŒ "show measure tool"
  • โŒ "inspect demo"

Always use a descriptive --reason on recording start. The user sees it in the approval dialog. Bad: "Demo recording". Good: "Recording adom-tsci Inspect tool โ€” hover pads, show net + JLCPCB part card."

TTS voice: en-US-AndrewNeural is the default. Alternatives when the demo needs variety: en-US-AriaNeural (polished female), en-US-GuyNeural (warm neutral male). Pick ONE voice for a whole demo โ€” switching voices mid-demo is jarring.

Step 5: ๐Ÿ›‘ MANDATORY โ€” open adom-video-post storyboard and let the user review every clip

This step is not optional. The whole per-section recording flow exists so the user can audit each clip individually, because AI-driven demos routinely screw up details a full-video watch can't pinpoint. Skipping this step โ€” going straight from manifest โ†’ concat โ†’ wiki upload โ€” destroys the user's ability to tell you "clip 5 measured the wrong thing" or "clip 8 never clicked anything." Don't do it.

# Opens a Hydrogen webview listing every clip in the manifest with its
# title, description, and a player. The user can play each one and
# tell you which clips are bad without watching the whole video.
adom-video-post storyboard $MANIFEST \
  --tab-name 'adom-video-post: <name> review' \
  --port 8797

Then:

  1. Actively point the user at the storyboard tab. Activate it, screenshot to confirm it rendered, tell the user the tab name to look at. "The storyboard is open in tab adom-video-post: โ€ฆ, 13 clips, take a look and tell me which ones are wrong."
  2. Wait for user feedback. The user will tell you "clip 5 needs more parts clicked," "clip 11 walkthrough isn't advancing," etc. โ€” or just "looks good."
  3. Re-shoot surgically. adom-video-post manifest remove --id <id>, re-record that one clip, manifest add with updated description, point the user back at storyboard. Repeat until they approve.
  4. Only then proceed to Step 6 (concat + publish).

Never concatenate or upload a demo the user hasn't seen clip-by-clip.

Background-mux while the user reviews

The concat step is slow (60โ€“90 s for a 6-clip demo). The user reviewing snippets in storyboard does NOT need it done. These should run in parallel:

# Kick concat as a background job the moment manifest is final.
( ffmpeg -y -f concat -safe 0 -i $LIST -c copy \
    ~/project/recordings/<name>-final.webm \
  && echo "concat DONE" ) &
CONCAT_PID=$!

# In parallel, open the storyboard for review.
adom-video-post storyboard $MANIFEST --tab-name 'adom-video-post: <name> review' --port 8797

# When user approves: concat is already done. Upload.
# When user flags a re-shoot: kill the in-flight concat, re-shoot the clip,
# update manifest, restart concat.
kill $CONCAT_PID 2>/dev/null

Treating concat as a finish-line task instead of a parallel one wastes 60โ€“90 s ร— number-of-revisions of user time.

Step 6: Concat + publish โ€” ONLY after storyboard approval

# Option A: `adom-video-post concat` (drops audio today โ€” KNOWN BUG, use B)
# Option B: ffmpeg concat demuxer (preserves all streams)
LIST=$(mktemp)
for c in $CLIPS/*-narrated.webm; do echo "file '$c'" >> $LIST; done
ffmpeg -y -f concat -safe 0 -i $LIST -c copy \
  ~/project/recordings/<name>-final.webm
rm $LIST

Verify audio is present (voiceover is the whole point) โ€” an all-video, no-audio output is a bug to catch here, not after upload:

ffprobe -v error -show_streams <name>-final.webm | grep codec_type
# Must show both `video` and `audio`.

Then publish (Step 7). If any section is bad, adom-video-post manifest remove --id <id>, re-record that ONE clip, re-register with updated description, reopen storyboard for another review pass, then re-concat. The surgical re-shoot is the whole point.

Step 6a: ๐Ÿ›‘ Show the final in adom-video BEFORE wiki upload

Before any adom-wiki asset upload, the final webm goes through adom-video so the user can scrub it in pup. Do NOT report final.webm produced at /tmp/... and stop โ€” that leaves the user to find the file, copy it locally, and open it in a random player. The result is review friction and missed bugs.

The right shape is: produce the webm, drop it in /tmp/videolib/, run adom-video play, navigate the user's pup tab to the proxy URL. Two-line completion:

mkdir -p /tmp/videolib && cp ~/project/recordings/<name>-final.webm /tmp/videolib/
adom-video play /tmp/videolib/<name>-final.webm    # prints "OK: webview url: ..."

The CLI also exposes seek, pause, set-rate, extract-frame, trim โ€” meaning if the user spots a bad section, adom-video trim --in <t> --out <t> cuts it without re-encoding, no need to re-shoot. That's why adom-video is the canonical playback surface and why python3 -m http.server + raw file URL is wrong: you lose every one of those CLI hooks.

If adom-video isn't installed, install it from the wiki page first โ€” don't fall back to a generic player. Memory rule: feedback_video_playback_uses_adom_video.md.

Step 6b: Hero image + supplementary screenshots

Pick one frame from the final video as the wiki hero. Usually the frame where the marquee feature is clearest (e.g. the Inspect card hovering a chip). Then pull 2-3 more for the README / wiki body.

ffmpeg -y -ss <t> -i final.webm -frames:v 1 hero.png
shotlog resize hero.png     # keeps wiki pages lean

Step 7: Publish to wiki โ€” video, hero, screenshots, AND the demo script itself

# Final video
adom-wiki asset upload apps/<page> --asset-type video \
  --file <name>-final.webm \
  --caption "<one-line summary โ€” what the viewer learns>"

# Hero image
adom-wiki asset upload apps/<page> --asset-type hero \
  --file hero.png \
  --caption "<the marquee feature in one phrase>"

# Supplementary section screenshots
for s in hero section1 section2 ...; do
  adom-wiki asset upload apps/<page> --asset-type screenshot \
    --file $s.png --caption "<what this shot shows>"
done

# โญ Demo script itself โ€” upload as a "reproducible recipe" asset
# so another Adom user (or another Claude thread) can find + replay
# it without spelunking the source repo.
adom-wiki asset upload apps/<page> --asset-type demo-script \
  --file <repo>/demo/<name>-demo-script.md \
  --caption "Reproducible script for this demo โ€” scenes, narration, TTS config, reproduction commands"

Commit the script to the repo in the same PR as the app changes

The demo script is code for the purposes of review and diff. When you release a new version of the app, the demo script gets bumped too (new features โ†’ new scenes โ†’ new narration). Rule of thumb: the version at the top of the demo script and the version of the app shipping in the PR must match. A PR that bumps the app without bumping the demo script is incomplete.

git add <repo>/demo/<name>-demo-script.md <repo>/demo/record.py <repo>/demo/manifest.json
git commit -m "demo-script: update for <version> โ€” <what changed>"

Why the script is a first-class asset

  • Discoverability. Another Adom user browsing the wiki app page sees the video and the script. They click the script and learn: "oh, here's exactly how this was demonstrated, and I can re-render it for my fork."
  • AI-reproducibility. A fresh Claude thread pointed at the wiki page can pull the script and re-record the demo against a new version of the app without hand-holding. That's the payoff of putting the narration + TTS config + reproduction block in the file.
  • Review + tweak. Someone spots a typo in scene 7's narration? They edit the script file, open a PR, CI re-renders the affected clip, hero regenerates. No mystery about what changed.

The hero image is what shows up on the wiki landing page, in link-preview cards, and as the social-share image โ€” pick it deliberately. A board on a white background beats a dark canvas full of toolbar buttons. A card / panel that's clearly adom-tsci beats a generic 3D render.

Step 8: ๐Ÿงน MANDATORY โ€” restore the user's workspace before you stop

Do not leave the user's Hydrogen workspace cluttered with demo artifacts. The recording flow adds tabs, swings split ratios to 20/80, activates panels, and spawns background servers (storyboard, dev-harness, animation-server, whatever). None of that should persist past "demo published." Leaving the workspace in its mid-recording state is the same bug as AI panels parking themselves over VS Code โ€” the user has to manually drag everything back every single time.

What to restore

Before recording start, capture three things:

  1. Split ratios. adom-cli hydrogen workspace get โ†’ walk the tree โ†’ note every split's ratio. Save them to a temp file (you'll need them for the restore).
  2. Pre-existing tabs. adom-cli hydrogen workspace tabs โ†’ record { tabId, name } for every tab that existed before you started. Any tab that DIDN'T exist before is yours to remove at the end.
  3. The focused / active tab per pane. So you don't leave the user staring at your storyboard tab after the demo ends.

After adom-wiki asset upload finishes, tear down in reverse:

# 1. Kill background servers you spawned.
pkill -f "adom-video-post storyboard"
# (add any app-specific dev servers you started, e.g. tsci dev on 8850)

# 2. Remove every tab you added during the demo. Compare the current
#    tab list against the pre-demo snapshot; the delta is yours.
for name in "<tab you added>" "<adom-video-post: ... review>"; do
  adom-cli hydrogen workspace remove-tab --name "$name"
done

# 3. Restore every split's ratio from the pre-demo snapshot.
adom-cli hydrogen workspace resize --split-id "<id>" --ratio <original>

# 4. Re-activate the tab the user was looking at before you started.
adom-cli hydrogen workspace active-tab --name "<pre-demo active tab>"

# 5. Clean up any scratch files you created in the project tree
#    (temp `.kicad_pcb` copies, /tmp/demo-clips/ if you want โ€” though
#    leaving clips in /tmp is generally fine since /tmp is scoped;
#    the hard rule is the user's visible project tree).
rm -f <any temp files you copied into project dirs>

Verification

End the demo with a workspace get screenshot to confirm the tree matches the pre-demo snapshot (same split ratios, same tab count, same focused tab). If it doesn't match, keep cleaning until it does.

Why this matters

A user asking for a "demo" is asking for a deliverable (video + wiki page). They are NOT asking to have their workspace rearranged for half an hour. The mid-recording 20/80 split + temporary tabs are part of the recording apparatus, not part of the deliverable. Treat them like scaffolding โ€” build with them, demolish them when the video is up.

If a future demo skill (like the adom-tsci skill, or an adom-chipfit demo) inherits this doctrine, it should do the same: snapshot before record, restore after publish. Record a follow-up feedback memory entry if you discover an artifact type this skill didn't cover (e.g. "adom-tsci demo left tsci dev running on :8850" โ†’ add a pkill line to the tool-specific demo flow).

Legacy one-take + speedup path (not preferred)

The older flow recorded a single long take then sped up slow parts with adom-video-post process --markers. It still works and is the right call for live narration demos where timing is inseparable from speech โ€” but for scripted feature tours, the per-section path above beats it on every axis: easier re-shoots, cleaner TTS, better hero selection, no "narrate fast here, slow there" timing puzzle.

If you do need the legacy path:

adom-video-post inspect                      # show speedup summary
adom-video-post process --input <file>.webm --markers /tmp/adom-video-post-markers.jsonl
adom-video-post voiceover --input <file>-fast.webm   # live-narration UI
adom-wiki asset upload apps/<page> --asset-type video --file <final>.webm \
  --caption "..."

See also

  • SKILL.md โ€” parent: orchestration, the ten failure modes, the "real demo" 10-step shape
  • recording-mechanics.md โ€” capture path, surfaces, frame-rate sanity, NEVER stitch screenshots
  • script-and-tts.md โ€” script template, narration phonetics, captions