<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tom Pavlin</title>
    <description>The latest articles on DEV Community by Tom Pavlin (@tomaspavlin).</description>
    <link>https://dev.to/tomaspavlin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3896246%2F3ca0086f-2f79-4735-b68d-53b01c359426.jpeg</url>
      <title>DEV Community: Tom Pavlin</title>
      <link>https://dev.to/tomaspavlin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tomaspavlin"/>
    <language>en</language>
    <item>
      <title>I Built a Tool to Export Claude Design Animations as MP4</title>
      <dc:creator>Tom Pavlin</dc:creator>
      <pubDate>Fri, 24 Apr 2026 16:20:34 +0000</pubDate>
      <link>https://dev.to/tomaspavlin/i-built-a-tool-to-export-claude-design-animations-as-mp4-3nd6</link>
      <guid>https://dev.to/tomaspavlin/i-built-a-tool-to-export-claude-design-animations-as-mp4-3nd6</guid>
      <description>&lt;p&gt;This is an animation I made in Claude Design:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/5ZHtgopA2dk"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Claude Design launched a week ago. People started creating stunning animations with a single prompt - but there's no way to download them. No export button. No "Save as video." The same frustration kept showing up on X, Reddit, Hacker News.&lt;/p&gt;

&lt;p&gt;Most people's workaround? Screen recording. Which works — until you notice the color banding, dropped frames, and blurry gradients.&lt;/p&gt;

&lt;p&gt;So I built a tool to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Claude Design renders animations as live React code in the browser. It's not producing a video file — it's running a web app. There's no export pipeline. Screen recording is the default, but the result is visibly worse than what you see in the browser: color banding on gradients, dropped frames on fast animations, crushed transparency.&lt;/p&gt;

&lt;p&gt;This isn't a settings problem. Screen recorders capture your &lt;em&gt;display output&lt;/em&gt; — after GPU compositing, monitor color profiles, and real-time H.264 compression. The frame has been transformed multiple times before it lands in your file.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The stack: &lt;strong&gt;Playwright&lt;/strong&gt; with headless Chromium, &lt;strong&gt;ffmpeg&lt;/strong&gt; for encoding.&lt;/p&gt;

&lt;p&gt;The interesting part is how you capture frames from a live animation without screen recording. You can't just screenshot at regular intervals — JavaScript's &lt;code&gt;requestAnimationFrame&lt;/code&gt; keeps running and you'll miss frames or get timing drift.&lt;/p&gt;

&lt;p&gt;The trick is to &lt;strong&gt;take control of the animation clock&lt;/strong&gt;. Instead of letting time flow naturally, the backend freezes it and advances it manually — frame by frame.&lt;/p&gt;

&lt;p&gt;For Claude Design's React-based animations, this means walking the React fiber tree to find the &lt;code&gt;&amp;lt;Stage&amp;gt;&lt;/code&gt; component, grabbing its internal time hook, and calling it directly with exact timestamps: 0ms, 16.6ms, 33.3ms, and so on for 60fps. The animation jumps to that precise moment, the browser paints it, and Playwright screenshots it. No racing against real-time. Every frame is deterministic.&lt;/p&gt;

&lt;p&gt;The screenshots stream as raw PNGs into ffmpeg, which encodes them to H.264.&lt;/p&gt;

&lt;p&gt;A few things that were trickier than expected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detecting animation duration&lt;/strong&gt; — there's no standard way to ask "how long is this animation?" The tool probes the page's React component tree and extracts the duration from the Stage component's props.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two RAF cycles&lt;/strong&gt; — after setting the time, you need to wait two &lt;code&gt;requestAnimationFrame&lt;/code&gt; cycles before screenshotting. One for the DOM update, one for the compositor to actually paint. Screenshot too early and you get the previous frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canvas/WebGL animations&lt;/strong&gt; — not all Claude Design outputs use React Stage. Some use raw canvas. For those, the tool replaces &lt;code&gt;window.requestAnimationFrame&lt;/code&gt; with a stub and calls the page's render function directly at each timestamp.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;And here is my tool: &lt;a href="https://claude2video.com" rel="noopener noreferrer"&gt;claude2video.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love to hear what you think.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>design</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
