SOIL Animated Teaching Deck: One Production, Two Deliverables
| Deliverable | Content | Audience |
|---|---|---|
| A: Deck (.pptx) | Teaching deck built with SOIL's six engines. 2–4 🎬 animation slides embed animation clips; clips are silent and subtitle-free for live narration | In-class projection |
| B: Video (MP4) | Full narrated explainer of the same content: voiceover, subtitles, three-color theme | Preview, catch-up, upload |
Both deliverables share the same animations. First build B, then from B's silent twin cut out the 🎬 slide clips and embed them into A. This way, the animation is created only once, and the duration matches perfectly on both sides.
This skill only handles the integration step. It defers to two upstream skills for the actual work:
soil-teaching-deck(mathruffian-dot/soil-teaching-deck): six engines, page roles, visual slide layouts, sandwich structure, F-0 font installation.motion-explainer(mathruffian-dot/claude-motion-explainer), along with its companion skillsmotion-design,review-loop, and the official HyperFrames skills: script, narration, frame production, subtitles, three-color theme, review, export.
0. Environment and Paths
This document uses three placeholders. Before starting, locate their actual paths:
| Placeholder | What it is | Common location |
|---|---|---|
<smd> | This skill's folder | ~/.claude/skills/soil-motion-deck (Claude Code), ~/.agents/skills/soil-motion-deck (Codex) |
<me> | motion-explainer skill folder | Same pattern, folder name motion-explainer |
<soil> | SOIL skill folder | Same pattern, folder name soil-teaching-deck |
ls -d ~/.claude/skills/{soil-motion-deck,motion-explainer,soil-teaching-deck,review-loop} ~/.agents/skills/{soil-motion-deck,motion-explainer,soil-teaching-deck,review-loop} 2>/dev/null
PowerShell (when bash is not available on Windows):
Get-ChildItem "$HOME\.claude\skills","$HOME\.agents\skills" -Directory -ErrorAction SilentlyContinue | Select-Object FullName
Other agents (e.g., Gemini CLI): look for folders with the same names inside their skills directory.
If any folder is missing, ask the user to install it following the README in the corresponding repo (each repo requires copying the folder under skills/ or skill/ into the agent's skills directory). SOIL's install.py only installs into the first folder it finds and waits for the user to press Enter. To install manually with the agent: cp -r soil-teaching-deck/skill <skills-folder>/soil-teaching-deck.
Other requirements:
- Requirements from both upstream skills: Node.js 22+, ffmpeg, Python 3, HyperFrames, and a TTS engine: edge-tts (default) – no GPU needed, suitable for most users; or Breeze TTS 2 (advanced, requires NVIDIA GPU, for research and non-commercial use only – guide the user through
motion-explainer/references/tts-setup.mdonly if they request it). - Deck building: PptxGenJS 3.12.0 (install via this skill's
templates/package.json, see §5), and the GenSekiGothic2 H/B/M fonts (install per SOIL's F-0 step). - Thumbnails: Windows with PowerPoint installed is ideal (
thumbs.pywill use PowerPoint directly, matching fonts and video poster frames exactly). Without PowerPoint, use LibreOffice + poppler – layout can be checked but video posters may not render. - Tested versions: HyperFrames 0.8.168, PptxGenJS 3.12.0.
Agents without sub-agent support (e.g., certain Codex or Gemini configurations): wherever motion-explainer says "dispatch one sub-agent per frame in parallel", instead work through each frame sequentially, reading the same files in order.
1. Opening Interview (ask all at once)
- Subject, unit, target audience, class time (SOIL's standard questions).
- Which deliverables are needed: A+B (default), A only, or B only. Even for A only, still build B first: the narration determines each frame's pacing, making the animation natural. The only difference is you won't deliver B, so the user doesn't need to audition the voiceover.
- Color scheme. Default: "video three-color + SOIL sandwich":
- Video (and animation windows in the deck) uses motion-explainer's three-color theme: default background
#121212, text#F2F0EA, accent#FF7A1A. - Deck: cover, action slide, and conclusion are dark slides using the video's colors; content slides are light slides, with the animation placed inside a dark "player window."
- Video (and animation windows in the deck) uses motion-explainer's three-color theme: default background
- Voiceover voice: follow motion-explainer's rules.
The motion-explainer's own opening interview (platform, duration, voice, three-color) has already been asked here – do not ask again. The video length is not limited by motion-explainer's "60–90 second" recommendation; the length equals the narration's duration, typically 15–25 seconds per 🎬 slide, plus a few frames before and after.
2. SOIL Engines 1–3: Mark 🎬 Animation Slides
Run Engine 1 (concept positioning), Engine 2 (context positioning), and Engine 3 (page architecture) from soil-teaching-deck. Confirm with the user after each engine. In Engine 3's page role table, add an animate field to the pages that will contain animations. Use 🎬 as the marker, not ★ (SOIL's ★ means "key page" – a different concept):
Slide 6: Why must it hold? Area puzzle 🎬
- Page role: Process
- Single main point: The big square and triangles haven't changed, so the empty area stays equal
- animate: { frame: 04-proof, poster: last }
frame is the filename (without .html) of the video frame corresponding to this slide. It's fixed in §3 when writing the storyboard: if STORYBOARD.md has a frame with src as compositions/frames/04-proof.html, write 04-proof here. Each segment's length is determined by its narration, not specified here.
Which pages are worth animating (total 2–4 slides per deck, each segment 15–25 seconds): pages where change over time is the point.
| Suitable | Examples |
|---|---|
| Derivation, proof, process | Area proof, chemical reaction, light path |
| Accumulation or comparison | Counting squares 9 + 16 = 25, bar growth |
| Myth reversal | Wrong statement → cross-out → correct statement |
| Spatial relationships | Rotation, translation, net diagram, tilted square |
Not suitable: definitions, tables, practice problems, summaries. Use SOIL's visual slide layouts for those.
3. Write the Video Script from the Deck Flow (Handoff)
The video's frame sequence follows the deck's flow. First, write a lookup table in BRIEF.md inside the video project. Filenames are decided here:
| Deck Slide | Video Frame (filename) | Narration Summary | Purpose |
|---|---|---|---|
| 2 Problem intro | 01-ladder | Engine 1's scenario question | Video only |
| 🎬 3 | 02-squares | This slide's single main point | Clipped as p03 |
| 4–5 Concepts | 03-names | Core concepts + terminology | Video only |
| 🎬 6 | 04-proof | This slide's single main point | Clipped as p06 |
| … | … | … | … |
| 13 Summary | 07-takeaway | Engine 1's "one sentence to take away" | Video only |
Clip names use p + two-digit page number (e.g., p03, p06), matching the video(s, "p06", …) calls in build_deck.js.
Then follow motion-explainer's format to write SCRIPT.md (one ## Line N per frame) and STORYBOARD.md (each frame's src uses the filename from the table above). The narration material comes directly from SOIL's output:
- Engine 1's "three common misconceptions" → the three narration lines in the myth-reversal frame.
- Engine 1's "one sentence to take away" → the last frame's narration, verbatim; the deck's summary slide uses the same sentence.
- Each 🎬 slide's "single main point" → the last line of that frame's narration.
- Length estimate: 4–4.5 Chinese characters per second. A 🎬 frame's narration is roughly 70–100 characters (15–25 seconds).
When dispatching a 🎬 frame to a worker, add these four lines to _dispatch_context.md (they will be extracted for silent, subtitle-free playback):
- Understandable by visuals alone: key numbers, labels, and conclusions must be written on screen, not only spoken.
- Start from a blank state, end at the conclusion: the final state must be complete and still for at least 1 second, as it serves as the slide's poster frame.
- Keep important content out of the subtitle zone (y > 896 px): the video's subtitles would cover it; the same frame must work for both deck (no subtitles) and video.
- Transitions between frames (the same ladder, the same triangle) proceed as normal; the clip-cutting step will automatically remove overlapping transition parts.
Next, follow the full motion-explainer workflow: narration → camera → each frame (parallel if sub-agents available, sequential if not) → assembly, subtitles, color theme → draft review → output B.
4. Silent Twin → Cut 🎬 Clips
Use absolute paths or execute from the same folder. Let $FILM represent the full path of the video project directory:
python <smd>/scripts/make_silent.py --project "$FILM" # Create $FILM-silent: remove all audio tracks and subtitles
(cd "$FILM-silent" && npx hyperframes render --quality high --output renders/silent.mp4)
python <smd>/scripts/cut_clips.py --project "$FILM" --video "$FILM-silent/renders/silent.mp4" \
--map p03=02-squares p06=04-proof p09=06-myths@first --out "$FILM/deck/media"
cut_clips.pyreads each frame's start time and duration fromindex.htmland clips from "end of overlap with previous frame" to "start of overlap with next frame." No matter whether the transition is crossfade, push-slide, or zoom-through, it won't include content from adjacent frames. It prints each segment's duration and writes it to the speaker notes.- The poster frame defaults to the last frame (stopped at the conclusion). To specify a different frame per clip, append
@firstor@N.Nsecondsto the frame name in--map(e.g.,p09=06-myths@first). For a myth-reveal page, use@firstto avoid spoiling the answer prematurely. - Any change to the video (any frame, color change, length change): re-run
make_silent.py, render, andcut_clips.py. The silent twin is a snapshot; it does not update automatically.
5. Build the Deck (SOIL Engines 4–6)
- Run Engine 4 (cognitive editing) and Engine 5 (style) following SOIL's rules. For Engine 5's color scheme, use the scheme chosen in §1.
- Create the deck folder. Always use this skill's
package.json: the HyperFrames project's rootpackage.jsonhas"type": "module"; without its ownpackage.json,requirecalls will fail.
mkdir -p "$FILM/deck" && cp <smd>/templates/package.json <smd>/templates/deck_helpers.js "$FILM/deck/"
cp <smd>/templates/example_pythagoras.js "$FILM/deck/build_deck.js" # Start from and modify the example
(cd "$FILM/deck" && npm install)
- Rewrite
build_deck.js. Start with this fixed header. Always useLAYOUT_WIDE(13.333 × 7.5 inches): SOIL's PptxGenJS quick-reference usesLAYOUT_16x9(10 inches wide) and the Microsoft JhengHei font – do not copy that; the coordinates indeck_helpers.jsare designed for 13.333-inch width. Fonts follow SOIL's rules: title usesGenSekiGothic2 TW H, body text usesGenSekiGothic2 TW M.
const path = require("path");
const pptxgen = require("pptxgenjs");
const { makeDeck } = require("./deck_helpers");
const pptx = new pptxgen();
pptx.layout = "LAYOUT_WIDE";
const D = makeDeck(pptx, { theme: { bg: "121212", fg: "F2F0EA", accent: "FF7A1A" }, mediaDir: path.join(__dirname, "media") });
const s = D.lightSlide("Process・Animation");
D.title(s, "Why must it hold? Area puzzle");
D.video(s, "p06", 0.6, 2.0, 8.0); // Left side: 8-inch-wide player window (16:9); include a "click to play" hint below
// Right side: x = 9.0, width 3.9 inches: step summary or key points for the slide, so it's understandable without playing
pptx.writeFile({ fileName: path.join(__dirname, "UnitName.pptx") });
- 🎬 slide layout: left side animation (8.0 × 4.5 inches), right side 2–3 lines of steps or conclusions. Speaker notes include: clip duration, places to stop and ask students, expected answers.
- Other slides follow SOIL's page roles and visual slide layouts. Write practice problem answers in the speaker notes, not on the slide.
- Run
node build_deck.js. If clips aren't cut yet,video()will render a placeholder box; layout work can proceed.
If the user already has a SOIL deck: PptxGenJS cannot modify an existing .pptx. Follow SOIL's "diagnose-and-modify mode": read each slide's content (python -m markitdown <file>.pptx; if markitdown is unavailable, ask the user to paste the text), rewrite the slides to keep in build_deck.js, convert selected slides to 🎬 layout, and regenerate the entire file. When delivering, note that this is a newly rebuilt file; the original was not modified.
6. Review
python <smd>/scripts/thumbs.py "$FILM/deck/<DeckName>.pptx" --out "$FILM/deck/thumbs" # One PNG per slide + an overview image deck-*.png
Ignore SOIL's separate thumbnail.py (from the pptx skill); use this thumbs.py instead. Review the overview image slide by slide, checking against the list below:
- 🎬 slide poster is the animation's final frame, not a black box or placeholder text
- Animation window is not obscured by other text or graphics; the play hint below is visible
- Each slide has a single main point; sandwich structure is respected (dark cover, action, conclusion; light content slides)
- The deck's accent color matches the video's color family (on light slides, a deeper shade of the same accent is fine – e.g.,
#E8601Apaired with the video's#FF7A1A); numbers and terminology are consistent across both - Speaker notes contain clip duration, places to pause and ask questions, and answers
- Practice problem answers have been verified by calculating them
- Video B review is complete per
review-loop(screen capture one frame per clause, review each one)
7. Delivery
Provide the paths to the .pptx and MP4 files, and explain:
- Which slides are 🎬 slides, their individual durations, and which animation frame was used as each poster.
- The computer used for playback must have the GenSekiGothic2 font installed (the .pptx does not embed fonts; without it, the system fallback will be used).
- The videos are embedded in the .pptx and play directly in PowerPoint and Keynote. Google Slides may not preserve embedded video upon import; for Google Slides, upload the
media/*.mp4files to Google Drive and insert them as video links. - Ask the user to listen to the narration (ASR cannot detect tone). To fix mispronunciations, use
fix_voice.pyfrom motion-explainer; after fixing, re-cut the clips and rebuild the deck.
references/lessons.md documents the pitfalls encountered during the first implementation (Pythagorean theorem, 13 slides, 3 animation segments, 110-second video).