A lava lamp, written in a bedroom in 1998 for a contest neither of us expected to place in. Second out of however many. Rebuilt for the GPU twenty-eight years later because the original still ran.
I was rooming with Brett Camper (later a co-founder of Mapzen, these days a director of software engineering at Snap). What we had in common then was graphics programming, which mattered a lot because nobody else we knew wanted to do it.
In late 1998 we found a lava lamp round of Mincus' programming
contest, a recurring effect-coding challenge run off a personal page
at cyberenet.com/~mincus/programming/contest/, in the era when
that was a completely normal place for a competition to live. We both decided
to enter, retired to our respective rooms, and wrote our entries separately.
Mine started life in November as Blop Lamp, which is why
the source still calls its metaballs blops. There is a BLOP struct
and a BlopMove in the 2002 code, and now in the JavaScript port,
and in the shader above. A three-a.m. placeholder name from 1998 has outlived
every platform it was written for.
Both entries were DOS, mode 13h, in Watcom C. That is 320 by 200 pixels stretched across an entire screen, so the pixels are enormous, which is the whole problem. A lava lamp is a smooth curved silhouette and those are hard square blocks, and at that size you cannot not see the staircase.
I had Michael Abrash's Graphics Programming Black Book and looked up how to draw antialiased lines, so the outline could be generated procedurally and come out smooth. Brett went the other way: ordinary Bresenham lines, then blur the result as a postprocess. Same destination, opposite ends: get it right when you draw it, or draw it rough and fix it afterwards.
The reference for both of us was Brett's actual lava lamp, sitting in the apartment. Not just the shape, but how the blobs move and how they are lit. They are brighter at the bottom, because the bulb is at the bottom. Most simulated lava lamps disregard this entirely, and it is the single thing that makes a fake one look fake.
Brett's came out gold with red blobs. Mine is the blue one (the same blue still running at the top of this page).
I also tried to model refraction through the glass, and abandoned it. It
looked bad, and I did not know the first thing about Fresnel interactions at
the time. The attempt is still in the surviving DOS source, commented out,
annotated /* neat but wrong */, which is the correct verdict.
I took second. Brett took third. First place went to a demo of refracting metaballs that did not especially look like a lava lamp.
To be fair, it looked better than mine did. Transparent spheres with a real refractive index, properly refracted. The only thing it had in common with a lava lamp was the metaballs.
Go figure.
The judging comments on my entry, which I recorded at the time with visible disgust, were: "Good lighting. Good movement. Good Blobs." Lighting, movement and blobs are the three things I took off the lamp on the table.
We talked about those lamps for years afterwards.
We were both big fans of Jerkcity. DUH LAMPS reads exactly like a line out of the comic, which is the entire justification and remains sufficient.
Brett kept porting his. It has followed him onto every new platform he has picked up since. His words, in 2013: "the lavalamp is like my standard new platform thing." There is a JavaScript and WebGL version of the gold one.
I last touched mine in 2002, left it alone for twenty-four years, and then did all of it at once.
The 2002 Windows build (a port of the DOS original onto TinyPTC, a minimal framebuffer library for 64k intros) still launches on Windows 11 and animates correctly. That is a strange thing to discover about a twenty-four-year-old binary, and it made the rest of this hard to resist.
Reading it back turned up a bug that had been shipping the whole time. Every
buffer is char, which is signed on MSVC, so the blob accumulator's
saturation test can never fire and the compositing colour-key treats any byte
over 127 as transparent. The result is that the densest part of every blob drops
out and you see dark cores with bright rims. It was never meant to look like
that, and it is a large part of why it looks the way it does.
There is now a byte-exact JavaScript port verified against the original C at frames 1, 100 and 1000, and the GPU rebuild above, which computes everything in the original 320x200 coordinate space and treats resolution purely as a rasterization concern.
The DOS source survives too, and it is the actual 1998 file rather than a reconstruction: the copy I work from is byte-identical to one dated 28 November 1998, sitting in a Watcom source directory beside its own predecessors. The build order is legible from the timestamps alone, four versions across six days, ending two days before the entry went in.