Forest of Fun

Claire's Personal Ramblings & Experiments

Shipping VR in Godot: Troubles, Victories and Reality

micro

TLDR: This is the extended written version of a talk I gave at GodotCon. The 30 minute slot was too short, my delivery was knackered, and I worried on the day that the whole thing came across as too negative — so I'd cut a chunk of positive advice for time, and I've put it back in here. Yes, Godot can ship commercial VR — we did it with Augmental Puzzles. The labour cost was roughly £80k beyond what Unity or Unreal would have been. The freedom is real, the cost is real, and the API churn nearly broke us. We chose Godot because we want to push boundaries and we want to stick with it — but as a business we need to make that call honestly before our next project.

Extended talk recording this article is based on.


I gave this talk at GodotCon recently and I really wasn't happy with my delivery. I was knackered. I'd squeezed too much content into thirty minutes, and on the day I worried I was being too negative — so I'd cut the positive advice section to make the technical war stories fit the slot. So I sat down in front of a livestream a few weeks later, threw the cut slides back in, and went through the whole thing again at a pace that was actually breathable.

This is that extended version, written down. If you're an indie thinking about Godot for VR, this is the post I wish someone had handed me three years ago.

Shipping VR in Godot: Troubles, Victories and Reality — title slide

Who Am I

Bio slide showing games shipped from PS2 era through Dead Nation, Wonderbook, Modeler and Dreams

I've been shipping games since the PS2 era, in big studios, small studios, and as part of corporations. Programmer, designer, consultant. In VR since 2013, on PSVR and PSVR2 stuff and OpenXR. When I briefly left games I went to Adobe as their main IC for XR, doing collaboration work with Apple, Meta, Pico and building out the XR engine for Modeler.

I'm a Godot contributor, mostly on the OpenXR side, advocating for owning the tech stack through open source. So this isn't a hit piece. I'm a pig, not a chicken — more on that later.

What We Shipped

Can Godot ship commercial VR — short answer yes, cost £80k more than Unity/Unreal base

The key question this whole talk is built around: can Godot ship commercial VR?

Short answer: yes. We've done it. Augmental Puzzles shipped on Meta Quest on Feb 3rd 2026 and Steam on Feb 13th 2026. It's our third or fourth Godot game depending how you count.

Slightly longer answer: it cost us roughly £80k more in labour than if we'd done it in Unity or Unreal. Unreal probably wouldn't have been a practical choice given our performance targets, but Unity would have been, and we'd likely have shipped at slightly higher quality.

That £80k isn't a made-up number. I had to sit down and work out an estimate for project costs and valuation, and that's where it landed.

Why Godot

Why Godot slide — tech freedom, modular by design, source available, not Unity not Unreal

Tech freedom. Own the whole stack. Modular by design — replace what you need. Source available, so anything is solvable with time. I've shipped on Unity. I've shipped on Unreal. I've shipped on a pile of custom engines. I know the tradeoffs.

The other thing — a concern I picked up at PlayStation and again at Adobe — is that not enough devs are working directly with the XR APIs. When everything is on Unity or Unreal, the people building games aren't getting their hands into the underlying tech, and the stack as a whole stops developing. There's a giving-back mindset baked into the Godot choice.

But. Two big buts.

  • Platform holders assume you don't exist. It's improving, but it bites in surprising ways. We were talking to a trailer company recently and they asked if we had a Liv licence. Liv is the standard way to capture VR trailers. Godot doesn't support it. Unity and Unreal do. These things keep coming up.
  • Publishers only see risk. An engine they're not familiar with. Everyone is risk averse right now.

True Cost of That Freedom

True Cost of That Freedom — £80k in labour, code vs licence fees, biggest challenge is profit and surviving

Roughly £80k in labour to build the custom tech we needed to ship. You pay it as code instead of as licence fees and plugins. You own it free and clear, and there are tax credits.

For an indie studio, your engine choice is your single biggest strategic bet. And while a lot of the benefits are long-term, your biggest challenge as an indie isn't long-term — it's getting to profit and surviving.

There's a phrase I love: turnover is vanity, profit is sanity. If your business isn't making money, it's not a business. None of us are trying to make crazy amounts of money. We just want to keep getting paid so we can keep making games.

Actually Our 3rd or 4th Godot Game

Augmental Puzzles screenshots — passthrough sudoku in VR and the comfortable collection branding

People look at Augmental Puzzles and think it's the obvious "small Godot game" choice. It really wasn't. It's the game we ended up at after a chain of cancellations.

Digging VR — Blocked

Digging VR slide showing chunked voxel grid, SDF operations and splat rendering references — PowerWash plus Puzzling Places plus paleo dig

A modeller-style VR digging game. Chunked voxel grid, SDF operations, splat rendering. PowerWash Simulator meets Puzzling Places meets a paleo dig. I knew the Quest could do it. Turns out Godot couldn't. I wrote about the technical thinking behind that title in Volume vs Surface.

We needed indirect draw dispatch features in the renderer that weren't there yet. We did sit down and estimate the cost of implementing true indirect dispatch plus the bunch of other rendering features the project would need, and the answer was clear: that wasn't the project we should move forward with. The cost was too much for where we were. Then — much like the FastText saga and Zi's TextMesh workaround that we'll get to later — David House (Bonkahe) came along and found a smaller, more elegant change: not as good as true indirect dispatch, but it enabled direct MultiMesh buffer RID access, which in theory makes this doable with a few other smaller bits stitched on top. So the digging game isn't dead forever, just shelved while we ship something that pays the bills. That was our first proper "Godot can't build this game" moment.

Rune Magic — Scrapped

Rune Magic prototype showing rune drawing in a library environment

Got to prototype. Realised the core idea kind of sucked. Clean cancel before the sunk-cost trap closed. This one's not on Godot — that's just gamedev.

Magic Shop — Cancelled with the Funding

Magic Shop screenshots — chopping ingredients, the magical apothecary scene, hex/seafood/fire spell selection, crushing consonants

This is the one we took furthest. Based on my wife's book series. Custom physics responses sat on top of an early Jolt plugin (before Jolt became the default). We had Meta funding lined up and two publishers interested. I left Adobe to set up the company properly — conflict of interest stuff.

Then the funding environment changed. Contracts got yanked. One of the publishers went out of business. I got my hands on some background sales data and the answer was a flat "no, this is not the right game to build right now." Scope and market were misaligned.

We could have built that game in Godot. I was nervous about Godot's character animator being strong enough but I had workarounds in mind. The cancellation was a market call, not a tech call. I wrote about the wider business reasoning in VR Biz: The Funding Cliff and The Wider Game.

The Pivot: Augmental Puzzles

The Pivot slide — ship something small, work within Godot's tech limits, sudoku plus Logitech MX Ink pen, with a passthrough toggle visible in a home office

When everything around you is on fire, the logical move is to ship something very small that works inside Godot's actual tech limits. Validate the pipeline. Prove we can finish.

The trigger was a Logitech MX Ink. I worked with Logitech on the pen while at Adobe, and as it was approaching commercial release I sat down to get the interaction profile into Godot and write a quick drawing test. Naughts and crosses on a virtual notepad. Then I turned around and went "hang on, I want to play sudoku." Went on the VR stores looking for a sudoku game. There wasn't one.

I had a relationship with Logitech for support. I love sudoku. The scope was small enough that I was confident Godot could do it. Sold to me. That became Augmental Puzzles.

Speed of Godot

Speed of Godot — game playable in two days, full menu flow in one week

This is where Godot really shines. Game up and playable in two days. Full menu flow in one week. I originally said three months to a shipped MVP — laughably wrong, ended up being eighteen months to good — but the speed of standing up a project in Godot is genuinely one of the engine's superpowers.

Puzzles turn out to be deceptively perfect for VR:

  • Seated, head-down — low fatigue
  • Handles every comfort tier
  • Small scope, big replay value
  • Forgiving of iteration

Cool Stuff in Augmental Puzzles

Cool Stuff in Augmental Puzzles — solver framework, sudoku, bugs, engine work pie chart showing the work breakdown

People hear "sudoku" and think it's trivial. It isn't.

  • Full constraint solver and hint system — solves any logical puzzle, generates them too. We hand-set all our puzzles, but the solver makes hand-setting easier and provides hints in the way a human would solve, not the way a computer would. Trickier than it sounds.
  • Solver framework — same AI, generalises out to other puzzle types we'll add.
  • Infinite undo/redo and multiplayer groundwork — building it right early so the future-multiplayer port isn't a rewrite.
  • Save merging and compression — cloud saves across many devices, day-one design constraint.
  • Fake box balls — those magnetic-looking balls you see flying around the menus aren't there for decoration. They're a comfort device. As menus flick on and off your eye has something to lock on to and track, which massively reduces fatigue across scene transitions. They're actually boxes with a fake ray-trace in the fragment shader to look like perfect spheres. We needed that to hit our framerate and quality goals at once. (I went deeper into VR comfort and the fatigue side of this in Fatigue in VR — most of "comfort" isn't nausea, it's how much you're asking the player's brain and body to do.)

The work splits roughly: a chunk of pure sudoku, a slice of bug-fixing, a slice for the solver framework, and a huge chunk for engine plumbing and Godot fixes.


Technical Issues

This is the bit you came for.

Controllers, Composition, Punch-Through

Controllers, Composition, Punch-Through slide — render models, composition layers, passthrough, OpenXR extensions are not universal, plus PSVR2 and Apple Vision sit outside OpenXR entirely

Every VR vendor ships something different. On a Meta headset, render models are gorgeous — the exact controller you're holding, animated buttons, perfect pose. Not on every platform. And if you support a platform without render models, your visuals get inconsistent unless you do the work to ship a custom hand controller anyway. So we did, and the Meta render model became wasted effort visually. I dug into the wider standards picture in OpenXR's New Controller and Why the People in the Room Matter — generic controller profile is a quietly huge deal.

Composition layers give you "free" high-resolution quads at the compositor level — fantastic for text and 2D-in-3D UI. Not universal. Different OpenXR extensions exist on different platforms. What works on Quest may not exist on PCVR, Pico, Vive, or Windows Mixed Reality — the Khronos OpenXR extension support matrix is the page I have permanently bookmarked. And PSVR2 and Apple Vision Pro aren't OpenXR headsets at all.

Passthrough we treated as a requirement. We hit some Godot bugs around render targets and punch-through with composition layers and passthrough interacting badly. The XR team got most of those fixed quickly, to be fair.

Pause: Six Months

Pause Six Months slide — personal issues, family illness, indie reality, ADHD diagnosis, with a 3D-printed smiling uterus toy on the right

Honest section, because I think indies shouldn't sugar-coat this.

We lost six months to personal and family stuff. Mum and some friends got cancer, my wife was sick, and I was struggling through the NHS pipeline for an ADHD diagnosis at the same time. Sadly one friend did pass — otherwise we have been blessed with fighters and good luck. If I'd still been working at a tech company I'd have taken six months' compassionate leave. Running my own studio just meant six months of burning money, and I tried to work through it, which was not the smartest idea I've ever had.

The ADHD diagnosis eventually came through and has helped a lot in retrospect. I wrote about more of this in A Personal Journey: Year One of Flammable Penguin Games if you want the longer version.

The technical issues that were piling up at the same time blocked our fast move to market. Tech blockers and life blockers compound horribly.

API Churn — The Rough Patch

API Churn slide — renames should be separate commits, deprecate don't rename — illustrated with a hand cherry-picking a single cherry from a pile

This is the thing that hurt us most as a studio working off a forked engine.

Renames should be separate commits. They keep getting bundled into commits that are about something else, sometimes by top-tier contributors, and it keeps getting accepted in review.

Why does this matter? Cherry-picks are a normal part of professional software stacks. You don't want to upgrade to a whole new Godot version — you want to grab the one specific commit that fixes the bug you have. Every time a rename is bundled with behavioural changes, cherry-picking that change drags the rename with it, breaks build scripts, breaks variable references in your fork, and turns a thirty-second cherry-pick into a multi-hour merge conflict resolution. We had a build pipeline silently broken for weeks because of exactly this — a key part of our build was renamed inside an unrelated commit, with no behaviour change, no deprecation alias, and no build-time error. We thought we had a perf bug. We were running stale code.

Squash commits make merges harder and reviews harder. I'd much rather see a clean stack of layered commits — each layer does one thing — than a single squashed blob. Easier to review, easier to cherry-pick.

Deprecate, don't rename. Even if a name has a typo, alias it. Mark the old one deprecated. Don't break the world to fix a spelling mistake.

I went deeper into all of this — the rename pain, the build pipeline knock-ons, and the platform store compliance side of things with Meta and Epic — in Godot's Rough Patch.

Why So Many Rendering Stories?

Why So Many Rendering Stories — OpenXR in Godot is best in class, but the rendering team is stretched thin across mobile, desktop, web and XR

You'll notice a lot of this talk is rendering. There's a reason.

OpenXR in Godot is best-in-class. The XR team is excellent. But XR devs push against budgets nobody else hits, in standalone, PCVR and on console. We pay the tax, and we patch.

The Godot rendering team is stretched thin. Rendering programmers are hard to get, the code is hard to review, and they have to serve a hardware base that ranges from shitty Android phones to web to consoles. The engine isn't XR-first. No shade — only appreciation. It needs highlighting because it shapes everything that follows.

Why Label3D Breaks in VR

Why Label3D Breaks in VR slide — unique material per glyph thrashes the cache, MSDF quality bugs, looked like shite at VR distances; workaround is TextMesh — with a Bluesky post from Zi at Penguin Festival showing his motion analysis VR scene

We were ready to ship a friends-and-family build. Then performance fell off a cliff.

I pulled the magnetic balls out — same. I went hunting for fragment-rate problems — nothing. The frame counts were fine on average. The killer was spikes when objects entered the world.

Label3D was generating a unique material per glyph. Every. Single. Character. The theory was that the material cache further down would save you. I'm not 100% convinced it does, and even if it does there's a lot of cache thrashing. Combine that with MSDF font quality bugs (since fixed upstream — thanks bruvzg) which forced us to crank up resolution to make text not look like shite at VR viewing distances, and you've got materials flying everywhere, VRAM thrashing, and an asset pipeline tantrum.

Big shout to Zi (Penguin Festival dev) — I found out after I'd solved this that he hit the same problem and just used TextMesh. If you're hitting Label3D performance trouble in VR right now, use TextMesh. It'll burn more frame time than ideal but it will ship.

FastText

FastText slide — shared FontResource across all FastText nodes, single draw call per text node, instance parameters drive per-glyph colour and theme via a custom shader, with a GPU font rendering demo screenshot

I wrote up the full FastText story — the diagnosis, the hatchet job on Label3D, and the shader work — in VR Text Was Killing Performance, So I Took a Hatchet to Godot's Label3D. The short version:

What I built instead. Three rules:

  1. Shared FontResource across all FastText nodes — multiple labels, one resource.
  2. Single draw call per text node — not ideal, would prefer one draw call for all text in its own pass, but ship-now-improve-later.
  3. Instance parameters drive per-glyph colour and theme via a custom shader.

Future direction is a single draw call for all text, and ideally moving away from MSDF entirely to proper GPU-driven splines in the style of Slug. Slug is proprietary and Godot-less; if it had a Godot version I'd have just paid for it. The good news is GreenLightning's gpu-font-rendering exists and is the path I want to take. That's a future PR.

I haven't tried to upstream FastText itself because it removes features in service of performance. It's better as an addon for now.

Platform Libs and GodotSteam

Platform Libs and GodotSteam slide — Steam DRM, Meta Horizon, Epic Online Services, PlayStation/Switch/Xbox; GodotSteam is great but single-store, we needed one surface for multi-store commercial shipping; Compliance is Compulsory

If you're shipping a Steam-only Godot game, GodotSteam is great. Single-store focus, well maintained.

We needed to ship on Steam, Meta, and (later) PlayStation. One surface for multi-store commercial shipping. Different platforms have wildly different requirements and very strict compliance — especially around data control. UK and EU GDPR and data controller laws are no joke. Even as an indie: register a data controller, write privacy policies, write your EULAs.

We also needed something that handled API rate limiting, CPU affinity, battery stress, and threading correctly — the bits the easy plugins skip. Compliance is compulsory. Especially with Meta, where we've already had data control headaches.

We picked Epic Online Services for the cross-platform layer. It's free, it doesn't force Epic accounts on the player, and it auths against Meta, Steam and PlayStation cleanly.

Backend Unified Middleware

We named it BUM, because we wanted something that dealt with platform shit.

  • One API for Steam / Meta / Epic / PS5 / future platforms
  • Offline demo mode for tradeshows
  • Multi-slot saves with cloud merge (day-one priority for me)
  • An auth state machine I know is compliant, that I can write down and report on

Cloud merge is one of those things that's a nightmare to retrofit. Build it day one or accept you'll never have it.

Extensions vs Modules vs Addons

Not 100% the same. Android extension builds fought us for weeks.

Initially we had platform code as a module. Godot at one point had a build cache issue that made SCons builds glacial whenever we iterated on the platform module. So we moved to an extension — and immediately hit linking problems with the Epic and Meta libraries on Android. Ended up setting up a JNI bridge in C++/Java, fighting CMake, and getting the Android activity layer to do what both Epic and Meta expected.

The default Android extension template is, ah, an interesting pipeline.

I'd written about this distinction before we got bitten by it: When to reach for C++ in Godot and Extending Godot: Modules, GDExtension, Addons cover the tradeoffs and the foot-guns in detail.

Build Cache Incident

Build Cache Incident slide — silent breakage for weeks, stale builds masquerading as a perf bug, build pipeline broke because of a rename

Build cache silently broken for weeks. Stale builds masquerading as a "perf bug" we couldn't find. Massive productivity sink. Solved eventually. Trust your infrastructure, then verify — I now have far more checks in our build system, on Jenkins, with proper validation that the APK actually contains the things it should contain.

Splash Submission Broke Us

Splash Submission slide — VRC.14 transparent boot rejection, working build then broken build with no code change on our side, undocumented API tested only on Unity and Unreal; fix is com.oculus.ossplash with type=mono, colorspace=Rec.2020, background=passthrough-contextual

We were on schedule for the Christmas window — and Christmas matters in VR. Headsets get gifted. New users boot up. Sales spike.

VRC.14 requires a transparent boot environment with your logo when you ship a passthrough title on Quest. We had it working. Working build, then broken build, no code change on our side. Days before submission, Meta updated the OS and broke us.

Undocumented API change. They'd flipped the default type from mono to stereo in the manifest, and our setup needed explicit values. Nothing in the docs, nothing in the forums. A friend in a private VR dev Discord (working on Unreal) had hit the same thing and pointed me at the fix:

com.oculus.ossplash meta-data:
  type=mono
  colorspace=Rec.2020
  background=passthrough-contextual

We had to hand-edit Godot's generated Android manifest.

This is one of those places "platform holders assume you don't exist" really shows up — Meta tested the OS update on Unity and Unreal. They didn't test on Godot. We missed Christmas. That's a real cost.

A Pattern You'll Recognise

Look at the rendering work and a pattern jumps out:

  • Single draw calls
  • Replacing default Godot shaders or pipelines because they're too heavy or not optimal for IO
  • Moving heavy work to compute and threading it
  • Engine defaults are optimised for the general case, not XR or console

The Magnetic Balls — MultiMesh + Compute

Magnetic Balls and MultiMesh + Compute slide — moved balls to MultiMesh, compute-shader physics, 8x8 vs 64x1 workgroup tuning, async multimesh update to avoid CPU/GPU hitch

Augmental is driven by physical balls you manipulate. Comfort and performance both depend on these being smooth. Original implementation: CPU-driven physics. Too heavy as content scaled.

  • Moved balls to MultiMesh — single draw call, single surface
  • Compute-shader-driven physics
  • Tuned workgroup size — 8x8 beat 64x1 for our access patterns
  • Async multimesh update to avoid the CPU↔GPU hitch (a recent Godot addition, exactly what we needed and what would also have helped the digging game)

If you're working with MultiMesh, look at setting buffers directly through RIDs. It's a great feature, courtesy of one of the renderer programmers whose name I keep forgetting to dig out and credit properly.

Small Optimisations, Big Wins

  • Menu mesh batching (multiple Blender meshes into one)
  • Single-mesh palette shaders — UV tricks instead of texture samples, no samplers in the fragment path
  • multi_tex.gdshader — single channel sampling where we couldn't avoid samples
  • Disabled shadows
  • Fake box balls
  • Fake specular
  • Sustained 72/90 fps after cleanup

Plus all the Godot fixes and holes plugged along the way.

Giving Back is HARD

Giving Back is HARD slide — in-game XR screenshot capture, GLES support, compositor blit pipeline, WorkerThreadPool for async JPEG, plus a list of other contributions: collision issues, Logitech pen, various XR minor bits, XR screenshot, other stuff I forget

I want to be very clear: I love giving back. The first Godot PR I ever did was a fix for ray–plane intersection that had been broken since Godot was first put on git. Decade-old bug. No unit test. The engine was using segment–plane everywhere so nobody noticed. Took ages to land. Every PR since has taken ages to land.

The XR screenshot capture I wrote for our feedback screen — Subnautica-style, mood-tagged bug reports — was a good one. Inspired by Charlie's work on Subnautica's feedback system, which I bumped into him about at GDC Europe years ago. Capturing the framebuffer is trivial in regular games. In XR right now in Godot it's broken. So I built capture-XR-to-texture using the compositor's blit pipeline (no framebuffer surgery) with WorkerThreadPool for async JPEG encode.

Original internal version was Vulkan-only. The PR adds GLES/OpenGL support, docs, and a demo. Just before it lands, the renderer team makes a change that breaks it (and a bunch of other PRs).

That happens a lot. Logitech pen interaction profile. Collision issues. Various XR minor bits. Other stuff I forget and dropped on the floor because I couldn't keep pushing.

The cost is real. Whatever a fix takes you for your game — say 10 hours — making the same fix landable for everyone is 30 to 50 hours. That 3–5x multiplier is the line item we're now backing off on.

Compositor FX and Stroke Compression

Compositor FX and Stroke Compression slide — custom render pass via compositor effect, depth test equal, delta fixed-point u8 strokes, two-step erase for instant feedback; with a screenshot of the Logitech MX Ink notepad covered in pen drawings next to a sudoku grid

The drawing work for the Logitech MX Ink is the chunk of work that made me so tired at GodotCon — I was finishing it up for a Logitech deadline.

The volume of drawing input was way too heavy for the default renderer. We needed 1k to 10k live strokes — a 16x16 grid where every cell can have annotations and pencil marks. Default in-world rendering was never going to scale.

What we do instead:

  • Custom rendering pass via a compositor effect (normal GLSL shader)
  • Dummy objects in the scene
  • Strokes injected into the compositor effect
  • DEPTH_TEST_EQUAL for order-dependent layering without flicker
  • Strokes stored as delta fixed-point u8 away from where you put them down — cache-friendly, cheap to upload, and what makes tens of thousands of strokes viable
  • Dynamically adjusts both thickness and quality with lazy revaluation
  • Erase is two-step for latency: place a temporary stroke for instant visual feedback, then real removal happens threaded behind the scenes — the user never sees the lag


Our Future

PSVR2: A Whole Other Talk

PSVR2 slide — in progress, MIT licence, less than one month of labour so far, not in the £80k estimate, with a photo of a small green test triangle on a debug screen

In progress. MIT licence (you'll still need to be a registered PlayStation developer). Less than one month of labour so far. Not included in the £80k estimate — that's a whole other set of numbers.

What Actually Shipped

What Actually Shipped slide — playable Sep 2024, friends and family Jan 2025, early access Feb 2026, Meta Quest 3 Feb 2026, Steam 13 Feb 2026, Logitech MX Ink May 2026, AndroidXR/Pico/Vision Pro/PSVR2 to come, 1.0 launch end of year

Milestone Date
Playable September 2024
Friends and Family January 2025
Early Access (Meta Quest) 3 February 2026
Steam 13 February 2026
Logitech MX Ink support May 2026
Android XR & Pico soon™
Apple Vision Pro soon™
PSVR2 end of year
1.0 launch end of year

Updates every few weeks, multiplayer and new modes incoming.

The friends and family slip to early access — January 2025 to February 2026 — is the family illness, the Label3D crisis, the build cache incident, the splash submission, and the API churn all rolled together. Thirteen months of "almost ready."

The Real Takeaways

The Real Takeaways slide — 1) you own all the code and bugs, 2) engine fork, 3) compliance is compulsory, 4) rewrite your hot path, 5) upstream when you can but PRs cost 3-5x dev cost

  1. You own all the code and bugs. All of it. Even the parts you don't want to own. Every addon you bring in is now your responsibility.
  2. You will fork. If you're targeting any kind of quality bar, plan to fork the engine. Build a process around it. Minimise the amount of forking but accept it's reality.
  3. Compliance is compulsory. Whether it's GDPR or platform certification, every platform has a downloadable doc that lists every test they run on you. There are no gotchas. Read it.
  4. Rewrite your hot path. Godot prototypes fast. Quality XR will involve rewriting that prototype — moving things to C++ and compute shaders. Plan for it.
  5. Upstream when you can, but PRs cost 3–5x your dev cost. Be honest with yourself about that multiplier when budgeting.

Do We Continue With Godot?

Do We Continue With Godot slide — Yes (struck through) maybe; the cost is real, the freedom is real, tech already built so the next title is cheaper, less PR back to main, more branching out

Yes… maybe.

The cost is real. The freedom is real. The tech we've built means the next title is cheaper — a lot of the platform plumbing, the FastText, the BUM layer, the multimesh physics, the compositor stroke system — all reusable.

Realistically, we'll probably submit fewer PRs back to main and branch out more aggressively. I don't love that — I'd rather give back — but the cost multiplier on upstreaming is brutal and we need to survive. We may end up taking Godot sideways into a hard fork at some point. Longer conversation.

Even after all this work, we're not hitting Unity's performance or Unreal's quality. We're missing features both have. I'd never go to Unity at this point. I could see us going to Unreal one day, or to a hard fork of Godot that's genuinely XR-first.

But I really like Godot. I like the community. I believe in what it stands for.


Advice to Devs

This is the section I cut for time at GodotCon and the reason this written version exists.

Can You Go PCVR First?

Can you go PCVR first slide — the hardest part for small teams is making the COMPLETE game, porting is a future problem, know your game and audience, is down porting hard or impossible

The hardest part of making a small-team VR game is finishing the bloody game. VR is hard. Performance is hard. Commercial-grade completion is hard.

If you can develop the entire game as PCVR first, do that. Less performance pain, easier pipeline, Godot works better. Piracy on Quest is also very high — worth a moment of thought.

The classic advice has always been "start with your weakest platform and go up." Given where VR is and how hard standalone is, I'd flip that for small teams: target PCVR first, port down later. Down-porting is hard but rarely impossible. Most game ideas aren't at the bleeding edge of performance. The core mechanics aren't usually tied to render budget.

For our title, we had to ship everywhere on day one — that's a Augmental-specific call, not a general one.

Spec Out Your Tricky Features

Look for the things that could sink you:

  • Character rendering and animation — Godot is improving fast but is nowhere near Unity, let alone Unreal. Players notice. Players don't care what tech you're built on.
  • Streaming and IO — open world, large scenes, asset streaming. Look closely at what this costs you.
  • Asset stores and prefabs — Unity's huge advantage. A lot of those prefabs come fully wired to leaderboards, achievements, all the bits you need. Godot is improving here but a 5%-better game doesn't necessarily beat a 5%-faster team.
  • Team experience and talent — easier to hire experienced Unity/Unreal devs than experienced Godot devs. Improving year-on-year, but a real factor.

De-risking Godot Projects

De-risking Godot Projects slide — solid playable, know expected pain points, talk to porting and codev studios with Godot experience, fork stable and pick, funding partners with Godot experience, find others invested in Godot — pigs not chickens

  • Get to a solid playable as fast as you can. Prove to yourself and to investors that this game can be done in this engine.
  • Know your expected pain points before investors ask. Don't be surprised in the meeting.
  • Speak to porting and codev studios with Godot experience. They exist now in a way they didn't two years ago.
  • Fork, stable, and pick. Lock to a Godot version once you're past initial prototyping. Cherry-pick only what you absolutely need from main. Every upgrade is a QA cycle.
  • Find funding partners with Godot experience — even trailer makers.
  • Pigs, not chickens. Old scrum joke: chicken says "let's open a breakfast place" and pig says "you're interested, I'm invested." Find people who are invested in Godot, not just interested. If you're betting your studio on it, you're a pig — find the other pigs.

I really wish there was a less unfortunate phrase for that.


Conclusion

Could we have shipped this game faster in Unity? Yes, and probably at higher quality. Would I have learned what I learned, owned the tech we now own, and been able to fork the engine for our next title? No.

The honest answer to "should you ship commercial VR in Godot?" is: maybe. It depends on your scope, your team, your funding, and how much pain you can absorb in service of the long game. The engine is brilliant for prototyping, the OpenXR work is best-in-class, and the community is genuinely excellent. The cost of shipping production-grade is just much higher than people realise, and the pattern of paying for it as labour rather than licences is a real strategic tradeoff.

If I had to pick one piece of advice from all of this, it'd be: before you commit, write down the £80k. Make it a real number. If you can budget for it and still hit profit, brilliant — Godot is a wonderful place to build. If not, look hard at Unity.

We're going to keep making VR. We love VR. We're in this for the long haul, and Augmental Puzzles is just the beginning of what we want to do.

If you want to chat, I'm on Bluesky and most other things as @evilkimau, or claire-blackshaw.com/blog.


Links

Augmental Puzzles

Related Posts

Tech Mentioned

Books and Comics

  • Game Dev / Null — true stories from making games, the comic I did back in 2018