Skip to content

classic-vibe-mac

Write C in a browser tab, press Build & Run, and a System 7 Macintosh boots with your freshly compiled 68k application sitting on its desktop.

Screenshot of classic-vibe-mac
Editor screenshot, 28 Sep 2026classic-vibe-mac ↗

What it is

A static web page that is also a complete classic Macintosh development environment. You edit C in a CodeMirror pane and press Build & Run; the page compiles it with a WebAssembly build of the Retro68 toolchain, links it into a 68k Mac binary, writes it into a disk image, and boots Basilisk II against that image. A System 7.5.5 desktop comes up with the application on it, in about a second. No install, no toolchain on your machine, and no backend. Editing the source and pressing the button again reboots the Mac with the change.

Who built itWorks for UNDRR, the United Nations office for disaster risk reduction, and is based in Bonn. He has been on GitHub since 2011 and has a hundred and eleven public repositories, nearly all of them small browser tools built by one person: two PDF utilities, an attention-heatmap toy, a reimplementation of the Johnny Castaway screensaver, a times-tables game for a seven-to-nine-year-old. This is the largest of them by a wide margin, and the only one that required writing a compiler toolchain.

Build log

8 stages
  1. 01

    The pipeline, end to end

    Everything happens in the browser against files served from GitHub Pages: HTML, JavaScript, the WebAssembly modules, and a chunked HFS disk image. A service worker shim supplies the cross-origin isolation headers that Pages cannot set, which is what makes `SharedArrayBuffer` available for the emulator. When you press Build & Run the page hands your source to a wasm build of `cc1`, runs the four-stage pipeline — preprocessor and compiler, assembler, linker, then a converter that turns the ELF output into a MacBinary — splices a `SIZE` resource onto the result, patches a fresh copy of an HFS template with it, spawns a web worker, and instantiates Basilisk II against both the boot disk and the disk that was just built. The stated division of labour is the interesting part: JavaScript owns the network, the Mac owns rendering and the event loop. Communication back out of the emulator goes through a mounted extfs volume that the Mac sees as `:Unix:`, so `cvm_log()` calls in your C land in a file the host polls into a console pane — there is deliberately no general-purpose socket inside the Mac. An opt-in Ethernet path exists behind a URL parameter and bridges the emulator worker to a Cloudflare Durable Object relay. The shelf you choose from holds twenty-six samples, and they climb in Toolbox surface rather than in scale — one of the learnings entries is titled exactly that. They run from a window that draws a single string, through a double-buffered bouncing ball, to Glypha III: John Calhoun’s 1992 arcade game, vendored whole under the MIT licence with its original sprite art, seventeen sound effects and about six thousand six hundred lines of period C. That is the same John Calhoun whose Johnny Castaway screensaver the author reimplemented for the web in another of his repositories, which makes this the second time he has carried a piece of that work forward.

  2. 02

    The commit log has the machine as author and the human as co-author

    Two hundred and thirty-eight of the three hundred and nine commits carry a co-author trailer, and the name on almost all of them is Ken Hawkins — the repository owner. The commits were written by an agent, which then credited the person. Every commit from the May burst ends with the same block: a row of dashes, then `Co-authored-by: Ken Hawkins <khawkins98@gmail.com>`. This is the inverse of the arrangement recorded elsewhere in this archive, where a person commits and the assistant is credited alongside them; here the assistant is the author of record and the person is the collaborator. Read alongside the second fact — that a dev dependency on Anthropic’s SDK sat in `package.json` until September, and the documentation describes dispatching several agents in parallel with different briefs — it looks less like a person using a chat window and more like a person running a small orchestration layer and letting it commit.

  3. 03

    The five-reviewer red-flag pass

    The most reusable thing in the repository is a document describing the process rather than the product. Before committing to any large piece of work — anything with a multi-week estimate, anything touching infrastructure, anything adding a new architectural axis — five independent agents are dispatched in parallel, each given a different lens, and each asked to write a severity-ranked critique. The lenses are chosen from a menu: domain expert, scope and project management, security and abuse, infrastructure feasibility, legal and intellectual property, editor and user experience, compilation and runtime, hot-reload feel. The orchestrator consolidates and decides. Converging high-severity findings across reviewers are show-stoppers; converging medium findings become scope reductions; low findings become follow-up tickets. The document is explicit that three lenses is the floor and five is the sweet spot, because more than five turns consolidation into its own project.

  4. 04

    Two epics it killed, and one it approved with the estimate intact

    The same document reports three outcomes from that process, all in May 2026, and the failures are more instructive than the success. An epic for real Mac TCP/IP over a WebSocket relay was closed: three reviewers independently found three different fatal problems — the design was wrong by an OSI layer, Cloudflare’s terms of service forbid services that look like VPNs, and the browser being targeted turned out to be actively licensed shareware. The original estimate was five to ten times too optimistic. An epic for a full in-browser integrated development environment with C compilation was also closed: one phase needed an OAuth scope and a token-exchange relay, which is to say a backend, which contradicted the project’s own constraint of having none; a later phase silently assumed an in-browser HFS writer that does not exist; and the honest cost of porting the whole compiler toolchain to WebAssembly was four to nine engineer-months. It was replaced by a smaller epic that does resource-fork editing with a WebAssembly build of the resource compiler instead — described in the document as covering about seventy per cent of the emotional promise for about five per cent of the effort. That third epic went through the same five reviewers and came back approved. The pattern is worth stealing precisely because two thirds of the ideas were killed by it.

  5. 05

    A hundred thousand words of things that went wrong

    The repository carries a learnings file of a hundred and eighty-three thousand characters, organised as dated entries with one-line titles, running from the first day of the project to September. It opens with twelve stories the author flags as the ones to read first, and their titles are themselves a summary of the project’s difficulty: build the test harness early because structural checks lie; shipping to staging is the boot test because a headless environment cannot simulate the runtime; the compiler is not re-entrant; a linker script directive silently overrides symbols from input objects; when you are bypassing the garbage collector, diffing a canonical build is the highest-leverage diagnostic you have. The body of the file is around a hundred entries of the same kind, and they are specific to the point of being unusable to anyone else and invaluable to the next person who tries this: the emulator reads its model identifier as the gestalt ID minus six; the resource-fork listing tool prints its columns in one order and not the other; System 7.5.5 has no single-file public download so the boot disk had to be built from an archive; GitHub Pages cannot set the isolation headers the emulator needs; one of the emulator layers is GPL-2.0 rather than the more permissive licence that was assumed.

  6. 06

    The labels in the tag list

    For a project with three stars, the tag list is unusually revealing. Eleven of the twelve tags are named `autonomous-` followed by a date in the middle of May 2026 and a short description of what had been finished — instrumenting the vendored apps, retiring the precompiled build path, closing a particular issue, shipping a debug console, a license stress pass. They read as milestones from a run in which the agent worked on its own for a stretch and tagged as it went, and one of the learnings entries refers to an autonomous-mode run in the same terms. The twelfth tag archives a compile-server branch. There are no version releases at all: the changelog groups the history into dated milestones instead, and says so explicitly, because nothing here is versioned.

  7. 07

    Two repositories, and the one that is not the point

    The compiler toolchain lives in a sibling repository, `wasm-retro-cc`, described as a C compiler for classic Macintosh 68k compiled to WebAssembly. It is licence-compatible, has no stars, was created two days after this one, and the README is careful to say that nothing in it is specific to this project — it is Retro68’s compiler, binutils and MacBinary converter built with Emscripten, reusable on its own. Splitting it out is the correct call and also means the interesting artifact is spread across two repositories, one of which most readers will never open. The license position is worth recording too: this repository is GPL-3.0, and one of the learnings entries is about discovering that a component it depends on is GPL-2.0 when a more permissive licence had been assumed.

  8. 08

    Then, in September, the trailers were stripped

    The last substantive commit is dated 24 September 2026 and is titled “commit-msg hook to strip AI co-author trailers”. It adds a git hook that removes `Co-authored-by` lines pointing at an Anthropic address and the “Generated with Claude Code” footer, and removes the blank lines those deletions leave behind. Two details in the change are worth noting because they show the author thought about it. The hook matches on the email domain rather than on the word “claude”, so a human collaborator named Claude is not stripped. And the documentation records the side effect that setting a hooks path makes any existing hooks in the local directory stop running. The same commit removes the Anthropic SDK from the dev dependencies. Read as a sequence, the repository documents a project that began with agents as the authors of record, spent a summer being developed by them in parallel with a review process built around them, and then in September turned off the disclosure.

Adjacent records

All records →