Pular para o conteúdo principal

AI Explainer Videos: The Code-Driven Pipeline

Intermediário

A submission titled "Opus 5.5 is good at explainer videos" sat near the top of Hacker News with 319 points and 175 comments — and reading the thread, the most interesting thing is how many people got the mechanism wrong. They assumed a video model. It isn't one.

What is happening is stranger and far more useful: a coding model writes a deterministic animation program, and a separate renderer turns that program into frames. The model never sees a pixel of the output. Which means the whole thing behaves like software — diffable, re-renderable, parameterisable, and debuggable — instead of like a slot machine you re-prompt until it looks right.

This page is the practical guide that thread was missing: how the pipeline works, which of the three render engines to pick (and which one the models are measurably bad at), the two failure modes that silently break agent-written animation code, the pacing arithmetic that separates a watchable explainer from an unreadable one, and where the money actually goes.

What you'll learn
  • Explain why a coding model beats a video model at explainers — and what it gives up
  • Name the reason Math.random() is banned in a frame-rendered animation, and what replaces it
  • Pick between Remotion, Motion Canvas and Manim on licence and on how well models write them
  • Spot the two traps in agent-written animation code: the Manim fork split and the stale Remotion API
  • Compute a minimum dwell time per slide instead of guessing, so viewers can actually read
  • Predict which line item dominates the bill (it is usually not the LLM)

The mechanism: the model writes a program, not a video​

Two completely different things get called "AI video".

Diffusion video models (the family covered in generative media) take a prompt and emit pixels directly. Excellent for b-roll, a drone shot, a texture, a mood. Bad at anything that must be exactly right: legible text, a correct architecture diagram, your actual product UI, a number that has to say 40%.

Code-driven animation goes the other way. A coding model writes source code for an animation — React components, a TypeScript scene graph, or Python — and a renderer executes it. Text is text, so it is sharp and spelled correctly. A diagram is a layout, so it is accurate. Your logo is your logo file.

That split explains the HN thread's most common workflow report: the model "creates an HTML page and uses raw JS timed animations", then the frames get captured and assembled with ffmpeg. It also explains what the approach gives up — it cannot invent photographic imagery, so most real pipelines call an image model or a video model for b-roll and composite it in.

The consequence worth internalising: your explainer becomes a repository. Change the price on slide 4, re-render, done. Localise the voiceover, re-render twelve languages from the same scenes. That is not a property any prompt-to-video model gives you.

Why determinism is the whole trick​

Here is the detail that quietly decides whether your pipeline produces clean video or a flickering mess, and almost nobody writing about this mentions it.

A renderer like Remotion does not screen-record your animation. It opens the composition in headless Chrome, sets the clock to frame 0, screenshots, sets the clock to frame 1, screenshots, and so on — and it does this across multiple threads, opening the page multiple times. Frames are produced out of order, in parallel, in separate browser contexts.

Everything follows from that:

  • Animation must be a pure function of the frame number. In Remotion that is literally the API: useCurrentFrame() gives you the frame, interpolate() maps it to a value. No timers, no requestAnimationFrame, no CSS transitions driven by wall-clock time. A CSS transition renders whatever it happened to be mid-flight when the screenshot fired.
  • Math.random() is broken by construction. It returns a different value in each thread and each page load, so a "random" particle jitters to a new position every frame. Remotion ships random(seed) — a seeded mulberry32 PRNG — precisely for this: random(1) always returns 0.07301638228818774. Same for spring(), which is a cached pure calculation keyed on (frame, fps, config).
  • Dropped frames stop being possible. A screen recording of a heavy animation drops frames when the CPU can't keep up. Frame-by-frame rendering just takes longer. This is why a 5-minute render on a laptop can produce a video that plays perfectly smoothly.
Watch out
  • If you only remember one rule for prompting an agent to write animation code: forbid wall-clock time. No setTimeout, no CSS transition, no Date.now(), no Math.random(). Every visual value must be derived from the current frame number. Models will reach for CSS transitions because that is what the web corpus is full of.

The three engines​

All three are real, actively maintained, and produce broadcast-quality output. They differ on language, on licence, and — importantly — on how reliably a model writes them.

RemotionMotion CanvasManim
LanguageReact / TypeScriptTypeScript (generators)Python
Reporemotion-dev/remotionmotion-canvas/motion-canvas (~19.2k stars)ManimCommunity/manim (~41k) · 3b1b/manim (~94k)
LicenceSource-available + Company LicenceMITMIT
Sweet spotProduct/launch video, UI, text-heavy explainerTimeline-precise motion graphicsMathematical and algorithmic visualisation
Model-written qualityStrong — and it ships official agent skillsDecentWeakest of the three (see below)

Two things on that table deserve more than a row.

Remotion's licence is the gotcha, not the code​

Remotion is not MIT. It is source-available with a two-tier commercial licence, and the threshold is small enough to catch most teams: free for individuals, non-profits, evaluation, and for-profit companies with up to 3 employees; a paid Company Licence for for-profit organisations with more than three.

The second split matters more if you are building a product rather than a video:

  • Remotion for Creators — seat-based, intended for low-volume rendering within and for your own company, explicitly not for serving personalised videos to your end users.
  • Remotion for Automators — render-based, which is the tier you land in the moment an agent renders videos for customers. From version 5.0 it carries mandatory telemetry reporting with a license key.

So "my agent generates a video per signup" is not a Creators use case. Price it as Automators before you ship it. If that is a dealbreaker, Motion Canvas is MIT and covers a lot of the same ground.

The Manim trap: two forks, one import name​

This one burns people who have never heard of it, and it also explains an observation from the HN thread — that strong coding models write worse Manim than you would expect, with community reports that Gemini currently handles it better than Opus 5.5.

There are two Manims:

  • 3b1b/manim — Grant Sanderson's original, the one from the famous videos, ~94k stars, installed as manimgl.
  • ManimCommunity/manim — the community fork, ~41k stars, the one that is actually documented and maintained for general use, installed as manim.

They are API-incompatible and both are imported as from manim import *. Every tutorial, StackOverflow answer and blog post in the training corpus is one or the other, unlabelled. So the model writes plausible code that mixes both dialects, and Python raises on a method that exists in the other fork. It is not a reasoning failure; it is a poisoned-namespace failure.

The fix is boring and it works: pin the fork in your prompt and in your environment, and give the agent the version's real API surface instead of letting it recall one.

Pin the Manim dialect before the agent writes a line

Use ManimCommunity Manim (the "manim" package on PyPI), NOT 3b1b/manimgl.
Before writing any scene, run:
python -c "import manim; print(manim.__version__)"
and confirm the version. If a class or method you want is not in that
version's API, do not use it — check with:
python -c "import manim; print([n for n in dir(manim) if 'Text' in n])"
Never mix manimgl APIs (e.g. ShowCreation) with community APIs (Create).

The stale-API trap (Remotion edition)​

The same poisoned-corpus problem hits Remotion for a different reason: the library moved faster than the training data.

In current Remotion, media components live in @remotion/media, and the trimming props are trimBefore / trimAfter. Preview and render can even use different components deliberately — Html5Audio from remotion while previewing, Audio from @remotion/media when rendering, switched on useRemotionEnvironment(). A model trained mostly on older material writes import {Audio} from 'remotion' with startFrom, which is the old shape.

That code may still run. It may also silently do nothing useful, which is worse.

This is exactly why Remotion publishes official Agent Skills — a set of twelve skills that hand an agent the current best practices instead of hoping it remembers them. They are designed for Claude Code, Codex, Cursor and friends, and they follow the same open format covered in SKILL.md as an open standard.

Install Remotion's official agent skills

npx skills add remotion-dev/skills

The skills are granular, which is the point — you invoke the one that matches the phase of work: /remotion-create to scaffold, /remotion-markup for animation and typography, /remotion-studio to preview, /remotion-render to render, /remotion-captions for subtitles, plus remotion-best-practices as the umbrella when you are not sure. Vendor-maintained skills are the cheapest available fix for a model's stale knowledge of a fast-moving library: one install, and the agent stops guessing.

The pipeline that actually works​

The single biggest quality lever is not a better prompt for the whole video. It is splitting the job so the model does judgement work and the renderer does determinism work — with a human-readable artefact in between.

Guided walkthrough1 of 7
  1. Ask for a JSON scene list first: per scene, a title, the on-screen text, the visual intent, and a duration in seconds. This is the cheap, reviewable step. You can read twelve scenes in thirty seconds and fix the narrative before a single component exists — and fixing the story is the edit that most improves the video. Code generated from a reviewed storyboard is also far more consistent than code generated from a paragraph of vibes.

Render from the CLI, then find your real concurrency

# deterministic render, reproducible in CI
npx remotion render src/index.ts MyExplainer out/video.mp4

# stop guessing --concurrency: measure it
npx remotion benchmark src/index.ts MyExplainer --concurrencies=2,4,8 --runs=3

Pacing: the reason most AI explainers are unwatchable​

The most consistent complaint in the HN thread was not that the videos looked bad. It was that they moved too fast to read. Slides appear, text animates in, and it is gone before a human finishes the sentence.

This is a bug with a formula, not a matter of taste. Adult reading speed for unfamiliar screen text sits around 200–250 words per minute, and a viewer also needs time to find the new text before starting to read it. So:

# minimum dwell time for a text block, in frames
words = number of words in the block
wpm = 200 # conservative for unfamiliar on-screen text
settle = 0.4 # seconds to notice and locate the new text
exit = 0.3 # seconds of breathing room before it leaves

dwell_seconds = settle + (words / wpm) * 60 + exit
dwell_frames = ceil(dwell_seconds * fps)

# worked example: a 14-word bullet at 30 fps
# 0.4 + (14 / 200) * 60 + 0.3 = 4.9 s -> 147 frames

Two notes that make this actually useful:

  • Animate in fast, hold long. The entrance transition should be 200–400 ms; the hold is where the dwell budget goes. Models tend to do the opposite — a long elegant fade, then a short hold.
  • If narration exists, the dwell floor is the narration length. Text must stay up at least as long as the sentence describing it. Which is why deriving scene duration from the synthesised audio (step 4 above) fixes pacing almost for free.

Clamp every scene to max(dwell_frames, narration_frames) and a large fraction of the "AI slop video" feeling disappears, with no change to the visuals at all.

What it costs, and which line item dominates​

Community reports from the HN thread put a complete generated explainer at roughly $3–$4 in API spend, with the notable detail that the cost was dominated by image-model calls, not by the language model. One commenter reported generating a 5-minute video on an M4 MacBook Air in about 5 minutes of wall-clock time using an orchestrated pipeline.

Treat the absolute numbers as perishable, but the shape is structural and worth planning around:

  • The LLM is cheap here. A storyboard plus a few hundred lines of animation code is a small number of tokens. Even at flagship pricing it is cents. See what AI costs across providers.
  • Per-asset generative calls dominate. Every generated image or b-roll clip is a separate paid call, and they multiply by scene count. This is the line item to cap.
  • Compute is yours. Rendering runs on your machine or your CI, so it is time and electricity rather than API spend — until you move it to a serverless renderer, at which point it becomes both.
  • Re-renders are nearly free, which is the whole structural advantage. Fixing a typo on slide 4 costs one render, not one regeneration. Localising into twelve languages costs twelve TTS runs and twelve renders, not twelve videos.

The practical budgeting move: generate images once, commit them as assets, and keep re-renders asset-free. A pipeline that re-generates imagery on every render is the one that produces a surprising bill.

The sameness problem​

The sharpest criticism in the thread is the one worth taking seriously: within weeks of these tools spreading, the outputs became recognisable. Same gradient backgrounds, same spring-in cards, same three-word bullets, same brisk voice. Several commenters also flagged repetitive copy and, in one case, a video confidently about the wrong subject entirely — a Twilight Imperium reference site described as an AI data startup.

If you use this seriously, the levers that measurably de-generify output:

  • Supply the design system, don't let it be invented. Pass your real palette, type scale, spacing scale and logo as constants the components import. Underspecified prompts are exactly where a model's house style leaks in.
  • Write the copy yourself, or edit it hard. The visuals are the part models are good at. The narrative is the part that reads as generated.
  • Use your own screen recordings as the hero asset. Real product footage composited into a generated scene is the single strongest anti-sameness move, and it also fixes the hallucination risk — the video cannot misdescribe your product if the product is on screen.
  • Verify the claims like documentation. Anything factual in an explainer is a factual claim being published in your name, with none of a text page's easy correction path. Check it before you render, not after it is on YouTube.
  • Break one convention on purpose. One deliberate choice that the default template would not make — an odd aspect ratio, silence where music is expected, a hand-drawn asset — is usually enough to stop the output reading as machine default.
Code-driven video: the vocabulary
Pressione Enter ou Espaço para virar o cartão. Use as setas esquerda e direita para navegar entre os cartões.Termo exibido.
1 / 8

What this is good at, and what it isn't​

Worth being honest, because the sceptics in that thread had a point: much of what gets produced is an animated slide deck with a voiceover. That is a perfectly good artefact for a changelog, a launch, a release note or an onboarding walkthrough — and a poor substitute for actual teaching, which needs a worked example, a wrong turn, and a reason to care.

Reach for the code-driven pipeline when:

  • The content must be exactly right — real UI, real numbers, real diagrams.
  • You will need to change it later, or ship it in several languages.
  • The same template will produce many videos from different data.

Reach for something else when the goal is photographic footage (use a video model), or when the value is in a human explaining a hard idea badly and then well — which is still the thing no pipeline produces.

Check yourself

0/5
  1. A model writes an explainer animation using CSS transitions and setTimeout. The preview looks perfect. What happens on render?
  2. Your agent's Manim code keeps failing on methods that 'should exist'. Most likely cause?
  3. A 3-person startup builds a product that renders a personalised Remotion video for every new signup. Licensing position?
  4. Reviewers say your generated explainer is 'too fast'. Cheapest structural fix?
  5. You expect the LLM to dominate the cost of a generated explainer. What do reports actually show?

Sources & further reading​

Next​