2026-10-25

How to make videos with Claude Code

A free guide to making real MP4 videos with Claude Code: the agent writes each scene as code, your computer renders the frames, ffmpeg encodes.

Yes, you can make videos with Claude Code. A coding agent writes each scene as code, your computer renders every frame as an image, and ffmpeg (a free tool that joins images into a video) turns those frames into an MP4. Nothing is filmed, and no image or video model is involved.

Can Claude Code make videos?

It can, if you think of a video as a series of drawn pictures. Claude Code runs in your terminal, edits files and runs commands itself. So it can write the code that draws your video, run the render, and run the ffmpeg command that makes the file.

It suits kinetic typography, motion graphics, explainers, 3D product shots (through Blender) and diagrams that draw themselves.

One honest limit: code draws, it does not film. It cannot make photoreal people or real footage. If you need a real face, generate that one shot with a video model or bring your own clip, and build everything around it in code. For that kind of shot, the free Google Flow prompts are each shown with the clip they made.

How it works

  1. You describe the video. What it shows, how long, which size, the look.
  2. The model writes it. A web page, a Blender scene, a React composition or a Python scene. Plain files on your disk, nothing hosted.
  3. Your computer draws every frame. Headless Chrome (Chrome with no visible window), Blender or the framework saves frame 0, 1, 2 and so on as PNG images.
  4. ffmpeg stitches the MP4. One command turns the frames into a video.
  5. You check stills, not videos. Ask for one frame per scene before the full render. Fixing a still is one message; fixing a render is ten.
  6. You publish. The MP4 is yours. No watermark, no per-render fee.

The one rule that makes it work

The page exposes one function, window.renderFrame(t), where t is seconds from the start. It redraws the whole canvas using only t and fixed values. Nothing inside it may read the clock or use Math.random(), Date.now(), setTimeout or CSS animations.

That way the same input gives the same pixels, every time. Frame 437 looks identical whether you render it first, last or twice.

What you need

The rendering side costs nothing. Node.js, ffmpeg, Chrome and puppeteer (the tool that controls Chrome from code) are all free. The only thing you might pay for is the coding agent.

AgentWhat it costs
Claude CodeNeeds a Claude subscription or an API key.
CursorHas a free tier with limited requests.
Gemini CLIHas a free tier for a personal Google account.

Plans change, so check each tool's current pricing. The method works the same in all of them. If you use a chat-only tool, you paste the files it writes and run the commands yourself.

You also need:

Your first video

This makes a 15 to 20 second silent title-card video: short lines that fade in and rise, one card at a time.

1. Make the project folder

mkdir my-video && cd my-video
npm init -y
npm pkg set type=module
npm install puppeteer

2. Add one font

Download Space Grotesk as a .woff2 file into a fonts/ folder inside my-video. It is under the SIL Open Font License. Headless Chrome only renders fonts it loads, so don't rely on fonts installed on your system.

3. Paste the starter prompt

Start Claude Code from inside my-video, then paste this. Swap the default lines and colours for your own if you like.

You are a motion designer who builds video from code. Make a silent 15 to 20 second title-card video: a sequence of short lines, rendered frame by frame in headless Chrome and encoded to MP4 with ffmpeg. No footage, no image or video generation, no audio. Every frame is drawn with Canvas2D in a web page.

INPUTS (replace these, or use the defaults):
- LINES: 4 to 6 short statements, 1 to 6 words each. Default: "Every frame is code" / "Nothing is filmed" / "Same input" / "Same pixels" / "Render it free".
- PALETTE: background, ink, one accent. Default #0b0b0f, #f4f2ec, #c8ff3d.
- FONT: one display family, downloaded as .woff2 into fonts/. Default Space Grotesk 700 (SIL Open Font License).
- SIZE: 1920×1080 at 30 fps.

PROJECT FILES:
- index.html: a canvas with id "c", @font-face for the local font, and one module script.
- tokens.js: W, H, FPS, colours, font and sizes.
- render.mjs: the puppeteer frame capture.
- package.json with "type": "module" and puppeteer installed (npm install puppeteer).

THE RULE THAT MAKES IT WORK:
Expose window.renderFrame(t), where t is seconds. It must clear and redraw the entire canvas using only t and constants. Never use Math.random, Date.now, performance.now, setTimeout, CSS animations or requestAnimationFrame inside it. Also expose window.DURATION and window.FPS, and set window.READY = true only after document.fonts.load('700 168px "Space Grotesk"') and document.fonts.ready have resolved.

THE CARDS:
One card per line, centred on a flat background. Each card fades in while rising 40 px over 0.5 s, holds for max(1.2, 0.35 + words/3.2) seconds, then fades out over 0.25 s. Exactly one word per card uses the accent colour. Keep all text inside a 144 px margin.

RENDER HARNESS (render.mjs):
Serve the folder on a free port so the font loads over http://. Launch puppeteer headless with a 1920×1080 viewport, open index.html, wait for window.READY, and for each frame i call window.renderFrame(i / FPS) and save canvas.toDataURL('image/png') as frames/f%05d.png.

ENCODE:
ffmpeg -y -framerate 30 -i frames/f%05d.png -c:v libx264 -preset slow -crf 18 -pix_fmt yuv420p -movflags +faststart out/title_cards.mp4

Render one still per card first and check it, then render the full video. If your tool can't run commands, write the files and give me the exact commands to run.

4. What to check

Look at the stills side by side before the full render. Motion hides mistakes that stills show.

If something is off, name the still and the problem: "In the card 3 still, the last word touches the right margin." Ask for a fix and new stills.

Then open out/title_cards.mp4 in any video player. If it plays, the whole pipeline works. Every bigger video is the same idea with more interesting frames.

Which route to pick

The web page is one of several routes, and Claude Code can drive all of them.

RouteUse it forCost
Web page (Canvas + headless Chrome)Kinetic typography, motion graphics, explainers, narrated long-formFree: Node, Chrome, puppeteer, ffmpeg
Blender + MCPProduct shots, 3D scenes, physics, smoke, cloth, cinematic camera movesFree: Blender is open source, Poly Haven assets are CC0
Remotion (React)One template with many outputs, captions, map animations, apps that render videoFree for individuals and companies of up to three people; larger companies buy a licence
Python (Manim)Maths, physics and finance explainers, graphs and formulasFree, MIT licence

Web page

This is the route in the starter prompt. It can draw anything a browser can: Canvas2D, WebGL shaders, three.js 3D, particles and grain. It is not a 3D package, so for real materials and physics use Blender.

Blender

The model controls Blender directly through MCP, a way for an agent to use outside tools. A free bridge called MCP for Blender lets it run Python inside Blender, look through the camera and import free assets. It needs uv, a Python runner. In Claude Code you add it with claude mcp add blender uvx mcp-for-blender. Cycles renders are slow on a laptop, so use EEVEE for checks and Cycles only for the final.

Remotion

Video as React components, with official agent skills you add with npx skills add remotion-dev/skills. Check the licence if you work in a company of four or more people.

Python

Manim is the engine behind 3Blue1Brown-style explainers. Python in, MP4 out, no browser, one file per scene. It is a diagram engine, so 3D is basic.

Common problems

SymptomLikely causeFix
ffmpeg: command not foundYour terminal was open before the install.Open a new terminal and try again.
A blank PNGThe page was not ready when the frame was captured.Set window.READY = true only after fonts, textures and shaders are ready, and make the harness wait for it.
Chrome fails to launch on LinuxThe sandbox cannot start.Add --no-sandbox, and only inside a container you control.
Motion differs from run to runMath.random() is called inside renderFrame.Use a stateless hash(i, seed) function instead.
Headline is a few pixels off centreLetter spacing was not set before measuring.Set font and letterSpacing, then call measureText.
The render is slowA blur filter covers a large area.Blur text only, not full-frame fills.

Where can I learn the full workflow?

The first three lessons of the course are free text lessons that go further, step by step:

  1. Setup: install the tools and prove the pipeline with a one-frame test MP4.
  2. The render contract: the renderFrame(t) rules, easing helpers and a determinism test that prints PASS or FAIL.
  3. Your first card: a design-tokens file, a five-second title card checked as four stills, and the render to MP4.

Read the 3 free lessons

For the full method, the course AI Video With Code has 12 text lessons in three stages, plus optional deep-dives. Later lessons cover kinetic typography and caption timing, then narrated long-form films with a script, voice, word-timed captions, sound and a cached parallel renderer. It includes a tested kit of 29 files that turns a script into a narrated, captioned film.

Start with the free lessons. If the test MP4 plays on your machine, you have what the rest of the course builds on.

Claude and Claude Code are made by Anthropic. This guide is written by PromptVault and is not affiliated with or endorsed by Anthropic.

The course this guide comes from

AI Video With Code: Films of any length, from code, for nothing per render.