Repository navigation
Description
Goal
Let motion-render make explainer videos without Claude Motion, at a quality that holds up next to Motion's output, so that users on plans without Motion (Free, Pro, Max) can use it too.
Narration (Gemini TTS), BGM (Lyria), sound effects (ElevenLabs), mixing and MP4 encoding stay as they are. Only the part that writes and draws the animation changes.
Current state
- Claude Motion is a beta that only Team and Enterprise have; it is off by default on Enterprise and not available on Free, Pro or Max (eesel: Claude Motion pricing, SmartScope). The README already says so (docs(readme): note that Claude Motion is a Team and Enterprise beta #12)
- The Motion dependency is small and isolated:
render.tsonly needs a page that exposeswindow.__animationwithload(film)→{ meta: { duration, parts: [{ key, a0, dur }] } },frame(t)→ PNG data URL, andconsoleLog().tests/fixtures/player/artifact-type/app.jsis already a stand-in player that satisfies this contract, andbuildworks with it- Motion-specific steps are only SKILL.md steps 3–4 (create the film from the Motion Artifact type, fetch it with
Artifact read/ArtifactData) andstore.ts(prepare) placeOnFilm()/placeSfx()place narration and effects by scene id and the film's actual scene starts, so any backend that reportsscene id → start, durfits
- What Motion gives us today that a replacement must cover: the Artifact type's authoring instructions (layout, motion, design system), a player, and a hosted preview URL
render.tstreats film code as untrusted: no network, nothing outside the film dir, Chromium sandbox on. A replacement must not weaken this
Research
Video frameworks
| Candidate | License | Latest (npm) | Model | Fit |
|---|---|---|---|---|
| HyperFrames (HeyGen) | Apache-2.0 | hyperframes 0.8.191, 2026-10-24 |
Plain HTML/CSS/JS, seekable timelines, built for agents | Best candidate (details below) |
| Remotion | Remotion License | remotion 4.0.538, 2026-10-22 |
React, frame = pure function | Strong, but a company license is needed for organizations of 4+ people (License FAQ). Every user's employer would have to check this, so not a good default for a distributed tool |
| Motion Canvas | MIT | @motion-canvas/core 3.17.2, 2025-02-16 |
Canvas scene graph, generators | No DOM/CSS, no release for ~20 months |
| Revideo | MIT | @revideo/core 0.11.0, 2026-07-10 |
Motion Canvas fork with a Node render API | Smallest community; canvas only |
| Theatre.js | core Apache-2.0, studio AGPL-3.0 | 0.7.2, 2024-05-19 | Keyframe editor | Stale; editor-centric |
| Manim | MIT | — | Python, math animation | Different stack; good for math, not general explainers |
| Lottie / Rive | MIT / — | — | Exported from design tools | Not something an LLM authors well |
Comparison background: Remotion vs Motion Canvas vs Revideo (PkgPulse).
Animation libraries (for a page we author ourselves)
All of these can be paused and seeked, which is what deterministic frame capture needs:
- GSAP 3.15: all plugins (SplitText, MorphSVG, …) are free under the Standard "No Charge" License. Not OSI open source; the restriction is on building visual no-code animation builders that compete with Webflow. Its FAQ says AI tools generating GSAP code are not a prohibited use. Paused timelines +
seek() - Anime.js 4.5 (MIT):
timeline.seek(ms) - Motion 14.6 (MIT):
pause()and a settabletime - Web Animations API:
pause()+currentTime
HyperFrames in detail (read from the repo at 0.8.191)
- Determinism: compositions expose
window.__hf = { duration, seek }; the renderer seeks every frame and never plays. On Linux it captures with CDPHeadlessExperimental.beginFrameinchrome-headless-shellwith--deterministic-mode; macOS, Windows and system Chrome fall back toPage.captureScreenshot(HeyGen: HTML to video,packages/engine/src/services/screenshotService.ts,packages/cli/src/browser/manager.ts) - Adapters for GSAP, CSS keyframes, WAAPI, Lottie, Anime.js, Three.js, D3 and maps (
packages/core/src/runtime/adapters/) - Format:
index.htmlwithdata-composition-id/data-duration; each scene is a hostdivwithdata-composition-src,data-start,data-duration.npx hyperframes timeline --jsonreturns each clip'sabsStart/absEnd, so we can read backscene id → start, dur. We can also writedata-start/data-durationourselves fromtiming.json - Audio: it mixes
<audio>elements itself, and with none it outputs video only. So we can keep our ownmix()and mux afterwards - Quality tooling for agents (this is what Motion's type instructions do for us today):
- Craft rules in
skills/hyperframes/references/motion.md: easing by role (expo.out/power4.outto arrive,power2.inOutto move,power3.into leave), exits 40–50% shorter than entrances, 60–120 ms word staggers, holds of about 0.5 s + 0.3 s per word, a list of "defaults that look generated" references/types/explainer.md: "one diagram that grows", the voice is the clockcheck --json: overflow, clipping, overlap, occlusion, WCAG contrast, text below a size floor.snapshot --atfor stills.lintfor the HTML contractthemes/(neutral, bold, editorial) with an 18-token contract, and a registry of ~210 blocks / ~239 components (charts, flowcharts, transitions)- Official skills for Claude Code (
npx hyperframes skills update)
- Craft rules in
- Footprint: Node ≥ 22, ffmpeg,
puppeteer-core, a downloadedchrome-headless-shell(separate from our Playwright Chromium), ~23 MB unpacked.--workersruns 1–24 Chrome processes in parallel - Concerns
- Security: Chrome always runs with
--no-sandbox, and the render path does not block network (packages/engine/src/services/browserManager.ts); "no network" is only an authoring rule. This is weaker than ourrender.ts - Japanese: the bundled Noto Sans JP is embedded as the Latin subset only; Japanese glyphs come from Google Fonts at compile time (cached), or from a
.woff2we ship. No help for Japanese line breaking - Telemetry is on by default (
HYPERFRAMES_NO_TELEMETRY=1turns it off) - Full determinism only on Linux; macOS (where most users run Claude Code) uses screenshots
- Young project (0.x, very frequent releases): pin the version
- Security: Chrome always runs with
Lessons that apply whichever we pick
From HeyGen's write-up and Remotion's official agent skills (remotion-dev/skills):
- Every frame is a pure function of time: no
Date.now(), unseededMath.random(), timers, self-running CSS animations or network at render time - Narration length sets scene length (we already do this with
timing.json) - Design for video, not a web page: one focal point per scene, safe areas and minimum text sizes (Remotion, for 1080 px-wide videos: key text 80 px from the sides and 100 px from top and bottom, headline 84 px, supporting text 44 px; scale these for 1920 px)
- Fit and measure text only after fonts load; fail if a font is missing instead of falling back silently
- Check stills of the middle of every scene before a full render
- HeyGen reports that plain HTML/CSS/JS gave more varied output than Remotion's React model, and that they tuned the authoring model so even a small model can write it reliably
- Keep the skill as a small router plus references loaded on demand (progressive disclosure)
Japanese typography (Motion handles this today; we would not)
word-break: auto-phrasebreaks Japanese at phrase (bunsetsu) boundaries using BudouX inside Chrome (since Chrome 119; needslang="ja") (Chrome for Developers). This directly addresses "unnatural line breaks in headings", which SKILL.md currently asks Claude to catch by eyebudoux(Apache-2.0, 0.10.0) can insert<wbr>when finer control is needed- Ship a Japanese
.woff2(e.g. Noto Sans JP, OFL) with the skill, since render-time network is off
Proposal
Phase 0: spike and decide (gate for the rest)
Make the same two films (a mechanism explainer such as Workload Identity Federation, and a data/chart one) three ways:
- HyperFrames render:
hyperframes render→ video only → ourmix()+ mux - HyperFrames runtime, our renderer: author in HyperFrames format, check with
lint/check/snapshot, but capture throughrender.ts(network blocked, sandbox on) by drivingwindow.__hf.seek - Our own minimal player: plain HTML/CSS + GSAP or WAAPI, implementing
__animationwith seek +page.screenshot
Compare against a Motion-made version of the same script:
- Render time for ~60 s at 1080p30 on macOS and Linux
- Determinism: render twice and compare frame hashes
- Japanese headlines: line breaks, glyph coverage, no network
- Visual quality: side-by-side stills reviewed by a person (a short rubric: layout, hierarchy, motion, transitions, consistency)
- Install friction (extra downloads, sandbox prompts in Claude Code)
Write the result and the decision back to this issue.
Phase 1: a second film backend
filmgets a kind:motion(today) orhtml(the chosen backend).stillsandbuildwork with both- Scene starts are read from the backend (or written from
timing.json) soplaceOnFilm()/placeSfx()stay unchanged - Keep the current hardening: no network, film dir only, sandbox on. If we use the HyperFrames renderer, document and mitigate the gap (e.g.
--docker, or route 2 above) - Bundle a Japanese font and set
lang="ja"+word-break: auto-phrasein the base stylesheet - Disable third-party telemetry
Phase 2: authoring guidance that matches Motion
- SKILL.md: if the Motion Artifact type is listed, use it as today; otherwise use the
htmlpath. Teams keep their current experience references/loaded on demand: layout and safe areas, design tokens (themes), motion grammar (easing by role, entrance/exit timing, staggers, holds, transitions), explainer patterns (cards, moving chips, numbered flow with the current step lit, as SKILL.md already describes), Japanese typography, determinism rules- A QA loop before
build: stills at the middle of every scene and at every sound effect, automated overflow / overlap / contrast / text-size checks, fix and re-check
Phase 3: docs and tests
- README (en/ja): which plans can use which path, extra requirements
- Tests: the new backend's film dir, scene timing read-back, determinism of a small fixture film, the render smoke test on the new path
Acceptance criteria
- On an account without Claude Motion,
/motion-render:motion-render <theme>produces a narrated MP4 with BGM (and SFX when the key is set) end to end - Rendering the same film twice gives identical frames (on the platform where the backend promises it)
- No network access and no files outside the film dir during render
- Japanese headlines break at phrase boundaries and never fall back to a missing-glyph font
- In a side-by-side review of the Phase 0 films, the new path is judged not worse than Motion on layout, motion and consistency
- The Motion path keeps working unchanged
Open questions
- Keep both paths, or move everyone to the new one once it is as good as Motion?
- Is a preview link still needed? Motion gives a hosted URL; the new path would give local stills and the MP4 (a local
previewserver could replace it)
Generated by Claude Code
Activity
umiyosh commentedon Oct 24, 2026
Split into one issue per phase. Each starts after the previous one is done; Phase 0 is the gate.
htmlfilm backend next tomotionhtmlpathhtmlpathumiyosh commentedon Oct 25, 2026
Open questions: decided
Keep both paths. Teams and Enterprise keep Claude Motion when the Motion Artifact type is available; every other plan uses the html path. In the side-by-side review (#17) the two looked alike overall, and Motion's motion was still slightly richer, so there is no reason yet to move Motion users off it. Revisit if the html path is judged as good as Motion.
No local
previewserver. Before the MP4, the html path is checked with the automatic layout check and stills of every scene, which has been enough. Once frame capture is faster (#25), the MP4 itself is the preview. Revisit if people need to show the motion to someone before the MP4 exists.The README now says this (#20).