Communitygithub.com

explainer

Make a short explainer video (60 s by default) from real material - screenshots of web pages or the screen, screen recordings, code and diagrams - turned into animated HyperFrames scenes with zooms, highlights, captions and narration. Works without any character; if the user configured one, it can open and close the video. Use when someone has a technical doubt a video would answer better than text ("how does X work", "walk me through the Y flow"), or asks for an explainer, walkthrough or demo video. Not for short talking clips (that is talking-clip).

What is explainer?

explainer is a Claude Code agent skill that make a short explainer video (60 s by default) from real material - screenshots of web pages or the screen, screen recordings, code and diagrams - turned into animated HyperFrames scenes with zooms, highlights, captions and narration. Works without any character; if the user configured one, it can open and close the video. Use when someone has a technical doubt a video would answer better than text ("how does X work", "walk me through the Y flow"), or asks for an explainer, walkthrough or demo video. Not for short talking clips (that is talking-clip).

Works with✓Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/NightZpy/talking-character-skill/tree/HEAD/skills/explainer

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does explainer do?

A spec file lists the scenes; the scripts capture the material, voice the narration, build one HyperFrames sub-composition per scene, and verify everything before it ships.

1. understand   read the code / docs / app the doubt is about
2. capture      scripts/capture.py      screenshots, element boxes, recordings, redaction
3. spec         you write explainer.json (scenes + narration + claims with sources)
4. verify facts scripts/verify.py facts (gate: nothing is voiced until it passes)
5. build        scripts/build_explainer.py (voice, captions, scenes; no character by default)
6. verify       scripts/verify.py all   (assets, build, render, audio) - loop until clean
7. render       scripts/render.py

Paths are relative to this package's root: the folder that holds .claude-plugin/, two levels above this file (resolve symlinks first). Requires the public HyperFrames skills (hyperframes, hyperframes-cli; hyperframes-registry and media-use for extras). Read hyperframes once before editing generated compositions by hand.

0. Preflight (always first)

Run python3 scripts/setup.py doctor (add --json to parse it). It lists every dependency, what it is for, and the exact install command for this machine; it exits 1 when a required item is missing.

  • Required missing (ffmpeg, Node.js 18+, the HyperFrames skills, and the ElevenLabs key or say when that voice is configured): tell the user in one line what each one is for and propose the printed command. Run it only after the user says yes. Never type or ask for an API key yourself: tell the user to export ELEVENLABS_API_KEY in their shell.
  • Optional missing: offer them once and say what each unlocks. Playwright gives web captures with element zoom boxes and full-page shots, tesseract (OCR) gives the secrets scan on screenshots, and ASR (mlx-whisper / openai-whisper) gives the audio check and exact word timings. Skip them if the user declines; the matching checks then become manual review steps.
  • HyperFrames skills (hyperframes, hyperframes-cli, hyperframes-registry, media-use): if missing, recommend npx hyperframes skills. Read hyperframes (and hyperframes-cli for render problems) before building or editing any composition.

Setup (first run, or when the user wants to change something)

python3 scripts/setup.py show prints the active config. If there is none, interview the user (one short question at a time, offer the default) and write it:

QuestionFlagOptions
Which parts?--featuresexplainer alone (no character file needed), or character,explainer to make a presenter possible
Narration language--languageISO code (en, es, ...): picks a clear say voice and tells the ASR what to expect
Narration voice--narration-voicevoice (the configured provider), say (free, macOS), none (captions only)
Voice provider--voiceelevenlabs (their ELEVENLABS_API_KEY from env + --voice-id), say, none
Credit guards--max-chars, --max-seconds, --daily-credit-capthe user's numbers
Render--renderlocal, cloud, preview
Size--size1080x1920 (default), 1920x1080, 1080x1080
python3 scripts/setup.py init --features explainer --voice say --render local --yes

init runs the doctor first and offers the same installs. If a config exists it asks before overwriting (pass --force when running non-interactively). setup.py voices --lang <code> lists macOS voices for a language and the user's ElevenLabs voices; --say-voice "<name>" picks one. Never ask for, print or write API keys.

1. Understand, then script

  • Get the facts from the source first: read the code, PR, doc or app. A wrong explainer is worse than none. Show the shape of the thing before the details, walk one real case through it (actual names, actual values), and keep each scene to a single idea.
  • Shape (≤ styles.explainer.max_seconds): 3-5 scenes of about 6-12 s each and a closing title. TTS reads about 2.4 words per second: keep a scene's narration under ~25 words.

Choose a style for this video

The package ships only neutral defaults. Pick a style per video from the topic, the audience and the user's brand or preferences, and ask when it matters (a brand, a public channel, a series). Do not repeat the previous video's look by habit. Put it in the spec's style block:

KeyValues
palettebackground, panel, ink, muted, accent, highlight (CSS colours; keep text contrast ≥ 4.5:1)
typographyfont, mono (HyperFrames bundled fonts), title_scale (0.6-1.6)
layoutalign (left, center), radius (0-60), background_style (solid, gradient)
motionmotion (calm, normal, lively): durations and easing of every move
captionscaption_style (box, outline, plain, none), caption_position (bottom, top)

A brand kit in the config (same keys) overrides your choice key by key. The presenter's set follows the video's background unless its block has its own style (see talking-clip).

2. Capture the material

python3 scripts/capture.py url http://localhost:3000/login --name login
python3 scripts/capture.py url http://localhost:3000/login --name login --box "#submit"   # needs Playwright
python3 scripts/capture.py screen --name settings --interactive
python3 scripts/capture.py record --name signup --seconds 12          # macOS
python3 scripts/capture.py add --name diagram --file ./docs/arch.png
python3 scripts/capture.py redact --name login --box 820,410,360,48   # or --blur
python3 scripts/capture.py list
  • url uses Playwright when installed (required for --box and --full-page), else headless Chrome. Without Playwright, give focus boxes as pixel rects [x, y, w, h] read from the PNG (twice the CSS pixels at the default scale). If Playwright lives in a virtualenv, run the scripts with that interpreter (.venv/bin/python scripts/capture.py ...). --box records an element's box in image pixels so a scene can zoom straight to it. Default --scale 2 keeps text sharp when zoomed.
  • Capture the smallest region that tells the story; a full desktop shrunk into a phone frame is unreadable. Use focus boxes to zoom.
  • A whole website as a project instead of single shots: npx hyperframes capture <url> (hyperframes-cli).

3. Write the spec

examples/explainer/explainer.json is a complete, working example. Put the spec at the root of the material: code files and captures it references must be inside the spec's folder. Scene types:

typeneedswhat it shows
screencapture, optional focus: [{"box": "#sel" or [x,y,w,h], "label": "...", "at": s}]the screenshot, then a camera move to each box with a highlight and a label
recordingcapture (a video), optional focusthe screen recording, muted, same camera and labels
codefile, lines: "a-b" (≤ 24, lines ≤ ~49 chars in vertical), highlight: [{"lines": [a, b], "at": s}]the code on a card, lines appearing, bands on the key lines
diagramnodes: [{"id","label","sub"?,"highlight"?}], edges: [[a, b]], optional flow: [ids]boxes and arrows building up, a token travelling along flow
titletext, optional sub, dura closing or section card

Motion, on any scene (optional; colours and timing come from the style, so vary them per video like the rest of the look):

KeyWhat
callouts: [{"type": "circle" or "arrow", "box": [x,y,w,h] or "#sel", "at": s, "note": "..."}]hand-drawn loop or arrow that draws on; image pixels on screen/recording scenes, frame pixels elsewhere
kinetic: [{"text", "at", "dur", "y"?, "from"?}]words slamming in for emphasis; use sparingly (one or two per video)
counter: {"to", "from"?, "at", "dur", "prefix"?, "suffix"?, "label"?}a count-up that lands on the exact value
top-level transition: "wipe" or "fade"a transition at every cut (default none)

They follow the registry items count-up, caption-kinetic-slam, hw-callout-circle and hw-arrow (see /hyperframes-registry). style.hand_font: "Caveat" fetches that handwriting font with npx hyperframes add. Do not make every video use every feature; pick what the story needs.

Every scene with narration must carry claims: each technical statement it makes, with a source (path:lines relative to the spec, capture:<name>, https://..., doc:<name>) and status: "supported" once you checked it against that source. "claims": [] means the narration makes no technical claim. Unsupported claims are fixed or cut, never voiced.

No character by default. An explainer is narration, captions and visuals. Add the character as presenter only when the user asks for it, or when you judge it adds value (a series with a host, a friendly onboarding) and you say so to the user with the reason. Then add a presenter block (intro / outro, each {"text", "plan"?, "mood"?, "style"?, "claims"}; plans follow the talking-clip format) and build with --presenter. It also needs features.character. Presenter scenes get captions too (unless the spec sets "captions": false). examples/explainer/explainer-with-presenter.json is the example.

4-5. Facts gate, then build

python3 scripts/verify.py facts --spec explainer.json
python3 scripts/build_explainer.py --spec explainer.json --project out/explainer --estimate
python3 scripts/build_explainer.py --spec explainer.json --project out/explainer [--confirm] [--presenter]

--estimate prints length and ElevenLabs credits; tell the user before spending, then build with --confirm. The builder also runs the facts gate and stops if it fails. Captions show the script's own words (case, punctuation, numerals) timed from ElevenLabs' alignment, ASR, or an estimate.

6. Verify (required loop)

python3 scripts/render.py out/explainer --out out/explainer.mp4 --quality draft
python3 scripts/verify.py all --project out/explainer --spec explainer.json --video out/explainer.mp4
StagePasses whenIf it fails
factsevery narrated claim has an existing source and status supportedcheck the source; fix or cut the claim
assetscaptures and code are legible at the output size; OCR (tesseract) / text scan finds no emails, keys, tokens or card numbersadd focus boxes or recapture smaller; capture.py redact; replace secrets in code with placeholders
buildnpx hyperframes check --json has no errors or warnings (except verify.ignore_rules)fix the spec or the generated composition
renderyou looked at the contact sheet (start, every scene change, mid-scene, end): no overflow, overlap, cut-off or unreadable text; visuals match the narrationfix, rebuild, re-render
audioASR of the rendered audio matches the script (verify.min_asr_similarity) and the duration is within the limitregenerate the voice or shorten

How to drive the loop:

  1. Run verify.py all. Each run is one iteration (counted in <project>/.verify/state.json).
  2. render always comes back as review first: open the contact sheets it lists, check every frame, then record what you saw: python3 scripts/verify.py mark render pass --project out/explainer --note "<what you checked>" (or fail, then fix). The mark is tied to those exact files; any rebuild invalidates it.
  3. Without OCR or ASR installed, assets / audio become review too: check by eye or ear and say so in the report.
  4. Fix what failed, rebuild or re-render, and run verify.py all again. Exit 0 = ship.
  5. When the count reaches verify.max_iterations (default 3) it exits 2: stop and tell the user what still fails. Do not ship silently. Delete .verify/state.json to start a fresh count after a major change.

VERIFY.md shows numbers: OCR images scanned and hits, ASR similarity with words heard and expected, duration against the limit. Quote them when you report. Scenes are lengthened automatically so the last caption stays readable; if a line_unread warning remains, give that scene more min_dur.

Keep the user's normal HOME when running the scripts: a temporary HOME makes npx, Playwright and whisper download everything again, and breaks gh/npx auth.

Audio mismatches on numerals, acronyms or foreign words: set language in the config and write those words in the narration the way they should sound ("fifteen", "A P I"). VERIFY.md in the project is the checklist report; include its summary when you hand the video over.

7. Render

python3 scripts/render.py out/explainer --out out/explainer.mp4 uses render.backend (local, cloud or preview); render.max_mb re-encodes to fit an upload limit. Never commit mp4 or wav files.

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Related Skills