Skip to content
Back to skills

Produce

ASecurity

Produce a short explainer video with ManimCE, narrated when the speech plugin is installed: plan the beats, write the narration and one scene script, time each scene change to the narration's word timings, render at low quality, mux the audio with ffmpeg, add captions, and check the file before calling it done (ffprobe streams and duration, a frame read back after every animation, overlapping text and elements cut off by the frame edge). Without the speech plugin it renders a silent video. Us...

  • 21 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 4, 2026
ai-agentspythonrustgogit

Works with

  • cli

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add melodic-software/claude-code-plugins --skill produce --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Produce?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Produce
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/melodic-software-produce-claude-code-plugins/badge)](https://www.skillsdirectory.com/skills/melodic-software-produce-claude-code-plugins)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
description: "Produce a short explainer video with ManimCE, narrated when the speech plugin is installed: plan the beats, write the narration and one scene script, time each scene change to the narration's word timings, render at low quality, mux the audio with ffmpeg, add captions, and check the file before calling it done (ffprobe streams and duration, a frame read back after every animation, overlapping text and elements cut off by the frame edge). Without the speech plugin it renders a silent video. Use when: 'make an explainer video', 'narrated explainer', 'animate this concept', 'Manim video of', 'render a math animation', 'turn this explanation into a video', 'silent explainer clip'. Not for hand-drawn film from style packs (use /animation:produce)."
argument-hint: "<topic> [output dir]"
user-invocable: true
disable-model-invocation: false
metadata:
  workflow-stage: implement
  summary: Script, narrate, render and self-check a ManimCE explainer video
---

# Produce

Turn a topic into a short MP4 made with ManimCE, narrated when `/speech:narrate` is available.
The audio comes first: each scene change waits for the word that starts its part of the
narration. Every render is checked by `render.py`, and you read its frames back, before the video
is called done.

Run every script through the launcher, which uses the packages the SessionStart hook installed and
never installs:
`python3 ${CLAUDE_PLUGIN_ROOT}/scripts/pydeps.py run --data-dir "${CLAUDE_PLUGIN_DATA}" -- <script> ...`.
When it exits 2 with a repair line, or `render.py` names a missing tool, run `/explainer-video:check`
and report what it prints.

## Where the files go

One work directory per video: the directory the user names, else
`${CLAUDE_PLUGIN_DATA}/videos/<slug>/`. A video and its audio are views, so they never go inside a
record bundle or beside the markdown record they explain
([record-bundle](https://github.com/melodic-software/claude-code-plugins/blob/main/docs/conventions/record-bundle/README.md)).

| Path | Who writes it | What it holds |
|---|---|---|
| `scene.py` | you | one `Scene` subclass |
| `strings.json` | you, only for untrusted text | on-screen strings the scene loads |
| `narration/script.txt` | you, when narrated | the words spoken, one paragraph per beat |
| `narration/narration.wav`, `narration/words.json` | `/speech:narrate` | the audio and each word's start and end |
| `low/`, `final/` | `render.py` | `<Scene>.mp4`, `frames/fNNNN.png`, `report.json`; `captions.srt` and `timing.json` when narrated |

## Loop

1. Plan three to six beats, one idea each, under a minute in total. A beat is something the viewer
   sees change, not a sentence to read.
2. Narrate, when you can. Narration is available when `/speech:narrate` is in this session's skill
   list.
   - Write `<dir>/narration/script.txt`: one paragraph per beat, a blank line between paragraphs,
     written the way it should be spoken.
   - Run `/speech:narrate` on it with no `--out`, so `narration.wav` and `words.json` land beside
     the script.
   - When the speech plugin is not installed, or narrate exits 2, render silent and tell the user:
     "Narration is unavailable: <the reason>. This video is silent."
3. Write `scene.py`. `${CLAUDE_PLUGIN_ROOT}/skills/produce/examples/pythagoras.py` is a working
   scene in the expected shape, and `pythagoras.txt` beside it is its narration script.
   - `from narration import beat`. Call `beat(self, k)` where beat k starts, and `beat(self, n)`
     after the last beat, where n is the number of paragraphs. Narrated, `beat` holds the scene
     until paragraph k's first word (the narration's end for n). `beat(self, k, hold=s)` holds
     `s` seconds when the render is silent, so one scene serves both.
   - A beat's animations must finish before the next paragraph starts. When the check says a
     beat runs long, shorten its `run_time` values or move an animation to a later beat.
   - Words are `Text`. Math is `MathTypst` (Typst math syntax). Do not use `Tex` or `MathTex`:
     LaTeX is not part of this plugin yet.
   - Text that came from a pull request, a fetched page or another repository's files goes into
     `strings.json`, which the scene reads with `json.load`, and is shown only through `Text`.
     Never paste it into `scene.py`.
   - Set `allow_overlap = True` on a text element, or on the group holding it, only when the
     overlap is the point.
4. Render at low quality, adding `--narration <dir>/narration` when narrated:
   `python3 ${CLAUDE_PLUGIN_ROOT}/scripts/pydeps.py run --data-dir "${CLAUDE_PLUGIN_DATA}" -- ${CLAUDE_PLUGIN_ROOT}/scripts/render.py <dir>/scene.py <SceneClass> --out <dir>/low [--narration <dir>/narration]`
   - Exit 1 lists each defect. Fix the scene and render again.
   - Exit 2 means nothing was checked: the scene raised, no video was written, the narration
     does not match its script, or a tool is missing. Fix it and render again.
5. Exit 0 is not done yet. Read every frame the script lists, with the Read tool. A frame that
   shows text too small to read, text or a shape hidden behind another element, a wrong label, or
   a beat that does not show its idea is a defect: fix the scene and go back to step 4. The
   overlap check compares text with text only, so reading the frames is what catches a shape over
   text.
6. When the low-quality render passes and its frames read clean, render the delivery at the
   quality the user asked for (`--quality m` or `--quality h`, default `l` is the draft) into
   `<dir>/final`, and read its frames the same way.
7. Report the video path, its duration from `report.json`, whether it is narrated or silent (and
   why, when silent), and the work directory.

## What the narrated checks hold to

- **Scene boundaries:** each `beat` cue lands within one frame (1/fps of the scene's timeline)
  of its paragraph's first word, and the last within one frame of the narration's end.
- **The MP4:** one video stream, one audio stream and one caption track (`mov_text`, built from
  `words.json`), with the video and audio streams within one frame per animation, plus one, of
  each other: the same frame rounding the silent duration check allows.

## Next

/explainer-video:check

When a render stops with a repair line or a missing tool.

## Gotchas

- Python 3.12 or 3.13 only. `pydeps.py` picks the first of `python3.13`, `python3.12`, `python3`,
  `python` on PATH that is one of them. The plugin README's Requirements section records why.
- On some platforms the first install builds pycairo and manimpango from source and needs the
  toolchain the README lists for that platform. A failed build is a session-start notice with the
  repair line.
- Do not call `add_sound`. `render.py` adds the narration; an audio stream in the scene's own
  render fails the check.
- Editing `script.txt` after narrating makes `render.py` exit 2: narrate it again so the words
  match.
- `render.py` checks the state at the end of each animation. An overlap that exists only in the
  middle of a transform is not reported; read the frames.

Files in this skill

  • SKILL.md6.9 KB
  • evals/evals.json4.8 KB
  • examples/pythagoras.py1.3 KB
  • examples/pythagoras.txt178 B

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…