Remotion turns React components into rendered video, frame by frame. Claude Code writes React all day. So the idea that you could just ask it to author a Remotion scene directly — no editor, no timeline, just describe the shot and let the agent write the component — sounds almost too obvious to be worth a blog post. We thought so too, until we watched what actually happens the first few times an agent does that unsupervised. This is the workflow that came out of fixing what broke, not the workflow we designed on a whiteboard.
What Remotion actually is, for anyone who hasn't touched it
Remotion isn't a video editor. It's a rendering engine: you write a normal React component, it reads `useCurrentFrame()` to know where it is in time, and Remotion calls that component once per frame — in Chromium, headless — and stitches the resulting images into a video. There's no drag-and-drop layer underneath; the composition **is** the code. If you already know React, you already know most of the syntax; the only new idea is that your component runs 30 or 60 times per second of output, and every one of those calls has to draw the right thing for that instant.
That's a genuinely good fit for an LLM. Remotion scenes are ordinary, inspectable code — `interpolate`, `spring`, `<AbsoluteFill>` — not a proprietary timeline format a model has never seen. An agent that's good at React is, structurally, already most of the way to being good at Remotion.
The obvious version, and where it breaks
The naive integration is: give the agent the Remotion docs, ask it to write a composition file, run `remotion render`. We tried close variants of this early on, and here's what actually went wrong — not hypothetically, in real output.
**It renders the same frame more than once, and code that doesn't expect that lies.** A single video isn't rendered start to finish in one pass — Remotion renders frames in parallel across worker threads for speed, and a scene preview renders one frame in isolation, out of any sequence. Both of those only produce the right pixels if the component is a pure function of the frame number. Code with `Math.random()`, `Date.now()`, or a `setTimeout` looks completely normal in a code review and then produces a video where things flicker, jump, or render differently in the exported file than they did in the preview — because two different calls to "frame 40" computed two different things. This is the single most common thing an agent gets wrong on the first draft, because it's invisible until you actually render twice and diff the output.
**One giant component is a video you can't fix.** Ask for "a scene explaining the pricing tiers" with no other constraint, and a capable model will happily write one 200-line component: title, three cards, a badge, an entrance animation, all baked into a single `<PricingScene>`. It looks fine the first time. It's also now one opaque layer — changing the middle tier's price means re-touching a component you'd have to read start to finish, and the model has thrown away every seam that would have let you (or it, next time) edit just the one thing that changed.
**Code that type-checks can still fail at render time.** `tsc` and the actual bundler Remotion renders with don't always agree — we hit this ourselves on a scene that passed TypeScript cleanly and then failed the render bundler's parser on a string it didn't like. A model checking its own work against `tsc` alone will occasionally ship something that compiles but won't render.
What has to be true before an agent's Remotion code is safe to run
Given those three failure modes, here's the shape of the gate we ended up needing before any agent-authored scene reaches a real render:
- **A determinism ban.** `Math.random`, `Date.now`, `new Date`, `setTimeout`, `setInterval`, and `requestAnimationFrame` are rejected outright. Remotion supplies a seeded `random(seed)` for anything that needs to look random but has to render identically every time — that's the one escape hatch, and it's the correct one.
- **A real render-parity check, not just a type-checker.** The emitted component gets parsed by the same bundler Remotion actually renders with, not just `tsc` — so "compiles" and "renders" mean the same thing before the code is ever stored.
- **A security scan on executable code, not a blanket ban on words.** `eval`, `require`, `import`, `process`, `document`, `window` are rejected only where they'd actually execute — a scene is still free to display any of those words as on-screen text, which matters a lot if the content you're making is *about* code.
- **One hero visual, not one whole scene.** The instruction the agent gets is to build a shot from a library of existing, already-editable pieces first, and reach for a hand-written Remotion component only for the single element nothing in that library expresses — never to bake an entire scene (title, cards, captions) into one opaque block. That rule is doing more work against unfixable output than any of the technical gates above.
None of this is exotic engineering — it's the ordinary discipline of not trusting generated code blind. The specific list just happens to be Remotion-shaped: determinism because of how the renderer actually works, parity because a type-checker and a bundler are two different programs, and the one-hero-visual rule because "can I still edit this" is the whole point of doing any of it through an agent instead of asking for a finished MP4.
The loop, as it actually runs
In our own pipeline the agent never freehands a component from a blank page. It asks for the scene's fully-grounded brief — the narration, the agreed color palette, the official Remotion API rules, worked examples of the shape we want — and its **own** model writes the code against that brief. The studio never runs its own LLM on that step; it only validates what comes back: the security scan, the determinism check, the render-parity parse, then a real TypeScript pass across the whole project so a new component can't quietly break an old one. Reject at any stage and the agent gets the actual compiler error back, not a vague "try again."
Once a component passes, it doesn't go straight to a full render. It renders to three still frames — start, middle, end of its window — in seconds, using the same bundle a full video would use, just for one frame at a time instead of hundreds. The agent looks at those three frames the way you would: does the composition fill the frame, does the entrance land, is anything cut off or illegible at vertical aspect. If not, it rewrites with the specific problems named, and the loop — write, validate, preview, judge — repeats until the three frames are actually right. Only then does it get placed into the scene alongside the catalog pieces around it, and only then does a full render happen.
A worked example
Take a scene that needs a chart driven by real numbers — say, a before/after comparison for a performance post. The library of prebuilt pieces has bar charts and comparison layouts, but say none of them has the specific shape this narration wants: two numbers racing toward each other with a callout on the winner. That's a hero visual, so it's the one piece worth hand-authoring.
The brief hands back the two real numbers, the palette, and the rule that motion should read as entrance → emphasis → resolve, not just fade-in-and-sit. The agent writes a component using `interpolate` to animate both bars' widths off `useCurrentFrame()`, holds a beat once they've settled, then pulses the winning number's color. That's it submitted for validation. If the security scan and the determinism check pass and the bundler parses it clean, it renders to a three-frame filmstrip. If the middle frame shows the bars mid-animation looking cramped, that's a one-line note back to the agent — "widen the gap, delay the callout by a few frames" — not a rewrite of the whole scene, because everything else around this one component was never touched.
Where a plain Remotion project still wins
None of the above is an argument that you should always go through a studio to use Remotion. If you're building your own app and Remotion is a rendering step inside it — a certificate generator, a personalized-video feature, an internal reporting tool — hand-rolling your own composition gives you real advantages this setup deliberately gives up: arbitrary npm packages, real imports, no sandboxed scope, no committee of gates between you and `remotion render`. You wrote the code; you can trust it as much as you trust yourself, which is a different (and often looser) bar than trusting code an agent produced without you reading every line.
The gates described here exist for one specific situation: code that an agent is going to write, that's going into a shared render pipeline, that has to keep working after a hundred other people's scenes have been added and deployed on top of it. If that's not your situation — you're the only author, it's your own repo, you're going to review the diff — you don't need any of this ceremony. Write the composition, render it, ship it.
Where it's honestly still rough
The gates catch what we know to check for; they don't make an agent's first draft good, only safe. A hand-authored hero visual still comes back visually flat more often than we'd like on the first pass — "technically correct, forgettable" is a real failure mode the filmstrip preview catches but doesn't prevent. And the discipline of "catalog first, custom component only for the one missing piece" is an instruction, not a hard constraint — a determined-enough prompt can still talk an agent into baking a whole scene into one block, and the type-checker won't stop it, because unfixable-later isn't a compile error. That one is still mostly caught by a human looking at the result and asking to see the layers.
Try it
If you already drive a video pipeline from Claude Code over MCP, the fastest way to feel this is to ask for one scene that needs something genuinely custom — not a title card, something with real motion tied to real numbers — and watch what the agent does before it ever gets to a full render: the brief it works from, the rejection if the code isn't deterministic, the three still frames it checks itself against. Scenes stay editable the whole way through, and which models write the surrounding script and voice is still your call.
Related