CommunityCoding & Developmentgithub.com

mathruffian-dot/soil-motion-deck

Animated teaching deck: combines the SOIL Teaching Deck (six-engine presentation tool) with motion-explainer (explanatory animations) to produce two outputs at once. A is a .pptx teaching deck with embedded animated explanations on key slides; B is a narrated, subtitled MP4 video of the same content.

What is soil-motion-deck?

This skill, **soil-motion-deck**, lets an AI agent build a coordinated pair of teaching materials: a **SOIL methodology .pptx presentation** and a **full narrated MP4 explainer video**, sharing a single set of animations. The agent first produces the video (B) using the `motion-explainer` skill, which handles scriptwriting, voiceover, frame-by-frame animation with HyperFrames, subtitling, and three-color theming. Then it creates a silent twin of the video, clips out the animated segments corresponding to key slides, and embeds those silent clips into the presentation (A) built with the `soil-teaching-deck` skill. The result: the presenter can play the precise same animations on slides during class, while students can watch the complete video for preview or review. The skill supports Claude Code, Cursor, Codex, and Gemini CLI, and assumes the user already has the two upstream skills installed. It manages the entire workflow: an opening interview to define subject, audience, color scheme, and which outputs (A, B, or both); running SOIL's six engines to design the deck and mark animation slides; writing the video script from the deck's flow; rendering animations in parallel (or sequentially if sub-agents are unavailable); clipping and embedding the silent animations; assembling the final .pptx with PptxGenJS; and thorough review via thumbnail generation and checklist. The skill also handles modifying an existing SOIL deck by reading its content and regenerating it with animated slides, and includes scripts for making the silent twin (`make_silent.py`) and cutting clips (`cut_clips.py`).

Works with✓Claude Code✓Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/mathruffian-dot/soil-motion-deck/tree/HEAD/skills/soil-motion-deck

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

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

Documentation

SOIL Animated Teaching Deck: One Production, Two Deliverables

DeliverableContentAudience
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 narrationIn-class projection
B: Video (MP4)Full narrated explainer of the same content: voiceover, subtitles, three-color themePreview, 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 skills motion-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:

PlaceholderWhat it isCommon location
<smd>This skill's folder~/.claude/skills/soil-motion-deck (Claude Code), ~/.agents/skills/soil-motion-deck (Codex)
<me>motion-explainer skill folderSame pattern, folder name motion-explainer
<soil>SOIL skill folderSame 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.md only 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.py will 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)

  1. Subject, unit, target audience, class time (SOIL's standard questions).
  2. 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.
  3. 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."
  4. 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.

SuitableExamples
Derivation, proof, processArea proof, chemical reaction, light path
Accumulation or comparisonCounting squares 9 + 16 = 25, bar growth
Myth reversalWrong statement → cross-out → correct statement
Spatial relationshipsRotation, 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 SlideVideo Frame (filename)Narration SummaryPurpose
2 Problem intro01-ladderEngine 1's scenario questionVideo only
🎬 302-squaresThis slide's single main pointClipped as p03
4–5 Concepts03-namesCore concepts + terminologyVideo only
🎬 604-proofThis slide's single main pointClipped as p06
…………
13 Summary07-takeawayEngine 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):

  1. Understandable by visuals alone: key numbers, labels, and conclusions must be written on screen, not only spoken.
  2. 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.
  3. 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.
  4. 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.py reads each frame's start time and duration from index.html and 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 @first or @N.Nseconds to the frame name in --map (e.g., p09=06-myths@first). For a myth-reveal page, use @first to avoid spoiling the answer prematurely.
  • Any change to the video (any frame, color change, length change): re-run make_silent.py, render, and cut_clips.py. The silent twin is a snapshot; it does not update automatically.

5. Build the Deck (SOIL Engines 4–6)

  1. 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.
  2. Create the deck folder. Always use this skill's package.json: the HyperFrames project's root package.json has "type": "module"; without its own package.json, require calls 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)
  1. Rewrite build_deck.js. Start with this fixed header. Always use LAYOUT_WIDE (13.333 × 7.5 inches): SOIL's PptxGenJS quick-reference uses LAYOUT_16x9 (10 inches wide) and the Microsoft JhengHei font – do not copy that; the coordinates in deck_helpers.js are designed for 13.333-inch width. Fonts follow SOIL's rules: title uses GenSekiGothic2 TW H, body text uses GenSekiGothic2 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") });
  1. 🎬 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.
  2. Other slides follow SOIL's page roles and visual slide layouts. Write practice problem answers in the speaker notes, not on the slide.
  3. 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., #E8601A paired 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/*.mp4 files 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.py from 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).

Related Skills