<?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.us-east-2.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>Vibe coding for WebXR in 2026: I built a tool that turns a sentence into a VR experience</title>
      <dc:creator>Tom Pavlin</dc:creator>
      <pubDate>Wed, 22 Jul 2026 14:04:16 +0000</pubDate>
      <link>https://dev.to/tomaspavlin/vibe-coding-for-webxr-in-2026-i-built-a-tool-that-turns-a-sentence-into-a-vr-experience-19jo</link>
      <guid>https://dev.to/tomaspavlin/vibe-coding-for-webxr-in-2026-i-built-a-tool-that-turns-a-sentence-into-a-vr-experience-19jo</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flriwwl7p5g0snn6k1lss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flriwwl7p5g0snn6k1lss.png" alt="Lunar WebXR scene created completely with AI in one prompt" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vibe coding ate web development in about a year. You describe an app, something like Cursor or Bolt writes it, you ship it. For flat 2D web apps this is just normal now.&lt;/p&gt;

&lt;p&gt;VR got skipped. If you wanted to build something for a headset you still had two real options: learn Unity or Three.js properly, or use a no-code builder that traps everything you make inside its own engine and never hands you an actual app you can open anywhere.&lt;/p&gt;

&lt;p&gt;I wanted a third option, so I built it. &lt;strong&gt;&lt;a href="https://turbl.dev/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=webxr-2026&amp;amp;utm_content=try-it" rel="noopener noreferrer"&gt;Turbl&lt;/a&gt;&lt;/strong&gt; lets you describe a VR scene in one sentence and get a real WebXR app back, running in your browser, openable on a Meta Quest with a link. It's React Three Fiber under the hood. No code, no store, no install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why nothing else scratched the itch
&lt;/h2&gt;

&lt;p&gt;By 2026 there were a handful of AI tools poking at 3D and games. Most of them build on their own closed engine, so whatever you make lives on their platform and you can't take the real app anywhere. The ones aimed at actual developers could scaffold a bit of Three.js, but weren't built around VR, or around the one loop I cared about: type a sentence, put the headset on, walk around inside the thing, send someone a link.&lt;/p&gt;

&lt;p&gt;That loop is the entire reason WebXR (VR on the open web) is interesting in the first place. No app store gatekeeping, no 200 MB download, no sideloading through some sketchy tool. You open a URL and you're inside it. I couldn't find anything that treated &lt;em&gt;that&lt;/em&gt; as the whole point, so Turbl does.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;It's less mysterious than the demos make it look.&lt;/p&gt;

&lt;p&gt;You send a prompt. A coding agent spins up in a throwaway sandbox and writes the actual source: React Three Fiber components, the xr setup, whatever meshes and lights and logic the scene needs. It builds that down to a single self-contained HTML file.&lt;/p&gt;

&lt;p&gt;The one clever bit is weight. The heavy shared libraries (React, Three, R3F) load once from a cached runtime instead of getting baked into every single game, so a finished scene is a few kB of its own code instead of a 7 MB blob. That's the difference between "open link, you're in" and staring at a ten second white screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf0zeu8e0xqu34tquho0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkf0zeu8e0xqu34tquho0.png" alt="Turbl host your WebXR project automatically, but if you want, you can downloaded it and do whatever you want with it" width="744" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What you end up with is a plain WebXR app. The same React Three Fiber stack a person would write by hand, nothing sealed in a black box. It runs in any WebXR browser, which in practice means the Quest browser or desktop Chrome.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nta0qswov2p1gnao3bs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nta0qswov2p1gnao3bs.png" alt="The vibe coded XR project can be tested in browser in few clicks" width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I've made with it
&lt;/h2&gt;

&lt;p&gt;Easiest way to show what it does is to show what it made.&lt;/p&gt;

&lt;p&gt;I typed this, typos and all:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;create a gallery so i can walk around&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr52k2mzat5cdcgaib07t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr52k2mzat5cdcgaib07t.png" alt="Vibe coding a VR art gallery: the prompt and the walkable WebXR result" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I gave it no dimensions and no art direction. What came back was a walkable room, framed pictures on the walls at eye height, and a sculpture in the middle you can orbit.&lt;/p&gt;

&lt;p&gt;The spatial choices are the part I didn't expect, because I didn't ask for any of them. The pictures aren't stuck up near the ceiling where you'd crane your neck. The room is big enough to actually walk "around." The sculpture is centered, the way a real gallery would place it. All of that came out of one sentence.&lt;/p&gt;

&lt;p&gt;Not everything I build with it is that calm, though.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82d7av9il9b5v2ywkxrz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82d7av9il9b5v2ywkxrz.png" alt="VR games vibe-coded with Turbl, running in the browser via WebXR" width="800" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6wylu4bcjekj1rz0r25q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6wylu4bcjekj1rz0r25q.png" alt="VR games vibe-coded with Turbl, running in the browser via WebXR" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this game you have to defend a hill from the monsters by throwing clay on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's not magic
&lt;/h2&gt;

&lt;p&gt;Worth being straight about this. VR is harder to vibe code than a web app for one dumb reason: you can't see the bug on a monitor. A scene looks completely fine on your laptop, then you put the headset on and a wall is at your ankles, so a "2 meter" wall is a real 2 meters around your body. Spawn point matters more than you'd think. And small text that's crisp on a screen turns to mush two meters away in a headset. Some prompts take a couple of tries. I'd rather say that than pretend it one-shots everything, because a lot of what I do on the tool itself is teaching it the stuff you only learn from wearing the headset too much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you want to see a finished one without signing up, here's a &lt;a href="https://turbl.dev/project/example-clay-peak" rel="noopener noreferrer"&gt;live scene&lt;/a&gt; you can open right now.&lt;/p&gt;

&lt;p&gt;If you want to type your own sentence and see what falls out: &lt;a href="https://turbl.dev/?utm_source=devto&amp;amp;utm_medium=community&amp;amp;utm_campaign=webxr-2026&amp;amp;utm_content=try-it" rel="noopener noreferrer"&gt;turbl.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you make something cursed with it, I genuinely want to see it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>vr</category>
      <category>xr</category>
      <category>gamedev</category>
    </item>
    <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>
