How the site was built, for the curious, and the suspicious.
One browser, one era. This site is aimed squarely at a Macintosh IIci running Netscape Navigator 3.0 in August 1996 -- a 640x480 screen peeking over the edge at 800x600 -- while accommodating the rest of the period: Lynx in a Unix terminal, NCSA Mosaic on Windows 3.1, and similar. Everything here was built to render on all of these, but with Netscape Navigator 3 on the IIci as the bleeding edge. If a feature arrived later, it's not here.
| Browser | Netscape Navigator 3.0 -- August 1996 |
| Hardware | 1986 to 1996, 640x480 VGA |
| Doctype | HTML 2.0 -- IETF RFC 1866 |
| Extensions | <FONT>, <CENTER>, <BLINK>, and the HTML 3.2 table attributes |
| Style sheets | None -- CSS1 came four months later |
| Character set | 7-bit ASCII (RFC 20), served as Latin-1 (ISO 8859-1) |
| Named entities | < > & -- and no others |
| Images | GIF 87a/89a, baseline JPEG (ITU-T T.81) -- never PNG |
| Color | 8-bit -- 256 on screen, 216 web-safe |
| Scripting | JavaScript 1.1, and nothing it cannot run |
| Palette | Green #00FF00 on black #000000 |
| Transport | nginx -- HTTP/1.0 (RFC 1945) on port 80 |
There is no stylesheet here, and nothing that stands in for one. The look of the page is built entirely from markup.
HTML 2.0, plus Netscape. We use an HTML 2.0 doctype -- RFC 1866, November 1995 -- with the extensions a 1996 author actually reached for. Nobody wrote pure 2.0 in 1996, and neither do we.
No CSS. CSS1 was not published until December 1996, and Navigator 3 cannot read it. Every style here is a tag or an attribute.
Type by the dial, not the point. No CSS means no points, no pixels, no em. Type runs on a coarse dial -- seven sizes, one through seven, with three the default -- and you turn it with <FONT SIZE="-1"> or +1 from there. That dial is the whole of the typography here.
Layout by table, not by box. There is no float and no grid, so the page is laid out the only way the markup allows -- inside a table. WIDTH pins the column so nothing spills past 640 pixels, CELLPADDING and CELLSPACING are the only margins on offer, and ALIGN sets the images against the text: a lattice of <TD> doing the work a stylesheet would otherwise do.
The rule does the dividing. With no borders or margins to style, the section break falls to the humble <HR> -- leaned on here harder than any other tag. NOSHADE kills the engraved bevel, SIZE sets its weight, WIDTH its span. The one attribute it never wears is COLOR, an Internet Explorer invention Navigator never knew.
ASCII only. A period browser reads bytes as Latin-1 (ISO 8859-1, HTTP's default charset), not UTF-8, so the pages are plain 7-bit ASCII -- RFC 20, the standard Vint Cerf wrote in 1969 -- and anything outside it is a numbered entity. Three named entities appear in the whole site, and not one more.
Blink stays, marquee degrades. <BLINK> is a genuine Netscape tag, so on Navigator it blinks. <MARQUEE> is Microsoft's, and Navigator renders it as still text -- which is honest. Modern browsers get a small script that scrolls it, and that script checks for a method Navigator 3 never had, so it bows out cleanly and leaves the still text alone.
The pages here hold the line at the site's 1996 target. However a footnote: frames.html winks past the time-freeze, and the reason is historical.
Frames were common around the time, but the standard that blessed and subsequently condemned them was not. Netscape invented frames and shipped them in Navigator 2.0 in late 1995 -- a proprietary extension born the way <BLINK> was: one vendor, no committee, no permission asked. Navigator 3 rendered them perfectly well, so by the target for this site they could be used on any page.
The W3C wanted no part of them. HTML 3.2 -- the Recommendation of January 1997 -- standardized tables and applets and left frames on the cutting room floor. Tastemakers piled on. The usability crowd said, flatly, to "just say no." Bookmarks broke. The Back button lied. A framed page had no single URL you could point at. So, for every site that used a frame to pin a navigation bar, another that used one trapped you three scrollbars deep.
The official blessing came late, and grudging. HTML 4.0 (December 1997) finally admitted frames, but quarantined them: they were not in the main grammar, but in a separate Frameset document type, something of a sandbox for the unruly ne'er-do-wells. HTML 4.01 sealed things up in December 1999.
That's the joke in frames.html. Its doctype is not HTML 2.0 like every other page -- it is HTML 4.01 Frameset, stamped to the very month of December 1999. That is, the one page on the site wearing a date three years past the freeze, bears a <NOFRAMES> escape hatch for any browser that could not allow it.
Born without a committee, standardized under protest, and deleted within the decade. The postcard from the future of 1999 stands nonetheless as a cheeky nod to quirks of technology.
Two formats, one rule: screenshots are GIF, photographs are JPEG.
GIF LZW unpack --> palette index --> pixel JPEG Huffman --> dequantize --> inverse DCT --> YCbCr-to-RGB --> dither
GIF unpacked LZW straight into palette indices -- each byte already named a color in the table. A 68030 looked it up and painted it. That was the whole job.
JPEG was another animal -- the baseline DCT process of ITU-T T.81, the same document the world also filed as ISO/IEC 10918-1. Every 8x8 block ran an inverse cosine transform -- sixty-four integer multiplies, twice over, no floating-point shortcut -- then a conversion out of YCbCr color, then a dither down to whatever 256 colors the screen was holding. A full 640x480 JPEG could make a 25 MHz 68030 grind for seconds. A GIF the same size was up before you blinked.
And here was the joke: the screen was 256 colors. JPEG's one real advantage -- thousands of shades -- was thrown away at the last step, dithered down to the same palette a GIF carried from the start. You paid the whole decode for a fidelity the display could not show.
So it came to pass that flat color and sharp edges -- a desktop, a game, pixel art -- were GIF: lossless, instant, exact. Continuous tone? A real photograph, the thousands of shades the dithering actually needed -- this was the one case JPEG earned its keep. The true photographs here remain JPEG.
GIF was not free. It leaned on LZW compression, and LZW was patented -- number 4,558,302, granted to Sperry in 1985, later held by Unisys. For seven years nobody minded. Then, on Christmas Eve of 1994, Unisys and CompuServe sent the bill: write software that read or wrote a GIF, and you owed a royalty. The web learned it had been built on a toll road.
So the format the whole web leaned on was the one with a lawyer attached. The fix already existed -- PNG, patent-free, better in nearly every way. Its 1.0 spec landed in 1996, and the IETF stamped it RFC 2083 the next spring -- but not one browser of the era rendered it, and Navigator did not until version 4, more than a year out. Until then the toll road was the only road. GIF, tax and all.
The markup is frozen in 1996. The plumbing is a pack of cheerful anachronisms, and honesty demands we name them. nginx serves this site, and nginx did not exist in 1996 -- its first release came in 2004. A period webmaster ran NCSA httpd or Apache. We run a web server from the future and aim it at the past, and every shortcut below falls out of that one confession.
Two doors, and one of them is from 2015. A period browser knocks on port 80 and gets exactly what it expects: plain HTTP/1.0, RFC 1945, May 1996 -- period-correct to the month. No TLS, no redirect, no HSTS (RFC 6797) herding it toward a handshake it cannot finish. But the very same server block also listens on 443, and a modern browser is quietly handed TLS 1.3 (RFC 8446) and HTTP/2 (RFC 7540) -- a binary, multiplexed, HPACK-compressed (RFC 7541) protocol that Navigator could not parse if its life depended on it. Two doors, neither one redirecting to the other, so no client is ever shoved toward the protocol it can't speak. The 1996 machine never sees the modern wire; the 2026 machine never sees plaintext.
The certificate is a robot. That TLS is Let's Encrypt, issued and renewed by certbot over ACME -- RFC 8555, 2019 -- a certificate authority and an automation protocol that postdate the target by two decades. A 1996 webmaster paid VeriSign a few hundred dollars and pasted in a PEM by hand; the strongest thing he could have negotiated was SSL 3.0, never even an RFC in its day and only filed for the record, as historic, in RFC 6101. We let a cron job mint the modern article for nothing, on a ninety-day clock.
It answers on IPv6. listen [::]:80 and [::]:443 -- the site is dual-stack. In 1996 IPv6 was barely a year old on paper -- RFC 1883, December 1995 -- deployed essentially nowhere, and RFC 2460 did not revise it until 1998. A period client reaches us over IPv4 (RFC 791, 1981), as it should; a modern one may arrive over an address family that scarcely existed when the markup was written.
CGI does not run the old way. The Perl scripts in /cgi-bin/ are real CGI -- the interface the web had run since 1993, though the IETF did not formally codify it as RFC 3875 until 2004 -- but nginx has no mod_cgi and cannot fork a script itself. So every hit is passed over a Unix socket to fcgiwrap, a small FastCGI shim that does the forking on nginx's behalf. The script still reads the same REMOTE_ADDR and QUERY_STRING it would have in 1996; the road the request take to reach it is pure modern duct tape.
The directory listings are a plugin. /pub/ and /errors/ are dressed up by fancyindex, a third-party nginx module. Those period-styled index pages are generated by code that never shipped with the server and never existed in the era.
The responses cache like it's 2026. Static assets carry expires 30d -- a Cache-Control: max-age header telling your browser to sit on them for a month. Cache-Control is HTTP/1.1, RFC 2068 section 14.9, January 1997 -- a year past the cutoff. A strict 1996 server, RFC 1945 to the letter, would have sent a bare Expires date (section 10.7) and nothing more.
So the bytes are 1996 and the wire is 2026. We are honest about the markup and shameless about the transport, and the one rule we never break is that a period browser must always get something it can actually render.
Not all of the plumbing is a compromise.
Pages stitched on the fly. Every page is assembled as it is sent; NCSA httpd had server-side includes by 1994, so this one is period-honest. The header and footer that ride on every page live in one file each -- change one, change them all -- and an include drops them in.
Flags of allegiance. Every response carries a few non-standard X- headers, the convention RFC 6648 later asked the world to stop minting -- which is exactly why we keep minting them. See them yourself; they are right there in the headers:
X-Best-Viewed-With: Netscape Navigator 3.0 X-Resolution: 800x600 X-Colors: 256 X-Blink-Support: required X-Clacks-Overhead: GNU Terry Pratchett
Knock on /coffee if you doubt our priorities. The one status code on this site that is both a joke and law.
Copyright (c) 2026 Yuri Broze