# How I created a Claude plugin to Create Demo Videos

> Source: <https://dev.to/everydaylentils/how-i-created-a-claude-plugin-to-create-demo-videos-5c9k>
> Published: 2026-09-17 14:26:14+00:00

tldr; I asked Claude Fable (in plan mode) to screen record and create cool demo videos for my projects. It worked and now I never have to open a video editor again.

The plugin has Node scripts plus a Remotion template plus a small MCP server. 

```
scripts/
  doctor.mjs          preflight: keys, ffmpeg, Chromium, macOS permissions
  plan.mjs            demo.json manifest + a cost estimate before anything is spent
  gen/tts.mjs         narration (fal.ai or ElevenLabs), word timestamps
  gen/presenter.mjs   the on-camera avatar, lip-synced to that narration
  gen/broll.mjs       image-to-video b-roll
  gen/sfx.mjs         ElevenLabs sound effects: whoosh, pop, riser
  capture/web-*.mjs   Playwright capture with a drawn cursor
  capture/mac-*.mjs   real screen recording + cliclick input
  capture/cli-*.mjs   a staged Terminal window, retimed to the voice
  edit/retime.mjs     stretch a raw take to the narration length
  edit/composite.mjs  layered meme cold opens (slow-mo, cutouts, freeze frame)
  render/render.mjs   Remotion
  qa.mjs              frame dumps, secret scan, PySceneDetect pacing check
```

**The scripts call the** **fal.ai API****and also ElevenLabs (optional) for voices.  You bring your own API keys.** 

Everything for a video lives in one `demo.json`. If state only exists in Claude's context, it's gone on the next run, so every script reads and writes the manifest. Artifacts are cached by a hash of their inputs. Change one line of narration and one audio file regenerates, not the video.

The first version recorded Claude while it explored the app. It was too slow, you would get three seconds of nothing, a click, three seconds of nothing.

The fix was two passes. In the rehearsal, Claude drives the app through MCP tools (screenshot, decide, act, screenshot) and nothing is recorded. The output is an action script with verified selectors and coordinates. Then a deterministic runner performs that script with eased cursor motion and human typing cadence while recording. No model in the loop, so no dead air.

```
node scripts/capture/web-perform.mjs \
  --actions demo/launch/actions/create.json \
  --out demo/launch/clips/create.mp4 \
  --target-duration 12.1 \
  --timestamps demo/launch/audio/create.words.json
```

Narration is generated before anything is captured. Once a line is spoken you know exactly how long it is, so the capture can be paced to land on it, instead of cutting footage to fit a voiceover afterwards. With word-level timestamps a click can be pinned to the exact word that describes it.

The same audio drives the presenter. The avatar is animated to the narration file that plays over the screen segments, so the narrator and the person on camera are audibly one person. It's one voice for the whole video, and that rule never bends.

Claude tried doing the edits in ffmpeg. I asked him if there was a better way, and he said Yes.

Claude decided ffmpeg should do trimming, cropping and loudness, and Remotion does everything else. The template uses `TransitionSeries` with fade, wipe and slide. Transitions overlap the scenes they join, which means the finished video is shorter than the sum of its scenes. Claude said he spent a lot of tokens on fixes for that: get things wrong and the last scene is truncated. So he made a helper compute the overlap for both the metadata and the render.  (whatever that means)

Narration is laid out on an absolute timeline rather than inside each scene, for the same reason. Visuals may overlap in a transition. Two voices overlapping is instantly audible.

The capture event log goes into the render as props, so Remotion knows where every click landed and can zoom the frame toward it. Captions come from the word timestamps. None of the components do file I/O; a `build-props` step validates every artifact exists on disk and inlines the data, so a missing clip is a clear error and not a black rectangle.  Claude really is smart.

Claude kept failing, until I had him use  [PySceneDetect](https://www.scenedetect.com/) to measure reference videos.  Analyze example Shorts and you get numbers: 17 to 24 shots in 28 to 37 seconds, a cut every 1.3 to 1.7 seconds, the hook cutting away from the face within a second, nothing held longer than 2.5 seconds. Those numbers became the `listicle` style's rules. The manifest validator now warns when a shot holds too long.

The same trick built the `dynamic` tutorial style. One reference tutorial: 48 shots in 268 seconds, about 40% full-frame face, 40% tall side panel, 20% corner card, every move a 0.2s ease-out. Now "more like this" means a style with a beat sheet.

And `qa.mjs` runs PySceneDetect over the finished render to check the rhythm actually landed:

```
pacing: 21 shots, 1.48s average — inside the 1.3-1.7s target
```

I didn't want a stock AI face. So I gave Claude a selfie and asked it to make a presenter out of me.

**Me:** Make an AI influencer of me, cool hair, clear skin, just better looking version of me.

**Claude:** Understood, fixing your jawline.

**Me:** ☠️

The workflow is `still.mjs`, which generates or edits a still through fal.ai's image models. A still costs cents, a video costs dollars, so you iterate on the image until it's right and only then animate it. The face is generated once and stored on the manifest. Regenerating it per scene gives you a subtly different person in every shot, which is far creepier than a slightly static one.

Animation is one step: image plus narration audio into a talking-head model (Kling is default since it handles input audio). Claude tried the other way, generate a video of a person and lip-sync it after, and it fights itself. Claude Fable told me it didn't look good, so I trusted him. If it was Claude Opus I wouldn't trust a word he said.

After a few videos published on TikTok the avatar needed new clothes. Every video showing the same shirt in the same room looks like one video posted repeatedly, so there's a `wardrobe.json` of looks, each generated and approved by me. 

As I tried different video types and examples for Claude to mimic the capabilities grew.  Nine named styles so far. Five wide, for YouTube, a landing page or a README: `launch`, `anchor`, `tutorial`, `dynamic`, `explainer`. Four vertical, for Shorts, Reels and TikTok: `listicle`, `cohost`, `flashcard`, `glide`. A style seeds the format, presenter mode, caption style and transition policy. Anything it sets can be overridden per scene.

A Short is not the demo re-rendered at 9:16. It's its own 15 to 45 second cut in a sibling `shorts.json` that shares the project's clips, audio and cache. Screen captures are reframed for free. Narration lines kept verbatim are cache hits. 

Each Short also renders a typographic hook card as frame 0, held half a second and wiped away. Vertical platforms grab an early frame as the thumbnail and when posting through an API I couldn't override it, so frame 0 has I wanted to start with a banner overlay.

It can film web apps through Playwright, native Mac apps through real screen recording, and terminal programs in a staged Terminal window. That last one means it can demo a Claude Code plugin from inside a live `claude` session, which is how the plugin's own videos were made.

I've seen a lot of startups sell subscriptions where you can generate a set number of videos for product promotion. The problem with those cloud services is they don't know your codebase, they can't drive your app, and the branding/colors and all assets would need to be handed off to their cloud agent before anything can even be started. Claude Code running on your Mac on the other hand has none of those problems - you have a concept for a demo video and Claude has all the tools needed to shoot a demo, understand what is actually being demonstrated and to stay on brand.

The other things is video generation is expensive. I'd have to markup the cost - usually I need to pay $1.50 in Fal/Eleven API costs to create a minute long video, so anything I charge per video would need to be over that. Then handle customer support, people who don't like how the video turned out and other problems and it seemed like too much of a hassle.

So it's free on github - you of course still need to pay Fal for credits to generate video.  If you want to try it, the project is a Claude Code plugin, a Codex plugin and an `npx skills` skill.   Each host reads a different manifest, and agents without an MCP client reach the rehearsal server through a shell script.

The code is MIT and it's all here: [github.com/mrieck/demoday-claude-plugin](https://github.com/mrieck/demoday-claude-plugin). If you find it useful, give the github repo a star.
