The Self-Compiling Webpage: How Goeteia Brings Scheme and WebAssembly Together

Jul 18, 2026 webassembly scheme programming-languages self-hosting web-development compilers wasm

The Self-Compiling Webpage: How Goeteia Brings Scheme and WebAssembly Together

Every web developer has encountered the familiar stack: your code lives on a server somewhere, which compiles or bundles it, then serves the results to the browser. Even modern Jamstack architectures, while clever about caching and distribution, still follow this basic pattern. But what if the webpage itself carried its own compiler? What if you could crack open a page, see its source, edit it, and hit Run—all without any backend infrastructure?

This isn't a thought experiment. It's Goeteia, and it's running in your browser right now.

A Page That Knows Itself

The Goeteia homepage is a living demonstration of self-hosting done right. When you load the page, a tiny (~50 KB gzipped) WebAssembly compiler arrives with it. This compiler is written in Scheme—the very language it compiles. From that moment on, everything you see is rendered by code running entirely in your browser tab.

Here's the kicker: the source you're reading is the source that renders this page. There's no hidden build step, no separate distribution bundle. The page contains the whole compiler, the whole runtime, and the whole application. Edit a form in the live editor, press Run, and watch the page recompile and re-render in about 80 milliseconds.

For developers tired of watching build tools spin up for what should be instantaneous feedback, this is genuinely refreshing.

Scheme: The Underdog Language That Could

Goeteia isn't using a toy subset of Scheme. It implements the full R6RS standard with syntax-case macros, complete with fenders, nested ellipses, and datum->syntax. When the expander runs, it uses hygiene by renaming—meaning a macro's bindings and your code's bindings can never accidentally collide, no matter how clever your macro author tried to be.

The implementation doesn't cut corners on the hard problems either. Exact bignums and rationals work as you'd expect. Call/cc and dynamic-wind integrate with WebAssembly's native exception handling. And every tail call becomes a return_call, so a loop running a hundred million iterations consumes constant stack space.

This matters because Scheme has always been a language about correctness and expressiveness over convenience. Goeteia proves you can have both: a philosophically rigorous language that also runs fast in the browser.

S-Expressions All the Way Down

What makes Goeteia conceptually beautiful is how uniformly it treats everything as s-expressions. Your document structure, your CSS, your graphics, your network protocol—all of it begins as lists that the runtime transforms.

(web html) and (web css) are pure functions that transform one representation into another. (web sx) is a macro that builds a static tree at expansion time, then wires each unquote to a signal. When that signal updates, only the relevant text node changes. No virtual DOM. No diffing. Just surgical precision.

This is the DRY principle taken seriously: a color is one binding shared between your styles and your code. The template macro ensures that the static parts of your page are built once and never reconstructed unnecessarily.

Typesetting Without the Layout Engine

Here's where Goeteia gets creative with a genuinely hard problem. (web dom) wraps the browser in ordinary procedures, but (web typeset) goes further: it takes the layout engine out of the browser's hands.

After pretext processing, Goeteia measures each distinct code point exactly once, then computes layout as a pure function from those metrics to line boxes. The result? You know heights before anything touches the DOM. Virtual scrolling and streaming chat interfaces stop guessing at content heights. Text can be set in environments where no layout engine exists at all—canvas, WebGL, anywhere.

The hero subtitle on Goeteia's site is rendered glyph by glyph this way, which is why it can dodge your cursor as you move across the page. It's a small effect, but it demonstrates that the architecture gives you control the DOM typically hides.

Graphics That Don't Compromise

On the graphics side, Goeteia includes a pure-Scheme transcoder for KTX2/Basis compressed textures—supporting both ETC1S and UASTC formats. The transcoder, written from the Khronos specs, comes in at roughly 12 KB gzipped. The official C++ implementation ships at 462 KB. That's a 38x reduction, achieved by careful implementation rather than feature amputation.

Rendering is GPU-driven. A compute shader culls the frustum, compacts the survivors, and issues one drawIndexedIndirect per geometry. The whole frame is decided on the graphics card, not the CPU.

Because a shader is a datum, macros can write shaders. The hero section's twelve thousand particles run their physics in a vertex shader that Scheme assembles at runtime. This is metaprogramming at the GPU level—elegant and efficient.

Networking Without Protocol Design

When your backend also speaks Scheme (via Igropyr), requests and replies are s-expressions. There is no protocol to design; read and write are the codec. With continuations on the server, a multi-request dialogue—think checkout flows, onboarding wizards, booking sequences—becomes ordinary control flow.

The dialogue is a process. "The user is at the confirm step" means the process is parked at that line of code. The flow runs as one process whose local bindings are the conversation state. A step order the code cannot express cannot happen. If anything dies, the transaction rolls back—proof is in the answer that never arrives.

On the client side, it's all (web rpc): datum in, datum out, exact rationals intact. (web ws) and (web sse) push datum streams. (web json) handles every other backend. Clean abstractions, zero impedance mismatch.

The Self-Hosting Fixpoint

Perhaps the most remarkable technical detail: the compiler is written in the Scheme subset it compiles. The self-hosted build recompiles itself and produces byte-identical output. This fixpoint is checked in CI fashion on every change, and every test runs through both compilation stages.

This is the kind of thing that makes computer scientists smile. If the compiler can compile itself and produce the same output, you've proven something fundamental about the correctness of your implementation.

What This Means for the Web Platform

Goeteia demonstrates that WebAssembly GC is a capable compilation target for real languages with real features. It shows that the browser can host sophisticated tooling without sacrificing performance. And it proves that self-hosting—the holy grail of bootstrapped systems—is achievable in a web context.

For developers, this opens questions about where computation should live. For infrastructure providers, it suggests new models for distributed, resilient web applications. For the curious, it's a reminder that the web platform is still full of surprises.

If you've ever wanted to understand what a self-hosting system looks like in practice, Goeteia is worth exploring. The homepage is the documentation, the editor, and the proof—all in one.


Have you encountered other self-hosting web projects? Thinking about how this might change where we deploy applications? Share your thoughts below.

Read in other languages: