The first ES5 JavaScript engine on Classic Macintosh
April 15–16, 2026 — a Power Macintosh G3 from 1998, running Mac OS 9.1, executed JavaScript inside a web browser and rendered an ASCII Mandelbrot fractal. It had never been done before.
The first JavaScript output on Mac OS 9: "Hello from Duktape on Mac OS 9!"
What Is This?
MacSurf is a web browser for Mac OS 9 PowerPC. It is built on the NetSurf engine, compiled with Metrowerks CodeWarrior 8, and runs on real Classic Macintosh hardware, with no emulation.
On April 15, 2026, MacSurf became the first browser to run a modern JavaScript engine (ES5-compliant) on Classic Mac OS. The engine is Duktape 2.7.0, a portable ECMAScript interpreter written in C89 by Sami Vaarala. It compiled on CodeWarrior 8 with zero patches to the engine source. Only configuration changes.
The Machine
Every line of code was compiled on a Power Macintosh G3 Minitower (Beige, 1998, Machine ID 510) with an aftermarket Sonnet G4 processor upgrade at 400 MHz. The beige G3 never shipped with a G4. 192 MB RAM (32+32+128 MB), 6 MB VRAM, Mac OS 9.1, CarbonLib 1.6, startup drive "Back40" on internal ATA. The Sonnet Processor Upgrade 1.4.5 extension is active in the System Folder. The machine belonged to Gary Hansen, who passed away. His G3, with Gary's own Sonnet upgrade still installed, is still compiling code and rendering fractals in 2026. This project is dedicated to his memory.
What JavaScript Can It Run?
Full ES5.1. Not a subset, not a toy. The complete language specification:
Closures, prototype chains, Array.map/filter/reduce, regex with capture groups
- Closures and higher-order functions
- Constructor functions with prototype inheritance (
instanceofworks correctly through the chain) - Array.prototype.map, filter, reduce
- Regular expressions with capture groups, flags, and global replace
- try/catch/throw with custom Error objects
- JSON.parse and JSON.stringify with nested structures
- Date arithmetic (Mac epoch converted to Unix epoch via GetDateTime)
- ES5 strict mode, Object.keys, Array.isArray
- Promise polyfill (synchronous resolution)
- setTimeout / setInterval (cooperative, event-loop driven)
Stress Test Results
All benchmarks measured on the physical G3 hardware:
| Test | Result | Time |
|---|---|---|
| 10,000-node linked list reversal | Correct | <1 ms |
| Regex email extraction | 4/4 correct | <1 ms |
| Binary search tree (15 nodes) | Correct in-order | <1 ms |
| 30×30 matrix multiply | Correct | <1 ms |
| Promise polyfill chain | Correct | <1 ms |
| Quicksort 5,000 elements | Verified sorted | 1 sec |
| 10,000-entry hash table | 10,000/10,000 | 1 sec |
| 100K string builder (array+join) | 100,000 chars | 2 sec |
| 100K Math.sqrt+sin loop | Completed | 3 sec |
| Ackermann(3,7) | 1,021 (correct) | 6 sec |
| ASCII Mandelbrot 40×20 | Renders correctly | ~2 sec |
An ASCII Mandelbrot set, computed entirely in JavaScript by Duktape on a PowerPC G3 running Mac OS 9
How It Works
MacSurf has three layers:
- The Browser (C, Carbon API, CodeWarrior 8). Handles window management, URL bar, scrolling, text rendering via QuickDraw. Links against NetSurf's five core libraries (libparserutils, libhubbub, libdom, libcss, libwapcaplet, totaling 443 source files, ~125,000 lines of C).
- The JS Engine (Duktape 2.7.0). An ES5.1 interpreter embedded as a single 3.6 MB C file. Configured for PPC big-endian, 128-frame recursion limit, no threading, no file I/O. Console.log output is captured and appended to the rendered page.
- The Proxy (Go, runs on a VPS). Strips TLS. The Mac sends plain HTTP; the proxy fetches HTTPS and returns plain HTTP. No config, no dependencies, single binary.
When MacSurf loads a page, it fetches the HTML through the proxy, strips tags for display, scans for <script> blocks, evaluates each through Duktape, captures console.log output, and appends it to the rendered content. The JavaScript runs on the Mac. Not on the proxy, not in the cloud. On the PowerPC. On Mac OS 9.
Why?
"If we can't load regular sites there is no point to this app really."
That was the moment the project pivoted from "strip HTML to text" to "run real JavaScript on a 1998 machine." The moonshot branch was created, Duktape was downloaded, configured, compiled, and producing results, all in a single overnight session.
No consumer browser has ever run ES5 JavaScript on Classic Mac OS. IE 5 shipped JScript 5 (pre-ES5) on Mac OS X. Classilla attempted SpiderMonkey on OS 9 but JavaScript was its primary crash source. MacSurf is the first stable, fully-functional ES5 engine on this platform.
fib(20) = 6765, 100K math ops in 3 seconds, ES5 strict mode, all on a 1998 Power Mac
Credits
Patrick Britton. Creator. Hardware, builds, testing, and the belief that a 1998 Mac could run JavaScript in 2026.
Claude (Anthropic). Development partner. Wrote the C code, diagnosed CW8 errors from transcribed logs, debugged crashes from photographs of a CRT monitor.
Sami Vaarala. Creator of Duktape. A C89 ES5 engine with a single-file amalgamation is what made this possible.
NetSurf contributors. The browser engine's clean C architecture and cooperative-multitasking design gave MacSurf a real engine to build on.
Macintosh Garden. The software archive that preserved CodeWarrior, ResEdit, and everything else needed to develop for Classic Mac OS in 2026.
Gary Hansen (1947–2002)
Gary Hansen was a communications lifer who rode every wave the industry threw at him. He started shooting photos and filing stories for the New Ulm Daily Journal at thirteen, landed at the Associated Press by twenty-one, covering Nixon, Bobby Kennedy, and McGovern out of the Pierre, SD bureau. By the mid-’80s had pivoted hard into the desktop publishing revolution, training thousands of employees at shops like 3M, Honeywell, and General Mills on the Mac tools that were rewriting the rules of print. He called himself “the quintessential Renaissance Man of communications,” and the résumé backed it up.
By the mid-’90s Gary had founded Digital Concepts Corporation out of his home in Edina, Minnesota, building websites, managing hosting, and doing print design and photography for a stable of clients. He ran four browsers simultaneously for cross-browser testing, kept nearly 1,700 bookmarks organized across them, and was an early adopter of everything from PageMaker to cable internet to Napster. His Power Mac G3, upgraded with a Sonnet Encore G4 processor because stock specs were never quite enough, was the nerve center for all of it.
Outside the screen, Gary was a private pilot, a certified SCUBA diver, a chess tactician, and a deeply committed motorcycle guy. He served on the board of the Minnesota Motorcycle Riders Association, designed their Freedom Review newsletter in PageMaker, lobbied for rider legislation, and eventually signed on as General Manager at Easyriders of Minneapolis, submitting a brutally honest five-page application that noted, among his weaknesses, “no tattoos.”
He was a father who named every password after his daughter Kaija, a husband to Deb, and a guy who helped everyone around him get online, get a résumé typed, or get a computer set up. He was 55 when he died in September 2002. The G3 that powers this browser was part of his world, and this project is a small way of keeping that machine, and the curiosity behind it, running.
