PricingDocs
profile picture for fz

fz

Introducing godot support (a.k.a. how we accidentally built an arcade machine)

Introducing godot support (a.k.a. how we accidentally built an arcade machine)
[Record Scratch] Yes, that’s us. You are probably wondering how we ended up in this situation. We started with a simple idea: "Let’s prototype how bitdrift would work on godot". Normal teams would write a PRD. Maybe write a spec. We are not normal. We built a fully functional arcade cabinet. This is the story of how a "quick MVP" spiraled into electrical engineering, 3D printing, a godot plugin and a new game.

Phase 1: The prototype

This began exactly how you’d expect: some engineer insisting that wiring a joystick, a DVI controller and a few buttons to a Raspberry PI is “basically trivial.” Nothing says “quick demo” like a few nights spent writing a linux kernel driver to map GPIOs as godot-compatible joystick events. Inputs were mostly functional (okay, only while touching a heat sink at the same time). So after convincing ourselves that this would work, we decided to use an existing arcade machine and rewire all internals to a custom board connected to a Raspberry Pi. Like any reasonable person would do.

Phase 2: The PCB

Staring at our protoboards and jumper cables we thought that, even if nobody will ever see it, we should design our own PCB with JST connectors to tidy things up. We also needed more power to drive the new board plus the Raspberry Pi, so we had to isolate the switch and low-rated parts. We ended up running a MOSFET from the power switch to split the high current / low current circuits. Before we knew it, KiCad was open, traces being laid out and we’d convinced ourselves that silkscreen alignment is just a suggestion. We also decided we needed a traced version of Chippy to print on the board. Obviously. At this point we hadn’t written a single line of the actual Godot integration. But hey, we have a legit looking 3D board, which we sent to manufacturing. Do you see “Speaker Out” upside down? Me neither. If you’ve ever printed a PCB, you know that the only time you find design issues is right after clicking “order”, so we did that. Turns out electrons are picky about direction, so we fixed a few things. Nothing major.

Phase 3: 3D Printing the mounts

With electronics done, we had to make them sit inside the cabinet without rattling around. Zip-ties are overrated, so we decided to print brackets, mounts and a controller enclosure. We approach 3D printing the same way we approach terraform: print → realize we forgot a hole → adjust → reprint → realize the hole is in the wrong place → wonder why we ever learned CAD → drill a hole. Eventually everything fit, and the machine looked surprisingly good… from the inside. We closed it up only to realize it must also look great from the outside. So we tore everything apart to measure every inch and then designed and printed vinyls featuring chippy. If it's worth doing, it's worth overdoing.

Phase 4: Building a game

We flipped the switch. Raspberry PI booted. The cabinet looked incredible. Everything powered on exactly as intended. And then… X11 greeted us like a 2001 Linux install party. To stay consistent with the theme of questionable decisions, we decided to build our own game. So we made Flappy Chippy, starring our mascot Chippy, a creature whose relationship with gravity is best described as “adversarial.” We kept the mechanics intentionally minimal: you flap, you avoid logs, you survive long enough to collect telemetry. That’s it. We added logs throughout, no pun intended.
Video of the debug preview of our game running from godot

Phase 5: Integrating bitdrift to Godot

Finally the part we were supposed to start with. Godot plugins can be written natively in Rust thanks to gdext, so in theory all we needed were “a few wrappers.” If you’ve been following along, you’ll know how ridiculous that sentence is. Turns out threading is hard and Godot’s scripting model is fundamentally single-threaded. That’s good… for them. Running the core SDK was pretty easy since it’s mostly unidirectional, but we also wanted to implement Session Replay and a few other niceties, which required to coordinate tokio tasks with Godot’s main thread without violating any assumptions. Godot calls into a Node written in Rust; the Rust node spins up async background tasks; tasks emit Godot signals; Godot routes them to UI components; everything remains deterministic; and nothing deadlocks. Even Godot seems surprised.
Our workflow debugger running side by side with the game
The end result: our SDK, running on a Pi, on a brand new Godot game, feeding real telemetry into bitdrift, and doing it inside an arcade cabinet we absolutely did not plan to build. But hey, that’s how we got here. And we are done. ... or, are we?

Stay in the know, sign up to the bitdrift newsletter.

Author


profile picture for fz

fz