Web Platform Adventures & PC Archeology

I recently ported the Basilisk II Classic Macintosh emulator to run in a web browser. I've been hoping to get it running for some time, and previously made an attempt back in 2013, before switching to focus on the PCE emulator. Since then browser technologies have advanced, and I've learned a lot more about emulation (in part by making a simulated computer of my own). The Basilisk II port is the culmination of both of these things. But enough about me, let's get into the gory technical details of how it works.

This post has been updated to use the Reason 4 syntax, and to account for API changes in Reason React. It is up-to-date as of April 2019. A Traditional Chinese translation of an older version of this article is available here.

Reason is a statically-typed functional programming language from Facebook which can be compiled to Javascript. Reason React is a wrapper for React which makes it easy to use from Reason.

We're going to build a small single page web app to put Reason React through its paces. The app will display a list of top Reason-related Github repos. It's a small enough task that we can complete it in a few hours, but also has enough complexity that we can kick the tires of this new language. This tutorial expects no existing knowledge of Reason, though a basic familiarity with static types would be helpful.

Update: Reason React now has a built-in routing feature which you can use instead of the library described in this post. However, if you can't use pushState routing (eg. because your app uses completely static hosting), the technique described in this post still works fine.

In my previous tutorial about Reason React, I covered most of the elements one might need for a typical web app, but one I left out was routing, so this is a quick guide to adding client-side routes to your Reason app.

We're going to use a library called Director, which is a simple and mature routing library for Javascript. We're actually going to install a version of the package called bs-director which also contains bindings to Reason/BuckleScript, which means we can use it easily from our Reason code.

The Internet Archive recently added the original Macintosh to the list of classic computers of which they provide emulation, so you can run their archive of software titles in your browser, without installing anything. This is great because it provides the same level of accessibility and convenience to emulation as you'd expect of playing a media file or viewing a document.

When you start up the emulated computer on these pages of the Internet Archive, you're running the PCE emulator, originally a piece of software intended to run natively on desktop operating systems, which has been adapted and recompiled to run in your web browser. As I did the initial work of porting this emulator to the browser (back in 2013), I thought it would be worthwhile to provide a run-down of the tools and hacks which made this possible.

This post is from a series I'm writing in which we'll learn how computers work, by writing a computer simulator in Javascript. However, I figured an explanation of binary and hexadecimal numbers is useful enough by itself, so here it is!

Before explaining how computers load data into their working space and process it, it's valuable to understand binary and hexadecimal numbers. This is because computer hardware only understands binary values due to the physical characteristics of the electronic circuitry used to implement them. I won't go further into explaining the reasons why computer hardware works with values in binary form, but you can read more about it here.

So what is binary? Binary is a 'base-2 number system'. But what does that mean?

Update: Some time after I wrote this post, Airbnb published their excellent enzyme library which does all the stuff described in this post and a lot more. You should definitely look into using it!

The React TestUtils shallow rendering feature allows us to test React components in true isolation from other component classes, and removes the need for a DOM in the test environment. It does this by allowing us to test the return value of a component's render method, without instantiating any subcomponents.

A basic example of how it can be used, assuming we're testing a component called <Page />:

It's somewhat difficult to find instructions on how to successfully install Pygame for Python 3 on Yosemite. The front page of the Pygame website has a link which appears to point to installation instructions, but it is broken.

A bunch of people have emailed me about getting Hypercard stacks running under emulation. Here is a pretty easy guide to running a Hypercard stack on a recent Mac (eg. running Mavericks, Mountain Lion, etc):

In a recent discussion on Hacker News about emulators being ported to the browser, I drew attention to my own project, PCE.js, which emulates a Macintosh Plus and an IBM PC/XT. Some of the questions brought up included why someone would undertake such a project, and also the legal considerations of including the software ROM required to boot the machine.

So, why port emulators of outdated computers to the browser? Well, to start with, I feel very strongly about the importance of learning from the past – not making the same mistakes again and again due to a lack of historical perspective. I was really inspired by Bret Victor's talk at the DBX conference, in which Bret demonstrated a bunch of technologies from the 1970s which attempted to solve problems that we're still wrestling with today. It's a great talk, and it precipitates the question; why haven't we figured this stuff out yet? Why do today's 'solutions' feel lame in comparison to these prototypes from several decades ago? If anything, it seems like we've gone backwards. The great past ideas Bret mentions, like Sketchpad, NLS, and Smalltalk, should inspire us to aim higher as we create the future.

Similarly, lots of great thinking and design can be found in old systems. The original Macintosh, with influence from the Xerox Alto, solved lots of user interface issues which people are still failing to think about today. A trivial example is that Mac OS, in 1984, had considered ‘angle of escape’ in its drop down menus. That is to say, menus don’t close when the mouse cuts a corner on the way to a submenu. It seems minor, but it’s something which Windows didn’t fix until 2001 (Windows XP), and plenty of web apps still do wrong to this day. The awesome usability and simplicity of the original Mac is something which should be available as a working, interactive demo to the newest generation of designers, makers and creators.

I've just completed porting Hampa Hug's excellent PCE emulator to run in the browser, using Emscripten. I've mainly focused on the pce-macplus build. This is pretty awesome because it means you can run classic Mac OS in the browser. Check it out: PCE.js - Classic Mac OS in the browser.

I've also got the pce-ibmpc build working (emulating an IBM compatible, up to a 286 CPU), and and pce-atarist, an Atari ST emulator also, with browser demos coming soon for each.

Emscripten is an awesome tool for porting existing native codebases to the browser. There are a bunch of cool projects using it to port graphical applications such as games and emulators, especially those which already use the SDL library as a cross-platform video, sound and I/O abstraction. Leveraging the fact that the SDL abstractions provide portability across different OS platforms means that by implementing of parts of SDL in Javascript and compiling the code via Emscripten, the browser can become (with some caveats) another SDL target platform. However, Emscripten's SDL 'shims' are still very much a work in progress, and in a current project of my own (porting a classic Mac OS emulator), I've run into some parts where I've had to fill in the gaps myself.

Specifically, if you're finding your SDL-based, Emscripten compiled app is failing to render to the canvas, the issue may be that the app is trying to use the incomplete SDL_CreateRGBSurfaceFrom method to create an SDL surface from a buffer of pixels.

The following log message appearing in the Javascript console is a possible giveaway:

I decided to install and play around with Pygame today, mainly as an excuse to write some Python for a minor departure from all the Javascript/Coffeescript I've been writing lately. Unfortunately the process wasn't entirely frictionless, due to Pygame not yet accounting for Apple's move to XQuartz as the recommended X11 implementation for Mac OS as of 10.8 Mountain Lion. As a result I ran into some compilation errors while Pygame was building it's native extensions, which fortunately were not too hard to fix as I had some familiarity with changes to X11 on Mountain Lion.

A while back I restyled Hacker News using the Stylebot extension for Chrome. Initially I just wanted to apply a fixed width, as the site's fluid layout can result in some very long lines on a large/wide display.