λ

Igropyr

Origins


The Igropyr project contains two parts: Igropyr on the backend, and Goeteia in the browser.

I started Igropyr back in 2018 simply because I wanted to write Scheme. I was hunting for a modern, production-ready Scheme web server—something that wasn't just an academic toy—and came up completely empty. Even now, most Scheme web servers still treat HTTP like glorified string concatenation. They're missing all the baseline stuff a real backend needs today: proper JSON handling, real concurrency, async I/O.

So I hacked something together. I tried Apache with CGI for a bit, then looked at Node and wrote a thin wrapper over libuv. That was the first real prototype.

Later on, I fell down the Erlang rabbit hole and got hooked on its philosophy: message passing and let it crash. Around that time, Swish came out with an Erlang-style system on top of Chez Scheme. It was brilliant, but its network layer was still stuck in that primitive string-building era. Still, Swish was the push I needed. It convinced me to tear Igropyr down and rebuild it from scratch.

Today's Igropyr goes a lot further. If a handler crashes or times out, it doesn't just silently drop the connection; it tells the client exactly what went wrong and hands back the steering wheel. The client can retry, tweak parameters, or bail out. In practice, this hides server-side hiccups from the user and cuts down wait times. Better yet, it talks natively in s-expressions. When both ends speak Scheme, you don't need a codec. Data just crosses the wire exactly as it is, down to the exact integers. Scheme finally has its own JSON.

It actually pulled off continuation-based web programming, too—that old pipe dream of the functional programming world. You wouldn't use it for a simple web form, but for strictly transactional flows? It's magic. A single transaction can stretch right across the wire, parked and waiting between the server and the client. At this point, it's packed with what you'd expect from a modern backend: JWT, non-blocking DB and Redis clients, auto-clustering, hot code swapping, and even BLAS-accelerated vector search.

Then there's Goeteia, which came from the itch to write the frontend in pure Scheme, too. I messed around with Scheme-to-JS compilers at first, but targeting WebAssembly ended up being the real answer. And I didn't even lose JS support in the process: the compiler spits out both from the same source. If a browser is too old for Wasm GC, it gracefully falls back to a generated JS twin. You never have to manually sync them.

The Goeteia compiler itself is a tiny 50kB footprint that runs directly in the browser, heavily dialed in for 3D. It can render heavy web effects on the fly straight from Scheme, or precompile them if you need raw speed and game-level performance. I also took a weird, distinctly Scheme approach to the DOM. Instead of a heavy virtual DOM tree, it uses macro-based state management and pretext effects.

Lately, Goeteia has kind of outgrown its original scope. Because everything about it is so small and fast—compiles take milliseconds, and testing logic requires zero GPU overhead, just pure math—you can run a ton of instances side by side. I'm currently using it to drive highly concurrent AI pipelines. You feed it video footage, and it extracts the skeleton, textures, skinning, and motion data. Stuff that used to require a mocap suit and a soundstage now just needs a raw video file.

AI is already great at generating reference art, turntables, and motion video. The missing link was getting from those pixels to actual, usable 3D assets. Goeteia is that last piece of the puzzle. Like any AI workflow, it's not a one-shot process; it loops, tweaking and converging on the target until the code decides it's right.

Both parts of this project are fully open source and free for anything, including commercial use. Have fun with it.