explainer-video
Skill11 starsChanged 3 months agoMITView on GitHub
Produce a narrated, animated explainer video (YouTube-quality, 1080p) from a topic, the HTML way — manuscript → local TTS speech → seekable-HTML graphics → combined mp4. Use when asked to "make an explainer/demo video", "animate this concept", "turn X into a narrated video", or to add a scene to this repo. Reproducible on x86_64-linux (Nix flake + virtual-clock frame capture, no cloud/API keys).
19 other projects use a version of this.
Adopted by
Most recently taken up by
- manoletre/explainer-videotheir own version, first seen Nov 8, 2026
- JacobStephens2/skillstheir own version, first seen Nov 1, 2026
- charlie947/reel-editing-skillstheir own version, first seen Nov 1, 2026
- konradre/video-production-skillstheir own version, first seen Oct 26, 2026
- adao-max/agent-skillstheir own version, first seen Oct 25, 2026
- aiworkflowpro/awp-playbook-aivideo-explainertheir own version, first seen Oct 20, 2026
Other versions19 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 19
- microsoft/cat-agent-skills★ 101same name
- iart-ai/explainer-video-skills★ 22same name
- Mng-dev-ai/explainer-video★ 18same name
- charlie947/reel-editing-skills★ 9same name
- konradre/video-production-skills★ 7same name
- Neelshah1810/Claude-Video-Skills★ 6same name
- arthurkatcher/explainer-video★ 4same name
- manoletre/explainer-video★ 4same name
- adao-max/agent-skills★ 2same name
- ilkerzg/explainer-video★ 2same name
9 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 repository18 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- android-app-reverserSkill
- android-emulator-app-live-inspectSkill
- aula-pii-scanSkill
- de-ai-proseSkill
- de-ai-repoSkill
- drawio-figure-reviewerSkill
- justfile-hygieneSkill
- model-raceSkill
- nix-scaffoldSkill
- phase1-prd-grillSkill
- phase2-backlog-snowballSkill
- phase3-backlog-ralphSkill
- readme-improverSkill
- refactor-smellerSkill
- scrub-for-publicSkill
- xterm-tmux-controlSkill
- zellij-controlSkill
The file
We split this skill into the rules it gives an agent
5 rules. 0 are common, 1 is distinctive, and 4 are very specific to this project.
0
Common
Most of the 17 edited versions we read keep these.
1
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
- Very specific: line 89
Every scene page is a pure function of ?t=<ms> — it reads window.T (milliseconds, set by shared/clock.js from the URL) and renders the …
- Distinctive: line 120
Keep the light default unless the user specified dark, then provision the toolchain.
- Very specific: line 133
Keep the tested af_heart voice unless choosing another intentionally.
- Very specific: line 182
Use the theme variables (--accent, --accent2, --panel, --ink), the .term/.codefile/.chip components, and <svg class="wires"> with <path …
- Very specific: line 206
Read the PNGs. Fix overlaps, wire anchor positions, off-screen elements, mistimed beats.
“Common” is measured: kept by at least 6 in 10 of the 17 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
explainer-video — narrated animated explainers, the HTML way
Turns a topic into a finished narrated video (1920×1080 by default) by rendering HTML/CSS/JS pages as deterministic frames at the manuscript resolution and muxing them with a local TTS voice track. (Manim and animated-SVG/marp are alternative ways to render the same manuscript; this skill is the HTML one — the most polished — and ships a self-contained HTML-only scaffold.)
Everything runs inside a pinned Nix flake on x86_64-linux: no
screen-recording, wall-clock animation, cloud APIs, or API keys. Work inside
nix develop path:. so a newly copied, untracked flake is addressed explicitly.
The pipeline ships inside this skill.
bootstrap.shand thescaffold/directory beside thisSKILL.mdis a complete, self-contained project — Nix flake (+flake.lock),Justfile, the shared infra (shared/clock.js,brand.css,tts.sh(Kokoro),kokoro_synth.py,tts_manifest.py,capture-html.sh,assemble.sh,assembly_fingerprint.py,audio_pcm_sha256.sh,copy_clean.sh,manuscript.py,narration_duration.py,scene_selection.py,scene_media.py,scene_len.sh,check.sh,audition.sh,review.sh,validate.sh,list_voices.py), the HTML track (tracks/html/render.sh,capture-cdp.mjs,verify.sh,verify-seek.sh,scenes/common.js+common.css),tracks/html/templates/scene.html, a templatescript/script.json, and one example scene. All paths below are relative to a project of that shape.To start a new video, bootstrap a clean scaffold out of this skill:
bash "$(dirname "$(realpath SKILL.md)")/bootstrap.sh" ~/my-video # from the skill dir cd ~/my-video && nix develop path:. # chromium, ffmpeg, node, Kokoro deps just fetch-kokoro # one-time: pinned Kokoro-82M model + venv (offline after)Then replace
script/script.json(the manuscript) and add scene pages undertracks/html/scenes/(copytracks/html/templates/scene.html). Everything is reproducible from the clean scaffold alone — the skill depends on nothing outside itself. The bootstrap deliberately excludes live generated state. (out/,assets/kokoro/,.venv-kokoro/,node_modules/are gitignored and regenerated byjust fetch-kokoro/ the render.)
The four stages (and where each lives)
| Stage | What | Files |
| 1. Manuscript | the canonical scene list: id, title, seconds, narration, visual | script/script.json |
| 2. Speech | WAV + duration + provenance receipt per scene, via local TTS | shared/tts.sh (Kokoro-82M) → out/audio/ |
| 3. Graphics | one seekable HTML page per scene, animated on a virtual clock | tracks/html/scenes/<id>.html |
| 4. Combine | frame-capture each page → mp4, then mux with narration | tracks/html/render.sh, shared/assemble.sh → out/html.mp4 |
The single source of truth is script/script.json: it owns voice, FPS,
resolution, scene order, and speech. Receipts bind each WAV to those synthesis
inputs, so changed text or a replaced WAV fails closed until narration is rerun.
Assembly embeds a canonical input fingerprint and the decoded final-audio hash
in the MP4; changed scene videos, narration artifacts, order, media settings,
assembly settings, or played narration make validation fail until rebuilding.
Themes
The palette + fonts are a swappable theme. Use the light default unless the
user requests another look. Bundled themes in themes/<name>/:
| theme | look | fonts |
light | warm cream/paper, blue accent (default; terminals stay dark) | JetBrains Mono + Inter |
dark | muted neutral dark, lifted blue accent | JetBrains Mono + Inter |
Activate one with just theme <name> — it copies themes/<name>/vars.css to
shared/theme.css, which shared/brand.css @imports, so every scene re-skins
with no page edits. All theme fonts are nix-provided (pinned). just themes
lists them; add a theme by dropping a new themes/<name>/vars.css (same variable
set). Only the palette/fonts change — scene layout is theme-agnostic.
TTS engine. Stage 2 is Kokoro-82M (shared/tts.sh, provisioned by
just fetch-kokoro) — fully local, offline, 24 kHz, deterministic (CPU
inference, fixed speed/lang, hash-checked model). The voice is .meta.voice.
It emits out/audio/<id>.wav, .dur, and .tts.json; downstream work verifies
the receipt before using an existing narration artifact.
The one non-negotiable rule: the virtual-clock contract
Every scene page is a pure function of ?t=<ms> — it reads window.T
(milliseconds, set by shared/clock.js from the URL) and renders the frame for
that instant. Never use Date.now(), setInterval, or
requestAnimationFrame for animation state. Break this and the frame grabber
desyncs and the render stops being reproducible.
shared/clock.js gives you: window.T, seg(t0,t1) (eased 0→1 progress of a
time window), fadeWin(t0,t1), lerp, easeInOut, clamp.
tracks/html/scenes/common.js builds the animation vocabulary on top:
enter(el,t0)/pop(el,t0)— fade+rise / scale-pop entrancefadeIn/fadeOut/showWin(el,t0,t1)— visible only inside a windowpulse(el,t0)— one-shot glow ringdraw(pathEl,t0,dur)— SVG stroke draw-on (stroke-dashoffset)typeCmd(el, cmd, t0)— deterministic typewriter (chars = f(T));cmdis a string or[{t:"text", c:"cssClass"}]spans for syntax colour; returns the ms it finishes typing so you can chain the next beatrevealLines(el,t0)— stagger-reveal child lines (terminal output)caretOn()— 2 Hz blink from T only
A scene constructs or queries its DOM once, then exposes window.render(). Put
every T-dependent mutation inside that function and set complete state on
each call; do not append, latch classes, or freeze const T outside it. The
capturer can then seek forward, backward, or repeatedly without carrying state.
See tracks/html/templates/scene.html for the copy-paste skeleton, and run
just verify-html <id> after changing a scene.
Procedure
0. Preflight and optional theme
Keep the light default unless the user specified dark, then provision the toolchain.
nix develop path:. --command just themes # light, dark
nix develop path:. --command just theme dark # only when requested
nix develop path:. --command just check
nix develop path:. --command just fetch-kokoro # pinned model + locked venv1. Write the manuscript (script/script.json)
For a new video, replace .scenes and set .meta.title, .meta.voice,
.meta.fps, and .meta.resolution (positive even 16:9 dimensions).
Keep the tested af_heart voice unless choosing another intentionally; run
nix develop path:. --command just voices to list every valid pinned voice ID.
Each scene:
{ "id": "s1_slug", "title": "On-screen title", "seconds": 30,
"narration": "What the voice says. Natural, tight, ~2.5 words/sec.",
"tts_text": "Optional speech-only spelling for pronunciation.",
"visual": "What animates, beat by beat — this is your storyboard." }Rules: ids are s<n>_slug; narration is commonly ~15–25s per scene (Kokoro
reads ~2.5 w/s); optional tts_text overrides only spoken text while
narration remains reader-facing. The visual field is the stage-3 brief.
Review and freeze the manuscript before rendering. Commit only when the user or
repository workflow authorizes it.
2. Render speech (drives every scene's length)
nix develop path:. --command just audio # all scenes
nix develop path:. --command just audio s1_slug # selected scenesThis writes out/audio/<id>.wav, <id>.dur, and <id>.tts.json. From now on
shared/scene_len.sh <id> returns the exact clip length (narration + 0.8s) —
render each scene page to that length, so visuals match speech with no dead
air or clipped narration. If text, voice, settings, or WAV content changes,
scene rendering and assembly reject the stale receipt and require fresh audio.
Now listen to the exact synthesized clips while reading both the reader-facing narration and the effective spoken text:
nix develop path:. --command just audition # all scenes, manuscript order
nix develop path:. --command just audition s1_slug # selected scenes, CLI orderPause here for explicit human approval of pronunciation and pacing. A
successful player exit is not approval. If a word sounds wrong, edit tts_text,
rerun just audio <id>, and audition it again. The command writes no approval
file and refuses to play anything if any selected WAV or receipt is stale.
3. Build the graphics (one page per scene)
Copy tracks/html/templates/scene.html to tracks/html/scenes/<id>.html and
realize that scene's visual. The skeleton is fixed:
- First two
<head>tags must beshared/brand.cssthenshared/clock.js(relative../../../shared/…— the pages live two dirs deep). Thencommon.css+common.js. <body><div class="stage">is a 1920×1080 design canvas that scales uniformly to.meta.resolution. Place elements withleft/toppx; start animated ones with classhidden0(opacity 0) and reveal them from the script.- Use the theme variables (
--accent,--accent2,--panel,--ink), the.term/.codefile/.chipcomponents, and<svg class="wires">with<path class="wire">for connectors youdraw()on. - The closing script assigns an idempotent
window.render, then calls it once for browser preview. Helpers take bare element IDs:window.render=()=>{ enter('hdr',300); typeCmd('cmd',CMD,900); draw('wire',1600); }; window.render();.
Verify while you build — do not wait for the full render:
# grab three representative instants of ONE scene as PNGs and LOOK at them
read width height fps < <(
nix develop path:. --command jq -r \
'[.meta.resolution[0], .meta.resolution[1], .meta.fps] | @tsv' \
script/script.json
)
for t in 0 8000 16000; do
nix develop path:. --command chromium --headless=new --no-sandbox --disable-gpu \
--window-size="$width,$height" --screenshot=/tmp/v_$t.png \
"file://$PWD/tracks/html/scenes/s1_slug.html?t=$t&fps=$fps&w=$width&h=$height" \
2>/dev/null
done
nix develop path:. --command just check # manuscript + scene files
nix develop path:. --command just verify-html s1_slugRead the PNGs. Fix overlaps, wire anchor positions, off-screen elements,
mistimed beats. This screenshot-per-beat loop is how the good scenes were made.
With no scene IDs, just verify-html checks every scene sequentially; explicit
IDs preserve CLI order and all requested scenes are attempted before failure is
reported.
4. Render + combine
nix develop path:. --command just html # every scene
nix develop path:. --command just html s1_slug # selected scene iteration
nix develop path:. --command just review # actual rendered clips, all scenes
nix develop path:. --command just review s1_slug # replace review set with this subset
nix develop path:. --command just assemble
nix develop path:. --command just validate
# -> out/html.mp4 (muxed with narration; audio padded to video length)render.sh uses tracks/html/capture-cdp.mjs — one persistent headless
chromium per scene driven over the DevTools protocol (load once, call
window.hfSeek, wait for fonts.ready + double-rAF, then capture). This is much
cheaper than launching a chromium per frame (shared/capture-html.sh), which
matters under load. Each scene's H.264 stream is copied without another lossy
encode; only padded AAC narration is encoded, with 2 dB of headroom. Assembly
fully decodes a temporary, applies MP4 fast-start layout, then atomically
publishes it. Embedded identities bind the finished cut to the ordered scene
MP4s, verified narration inputs, manuscript media settings, assembly contract,
and the exact decoded PCM that the final audio stream plays.
just review samples six exact decoded frame indices per selected scene,
including the first and last frames. It writes per-scene sheets,
out/review/contact-sheet.png, and out/review/layout.json; the manifest binds
the displayed frame indices and sheets to source MP4 hashes. Look at every
sheet. Successful generation proves only that frames were extracted. It does
not prove visual clarity, narrative correctness, synchronization, or that a
human reviewed them. Uniform samples can also miss short-lived defects, so play
the complete final cut before delivery.
5. Verify the final cut
nix develop path:. --command just validateThe validator checks the embedded assembly fingerprint and final decoded-audio
hash, fresh narration receipts and durations, exactly one H.264/yuv420p stream
plus one AAC stream,
resolution/FPS, total duration, audio headroom, full error-sensitive decode,
MP4 fast-start, and exact ordered decoded-frame parity with the source scene
clips. It is a technical gate, not a semantic one: watch the complete video and
obtain the user's approval. Commit sources only when authorized (out/ is
gitignored).
nix develop path:. --command ffplay -autoexit out/html.mp4One freshness limit is explicit: scene MP4s do not yet have render receipts for
arbitrary browser dependencies. The validator can prove which scene MP4s were
assembled, but cannot prove they postdate changes to HTML, CSS, the theme, or
local assets. After any visual-source change, rerun just html <ids> immediately
before just review <ids> and assembly.
Gotchas (learned the hard way — heed them)
- One chromium per frame melts under parallel load. With multiple renders going the box hit load ~77 and throughput collapsed to ~7s/frame. The CDP capturer fixes it; still, render one video at a time for best throughput.
- Flush before capture. Screenshot only after
document.fonts.readyand a doublerequestAnimationFrame— otherwise text/layout isn't painted yet. (Already handled incapture-cdp.mjs; replicate if you write a new capturer.) white-space: precan double-render whitespace runs — prefer explicit spans/margins for terminal alignment.- Absolute positioning drifts — a wire drawn to
M520 528must match the element's real px box; when you move a panel, move its wire anchors. The screenshot loop catches this immediately. - Narration ≠ your
secondsestimate. Kokoro is ~2.5 w/s; always size clips fromshared/scene_len.sh(real.dur), not the script'ssecondsguess.
Adapting to a brand-new topic
- Rewrite
script/script.json .scenes+.meta.titlefor the topic. - Optionally add or activate a palette under
themes/; do not duplicate theme data in the manuscript. - One scene page per scene; reuse
common.jsverbatim — its vocabulary is topic-agnostic (terminals, chips, wires, cards, reveals). - Stages 2/4/5 are unchanged — they read the script.
The infrastructure is generic; only script/script.json and the per-scene HTML
are topic-specific.
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.

