How I make motion videos with Claude Opus 5.5 (the full setup, prompts and numbers) A developer built a motion-design pipeline in which Claude Opus 5.5 writes a single self-contained HTML file where every frame is a pure function of time, Playwright screenshots each frame, and ffmpeg stitches the PNGs into an MP4. The approach produced a 3D product film for Slabwatch, including a modelled electricity meter, lighting, depth of field and a synthesised soundtrack, rendered on a laptop RTX 2050 at roughly 0.3 seconds per frame. The developer's render contract bans Math.random, Date.now, CSS transitions and requestAnimationFrame in render mode, and requires seeded noise and a window.renderAt(t) entry point. TL;DR. Opus 5.5 never touches a pixel. It writes one HTML file where every frame is a pure function of time, Playwright screenshots each frame, ffmpeg stitches them. Swap every adjective in your prompt for a number, ban the defaults by name, review stills before the full render. My 3D Slabwatch film rendered on a laptop RTX 2050 at about 0.3 s a frame. I'm not a motion designer. I've never opened After Effects. Last week I still needed a product film for Slabwatch, so I set up a motion design agent in Claude Code on Opus 5.5 and made one. It went through a flat 2D version that I honestly didn't like, then a full 3D rebuild with a modelled electricity meter, real lighting, depth of field, a mirror floor and a synthesised soundtrack, all rendered on my laptop's RTX 2050. Every "one prompt" motion video on your feed skips the middle part. The second prompt, the review, the "frame 84 is late" note. This article is that middle part. The exact setup, the render rules, the prompt template I use now, the numbers that make motion look expensive, and the checks that keep it sharp. Then, because my way isn't the only way, every other route I found: Blender, video models, Remotion, Manim and the rest, and when each one beats mine. Opus 5.5 outputs text. It never touches a pixel. Every motion clip you've seen from it is a program, almost always one HTML file, where every frame is a pure function of time . You give it a time t, it draws exactly that frame. Then a headless browser Playwright opens the page, freezes it at frame 0, 1, 2 and so on, screenshots each one, and ffmpeg stitches the PNGs into an MP4. That sounds boring but it's the whole trick, and it gives you three things: For that to work the page has to follow a few rules. I call it the render contract and it gets pasted under every motion prompt. Each line exists because something breaks without it: RENDER CONTRACT paste under any motion prompt - One self-contained HTML file. Only the libraries I name, pinned to an exact version. - No network requests except fonts and those pinned libraries. - Every frame is a pure function of t seconds . Expose window.renderAt t . - No Date.now, no setTimeout / setInterval, no CSS transitions, no requestAnimationFrame in render mode. - Seeded noise only mulberry32 . Never Math.random. - No state carried from one frame to the next. - Wait for document.fonts.ready before frame 0. - Loops: render frames 0 to N-1. Frame N-1 must flow into frame 0. - PNG frames into the final encode. Never JPEG. Why each line matters, quickly: Math.random makes shapes jitter between frames. One thing Movez points out that surprised me: Opus defaults to this plain "one HTML file + Playwright + ffmpeg" route even when Remotion or HyperFrames are installed. If you want a framework, say it in the prompt. My route is plain HTML, plus three.js when it's 3D. It's not the only one. Section 14 has the full table of every route Remotion, HyperFrames, Blender, Manim, Lottie, Rive, video models and more , with licenses and when to pick each. And where code loses: photoreal scenes, complex characters, organic movement. seeco makes this point well. Code wins on product films, UI motion, data stories, typography and launch explainers, which is basically everything a builder needs. For the rest, section 14 covers Blender and the video models, and how to mix them with code. No Claude Code? Start here. Florence's article has a no-install path. Open the Claude app, pick Opus 5.5, ask for the animation as one HTML file, and it plays in the preview panel. Then screen-record it Cmd+Shift+5 on a Mac, the Snipping Tool's video mode on Windows . While you iterate, ask for a frame counter on screen and a space bar pause. It's not frame-exact, a screen recording can drop frames, but it's fine for a first post. For the real thing: I run everything in Claude Code on Linux, but this works the same on a Mac. You need Node, ffmpeg and a headless Chromium. one folder for every piece you make mkdir motion-studio && cd motion-studio npm init -y npm i -D playwright npx playwright install chromium ffmpeg: sudo apt install ffmpeg Linux or brew install ffmpeg Mac claude then /model and pick Opus 5.5 Then a renderer. Mine is scripts/render.mjs , Claude wrote it, and the core is about this big: js // node render.mjs anim.html 6 30 file, seconds, fps import { chromium } from 'playwright'; import { pathToFileURL } from 'node:url'; import { mkdirSync } from 'node:fs'; const file = 'anim.html', secs = '6', fps = '30' = process.argv.slice 2 ; const FPS = Number fps , N = Math.round Number secs FPS ; // frames 0..N-1 mkdirSync 'out/frames', { recursive: true } ; const browser = await chromium.launch ; const page = await browser.newPage { viewport: { width: 1920, height: 1080 } } ; await page.goto pathToFileURL file .href, { waitUntil: 'networkidle' } ; await page.evaluate = document.fonts.ready ; for let i = 0; i < N; i++ { await page.evaluate t = { if window.renderAt window.renderAt t ; document.getAnimations .forEach a = { a.pause ; a.currentTime = t 1000; } ; }, i / FPS ; await page.screenshot { path: out/frames/${String i .padStart 4, '0' }.png } ; } await browser.close ; Then frames to video: ffmpeg -framerate 30 -i out/frames/%04d.png -c:v libx264 -profile:v high \ -pix fmt yuv420p -crf 18 -movflags +faststart out/anim.mp4 Every frame is exact because every PNG is the page frozen at one precise t, no matter how slow your machine is. A screen recording drops frames, this doesn't. Next to the renderer I keep two more scripts: scripts/qa.sh : makes a contact sheet, a frame strip, a phone-size test and a loop check from any MP4 the ffmpeg lines are in section 10 scripts/beats.py : librosa beat detection, so cuts can land on the music. In the smoke test it found 120 BPM on a 120 BPM click track, so it at least knows what a beat is And a CLAUDE.md in the studio folder that holds the render contract, the ban list and the QA rules. Every time something goes wrong, the fix goes in there as a rule, so the next piece doesn't hit it again. Honestly that file ends up mattering more than any single prompt. Each piece gets its own folder: pieces/