Bbetlang

get betlang

get betlang

56,000 lines of DOOM, in a language I made up.

bet is a small, real programming language: slang keywords on the surface, a serious compiler underneath. It compiles to native code through LLVM, manages its own memory, self-hosts, and runs DOOM. I built it as a contained experiment, and ran it to completion.

I built bet on a break from trying to make something that sells. I wanted a

project with a clear edge to it, one I could actually finish, and building a

compiler had been on my list for a long time. A joke language gave me the excuse:

keywords that read like a group chat, wrapped around a compiler that had to

genuinely work. I set one rule at the start: no research. I never checked whether

anyone had built this before, because I didn’t want the internet to kill the idea

before I’d written a line. As it turned out, Geoffrey Huntley

already had, and I didn’t learn that until later.

Geoffrey Huntley

A language that only works at the level of syntax is really just a costume, so I

gave it one real job. Games allocate and release objects constantly, and both

manual bookkeeping and garbage collection cost you frames you can’t spare. bet

handles that with arenas: allocate into a scope, use it for a frame, drop the

whole scope at once. The pattern itself isn’t new. Zig ships an arena allocator

that frees everything in one call, and Odin bakes the same arena and

temp-allocator idea in for game code. I wanted bet to carry it as a first-class

feature with its own keywords, so the language would read as a design of its own

rather than a slang reskin of something that already existed.

It’s a joke. I still wanted it to actually do something.

The other reason I built it was to run an experiment. I wanted to see how far an

AI coding agent could get on a hard, well-specified project if I stayed out of

the implementation. My job was to be the architect: I set the problem and the

acceptance criteria, then held the line on them. I did zero code review. A change

shipped only if it passed its tests, met the acceptance criteria, and cleared the

corpus. That was the only gate.

The proof that it works is DOOM, ported in full. id Software’s original C source

for the renderer, the game logic, the WAD loading, and the audio was rewritten in

bet: more than 56,000 lines, compiled to a native binary that runs the real

shareware game in a window.

Launch it and DOOM plays itself in attract mode. Those clips are the game’s

original recorded inputs, replayed through the simulation. Fixed-point math is

what makes that a real test: drift by a single step and the player starts walking

into walls. bet replays the inputs in lockstep with the reference C build, frame

for frame, so the whole simulation comes out bit-for-bit identical. Getting that

far with no shortcuts is what separates a toy language from one that can carry

real software, and it’s the result I trust most on a build I never code-reviewed.

So it finished, end to end: the compiler, self-hosting, documentation, and this

site. And that is where it stops. If a feature request comes in I’ll review it,

but there’s no roadmap and no version two on the way. bet was a joke and an

experiment and a way to learn what a build like this

actually takes, and it did all of that. If there’s one thing I want it to say

about me, it’s that I finish what I start.

The memory model is the real work.

Manual free() bookkeeping and GC pauses both wreck a frame budget. In bet you allocate into a crib, an arena scoped to the frame, and release the whole thing with evict in O(1). No per-object tracking, no stall in the middle of a frame.

That is the experiment. A joke on the surface, one hard problem solved properly underneath, and a build gated by nothing but its tests. It compiles to native code, it self-hosts, and it runs DOOM. It was never meant to become a product, and it doesn't need to be one. It's finished.

Where the time actually went.

Real numbers from a commit-tracked timelog, counting active effort with idle time clamped out. That clamping has one gap: three of the agents porting DOOM stalled on usage limits while the clock kept running, so the porting-games row runs about 12 hours high. Take those off and the real total is nearer 22.

I didn't know cursed existed until bet was already built. Geoffrey Huntley reached the same idea first: a slang-keyword language, compiled through LLVM, written by directing an AI, the same way I built bet. He did it well, and he got there before me. The credit is his.

↗ghuntley.com/cursedthe original write-up

𝕏@GeoffreyHuntleyfollow the person who started it