<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>R7 Orbit</title>
<link>https://r7orbit.io/</link>
<description>News, builds and the things in between: writing, videos, projects and code about building with AI.</description>
<language>en</language>
<lastBuildDate>Mon, 05 Oct 2026 00:00:00 GMT</lastBuildDate>
<atom:link href="https://r7orbit.io/rss.xml" rel="self" type="application/rss+xml" />
<item>
<title>How I built a browser game with R7 Orbit</title>
<link>https://r7orbit.io/blog/test/</link>
<guid isPermaLink="true">https://r7orbit.io/blog/test/</guid>
<pubDate>Mon, 05 Oct 2026 00:00:00 GMT</pubDate>
<description>What actually happened when I directed a team of AI agents to build a browser game, including the parts that went wrong</description>
<content:encoded><![CDATA[<h2>Vesper Drift: Building a Game by <em>Directing AI Agents</em></h2>
<p>Vesper Drift is a browser game where you start as a pebble in space and grow, one absorbed body at a time, into a black hole. I built it in R7 Orbit, a desktop app where I hand tasks to Claude or Codex agents. Each agent gets its own git worktree and <code>orbit/*</code> branch, and its work comes back to <code>main</code> through a pull request.</p>
<p>At the start of my recording I said I’d “sit the passenger seat for this one.” That was only half true. The agents wrote nearly all the code. I made the calls that changed the project’s direction, and a few of those calls were reversals.</p>
<h2><em>Plan</em></h2>
<p>Two agents wrote docs first, no code.</p>
<p>The <code>research agent</code> worked out that the game I meant was <em>Drifter Star: Evolution</em>. It admitted it couldn’t confirm most of the details, because Steam returned HTTP 429. The 12-stage ladder, Meteorite to Black Hole, came from a Steam review and is still the ladder today.</p>
<p>The <code>creative director agent</code> came up with the name, plus my favorite line of the project:</p>
<blockquote>
<p>“a quiet, luminous drift through a dark sky where you grow from a glowing pebble into a black hole, and every size feels different.”</p>
</blockquote>
<p>The first thing that didn’t stick: Orbit asked “2D top-down or 3D like the original?” I said 3D. It shipped as 2D anyway, and I can’t find any record of why. Answering a question doesn’t mean the answer reaches the agents who need it.</p>
<h2><em>Build</em></h2>
<p>I ran four agents in parallel: core engine, stages and choices, renderer and VFX, and HUD and screens. They landed about 5,400 lines in roughly 25 minutes, and all four PRs merged in the same minute.</p>
<p>They built against stubs of each other’s code, and a fallback file held it together until an integrator replaced it.</p>
<h2><em>Playtest</em></h2>
<p>To wire everything together I started an integrator on Sonnet, then swapped to Opus 5.5 at medium effort partway through. It deleted the stubs, rewrote the game loop and added smoke tests.</p>
<p>The “playtest” was a headless bot, and a bot only really measures pacing. Its own doc says the bots barely get hit, so it says little about how threats feel. I was the real playtest. My first reaction was “I was hoping for better,” then “it’s not bad, I can work with it.” That became PR #7 and version 1, a 2D canvas game.</p>
<h2><em>Research</em></h2>
<p>Next I had an agent look into how space actually works, because asteroids looked like they were on fire. It traced that to a thruster flag on the early stages.</p>
<p>It also produced a plan: six workstreams with strict file ownership and a frozen interface doc for the next team. I let it make the open calls (“use your best judgment”), so we ended up with an angled top-down camera, vendored Three.js and a 2D fallback.</p>
<h2><em>Phase 3:</em> Five Specialists at Once</h2>
<p>This was the big swing. A creative director, UI designer, sound designer, 3D engine agent and simulation agent all worked in parallel, and I merged their PRs the next morning. The 3D engine commit alone was 105 files and +18,365 lines. They also wrote good direction docs:</p>
<blockquote>
<p>“The game should read like a calm astrophotograph you can play.”</p>
</blockquote>
<blockquote>
<p>“Space is silent, the game is not.”</p>
</blockquote>
<p>Sound is all synthesized with Web Audio, so the repo has no audio files. The simulation is deterministic: every random number comes from a seeded generator.</p>
<h3><em>What Broke</em></h3>
<ul>
<li><strong>Merge conflicts.</strong> A frozen contract didn’t stop the engine and UI branches from colliding in <code>src/main3d.js</code>. Orbit sent follow-ups and the agents sorted it out, but it ate a chunk of the next morning.</li>
<li><strong>3D quietly fell back to 2D.</strong> Three.js wasn’t in the repo because <code>.gitignore</code> had <code>build/</code>, which also swallowed <code>vendor/three/build/</code>. The fix was one character (<code>/build/</code>), plus the 80,306 lines of Three.js it let in. That’s why the repo’s line count is mostly vendor code.</li>
</ul>
<h2><em>Phase 4:</em> 3D Becomes the Default</h2>
<p>Four more tasks: README and run scripts, 3D polish, making 3D the default, and balance tuning. A bot ran 24 seeds and 18 finished all 12 stages (median 14:55).</p>
<p>Then I actually played it and didn’t like it. “This is very overwhelming.” “The first version was better.” I said I probably wasn’t going to continue. (I’d used 17% of my weekly Max plan by then.)</p>
<h2><em>Polish Pass</em></h2>
<p>I kept going, but with four small, specific tasks instead of a big team:</p>
<ul>
<li><strong>Remove radar and hide cursor.</strong> The radar was the UI agent’s own work, and I cut it.</li>
<li><strong>Simplify the background.</strong> It took four tries. The first pass felt “like underwater,” and the last one added a nebula that I loved.</li>
<li><strong>Evolution previews.</strong> They came out a bit pixelated but worked.</li>
<li><strong>Gravity.</strong> I stopped this one halfway, so only the gravity part landed: the player now pulls smaller bodies toward it. Gravity was the thing I asked for most, again and again.</li>
</ul>
<h2><em>Dev Tools</em></h2>
<p>To test late stages without playing for 15 minutes, I asked for a menu to start at any stage. The first thing I did was start as a black hole, and I said “so far I’d say the clone is a big success.” A few hours earlier I’d said the first version was better.</p>
<h2><em>Video</em></h2>
<p>I recorded the whole process: 11 clips, 54 minutes. Agents turned that into a video. One indexed and transcribed the footage, one built a brand kit, one wrote the script, and one built the edit as code in Remotion.</p>
<p>The first render needed several rounds of fixes. The script aimed for 8:00 and the final cut landed at 10:51, which I was fine with.</p>
<h2><em>What I’d Tell Someone Trying This</em></h2>
<ul>
<li><strong>Questions get answered, then lost.</strong> I said 3D and got 2D. Make sure decisions end up in a doc the agents actually read.</li>
<li><strong>Agents tell you what they don’t know.</strong> Read those warnings. They were accurate.</li>
<li><strong>A bot can test pacing, not fun.</strong> The bot liked v1 and the 3D build passed its smoke test, but I found them boring and unplayable.</li>
<li><strong>Contracts reduce conflicts, they don’t remove them.</strong></li>
<li><strong>Check git, not just the summary.</strong> 3D “worked” while silently running 2D.</li>
<li><strong>Docs go stale fast.</strong> The README still calls 2D the default.</li>
<li><strong>The fix was smaller, not bigger.</strong> Four narrow tasks and a dev menu turned it around, not another big parallel team.</li>
</ul>
<h2><em>Closing</em></h2>
<p>Vesper Drift exists: 12 stages, six endings, a deterministic universe and synthesized sound. It’s about 13,400 lines of game JavaScript, and I didn’t write most of it. What I did was decide what to keep, what to cut, and when something wasn’t good enough, including when a lot of agent work was the thing that wasn’t good enough.</p>]]></content:encoded>
</item>
</channel>
</rss>
