Want to take your software engineering career to the next level? Join the mailing list for career tips & advice Click here


The original IBM PC and other classic machines emulated with JavaScript

Subscribe to updates I use pcjs

Statistics on pcjs

Number of watchers on Github 257
Number of open issues 24
Average time to close an issue 5 months
Main language XSLT
Average time to merge a PR 2 days
Open pull requests 2+
Closed pull requests 0+
Last commit over 2 years ago
Repo Created about 6 years ago
Repo Last Updated over 2 years ago
Size 406 MB
Homepage http://www.pcjs.org
Organization / Authorjeffpar
Latest Releasev1.50.4
Page Updated
Do you use pcjs? Leave a review!
View open issues (24)
View pcjs activity
View on github
Book a Mock Interview With Me (Silicon Valley Engineering Leader, 100s of interviews conducted)
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
Evaluating pcjs for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)

layout: page permalink: / machines:

  • id: ibm5150 type: pcx86 resume: 1 name: IBM PC (Model 5150) with Monochrome Display config: /devices/pcx86/machine/5150/mda/64kb/machine.xml
  • id: demoC1P type: c1p config: /devices/c1p/machine/8kb/large/machine.xml ---

PCjs Machines

Welcome to PCjs, home of PCx86, the original IBM PC simulation that runs in your web browser. It is one of several JavaScript Machines in the PCjs Project, an open-source project that includes:

All PCjs machine simulations are written entirely in JavaScript. No Flash, Java or other plugins are required. Supported browsers include modern versions of Chrome, Safari, Firefox, Internet Explorer (v9.0 and up), Edge, and assorted mobile browsers.

{% include machine.html id=ibm5150 %}

The JavaScript Machine above uses PCx86 configured with an Intel 8088 running at 4.77Mhz, with 64Kb of RAM and an IBM Monochrome Display Adapter. The machine is also available with a Control Panel featuring the built-in PCx86 Debugger. For even greater control, build your own PC. The PCx86 Documentation will help you get started.

PCx86 has steadily evolved to support more classic x86-based machines, including the IBM PC XT, the 80286-based IBM PC AT, and the 80386-based COMPAQ DeskPro 386. PCx86 fully supports the original machine ROMs, video cards, etc, and all machines run at their original speeds.

The goals of the PCjs Project are to create fast, full-featured simulations of classic computer hardware, help people understand how these early machines worked, make it easy to experiment with different machine configurations, and provide a platform for running and analyzing old computer software.


Some pre-configured machines are shown below, ready to run BASIC, DOS, Windows, OS/2, and other assorted software.

IBM PC running VisiCalc IBM PC running DONKEY.BAS IBM PC XT w/EGA, Windows 1.0 IBM PC XT w/CGA, Windows 1.01 IBM PC XT w/EGA, Windows 1.01 IBM PC AT w/EGA, OS/2 1.0 COMPAQ DeskPro 386, Windows/386 IBM PC AT w/EGA, Windows 3.0 IBM PC AT w/VGA, Windows 3.1 COMPAQ DeskPro 386, Windows 95 IBM PC w/MDA, CP/M-86 Microsoft Adventure (1981) Executive Suite (1982) Zork I (1982) Adventures in Math (1983) Rogue (1985)

There are many more PCx86 Demos, including an IBM PC with Dual Displays demonstrating early multi-monitor support, and multiple IBM PC XT machines running side-by-side with CGA Displays and EGA Displays.


Below is the OSI Challenger C1P, another simulation in the PCjs Project. It simulates Ohio Scientific's 6502-based microcomputer, released in 1978. More details about this simulation and the original machine are available in the C1Pjs Documentation.

{% include machine.html id=demoC1P %}

Developer Notes

The PCjs repository on GitHub contains everything needed to run PCjs computer simulations. All the PCjs emulators run in any modern web browser, with or without a web server, and examples are provided for both local and remote operation.

The project includes:

The bundled web server is not strictly required. Any web server (Node, Apache, Nginx, etc) that can serve the necessary JavaScript files to your browser will work. However, instructions for doing that are beyond the scope of this introduction.

In fact, you can run PCjs simulations without a web server at all, using the file: protocol instead of http:. However, most of the machine configurations require additional resource files (ROMs, disk images, etc), which are included in the project, but unless all the resource files are moved into a single directory (as they are in these Examples), your browser will probably be unable to load all of them, due to security restrictions. Using the bundled web server is the preferred solution.

The project includes a large selection of disk images, and a powerful DiskDump utility that runs on both the client and server, featuring a command-line interface (CLI) and web server API. Originally created to dump existing disk images as JSON, DiskDump has evolved into a full-featured disk image generator, capable of creating PC-compatible diskette and hard disk images from either lists or directories of files (including all subdirectories).

Installing PCjs with Node

The following instructions were originally written for OS X. However, users of other operating systems should have no problem following along. There are some prerequisites:

  • Node with NPM (download an installation package for your OS from nodejs.org)
  • Git (included with OS X Developer Tools; separate download required for Windows)

Some additional (optional) tools are also recommended:

  • Python (included with OS X; separate download required for Windows)
  • GitHub (useful for getting Git set up on Windows; also available for OS X)

Once you have the prerequisites, open a command-line window, cd to the directory where you'd like to install PCjs, and type the following commands:

git clone --recurse-submodules https://github.com/jeffpar/pcjs.git
cd pcjs
npm install --production
node server.js

Now open a web browser and go to http://localhost:8088/. You're done!

The current version of Node (0.10.32 at the time of this writing) should work fine, but version 0.10.26 is what's been used to develop and test PCjs so far.

Also, server.js was originally written using Express v3. Since then, Express v4 has been released, but the npm install command above will make sure that v3 is installed locally.

The plan is to eventually move development to a newer version of Node, and migrate the PCjs server to a newer version of Express; there's no desire to remain stuck in the past (well, ignoring the fact that PCjs is the quintessential stuck in the past project), but there's also no urgency to update.

Installing PCjs with Jekyll

PCjs can also be used with Jekyll and the Ruby WEBrick web server, now that a jekyll branch has been created to work with GitHub Pages. This is how the project is currently set up at pcjs.org.

This isn't going to be a Jekyll How To guide, because that would unnecessarily repeat all the information available at GitHub Pages. But we'll summarize the basic steps, which replace the npm and node steps above.

To install Jekyll for use with PCjs:

  1. Install Ruby (on OS X, it should already be installed)
  2. Install Bundler (on OS X, run sudo gem install bundler)
  3. Checkout the jekyll branch, since only that branch contains all the Jekyll-related files
  4. Create a Gemfile containing gem 'github-pages' (this is already checked in)
  5. Run bundle install (GitHub Pages alternatively suggests: bundle exec jekyll build --safe)
  6. Run bundle exec jekyll serve to start the web server

Now open a web browser and go to http://localhost:4000/. You're done!

Some useful Jekyll server options include:

bundle exec jekyll serve --host= --config _config.yml,_developer.yml

The --host option makes it possible to access the web server from other devices on your local network; for example, you may want to run PCjs on your iPhone, iPad, or other wireless device. And by adding _developer.yml, you can override the Jekyll configuration defaults in _config.yml. Using development (non-production) settings in _developer.yml is analogous to running the Node web server with certain development options; see Debugging PCjs.

GitHub Pages says you can run jekyll serve instead of bundle exec jekyll serve, but with the addition of more gems to Gemfile (eg, jekyll-sitemap), running jekyll serve may trigger dependency errors on some systems. bundle exec jekyll serve should always work.

Don't see any YML files in the root of your project? You probably forgot to switch to the jekyll branch:

git checkout jekyll

Last but not least, run bundle update periodically to keep Jekyll up-to-date.

Building PCjs

Unlike a typical project, where you have to build or configure or make something, PCjs is ready to run. That's because both the compiled and uncompiled versions of the PCjs emulation modules are checked into the project, making deployment to a web server easier.

However, in order to build and test PCjs modifications, you'll want to use Gulp and the Gulp tasks defined by gulpfile.js. If you already ran npm install --production as described above, then you should re-run it without the --production option:

npm install

to get all the development dependencies, including Gulp. You'll probably also want to install the command-line interface to Gulp. You can install that locally as well, but it's recommended you install it globally with -g; OS X users may also need to preface this command with sudo:

npm install gulp-cli -g

Now you can run gulp anywhere within the PCjs project to build an updated version. If no command-line arguments are specified, gulp runs the default task defined by the project's gulpfile; that task runs Google's Closure Compiler if any of the target files (eg, pcx86.js in the versions directory) are out-of date.

Using the JavaScript-based Closure Compiler

The latest gulpfile now compiles all PCjs machine modules using Google's JavaScript-based Closure Compiler.

Running gulp should build a complete set of compiled machine scripts in the versions directory. Individual machines can be compiled as well (eg, gulp compile/pcx86).

Using PCjs

From The Browser

The PCjs Node web server is little more than a file/directory browser for the PCjs project, plus a collection of APIs.

If a URL corresponds to a PCjs project folder and no index.html exists in that folder, the Node web server loads an HTML template (common.html) and generates an index.html for that folder.

The contents of the index.html will vary depending on the contents of the folder; for example, if the folder contains a README.md, then that Markdown file is converted to HTML and embedded in the index.html. Similarly, if the folder contains a machine XML file, that is embedded as well.

To work well with both the Node and Jekyll web servers, all Markdown files containing one or more embedded machines should contain a Jekyll Front Matter header that describes the machines. For example, here's the header from the pcjs.org home page (index.md):

layout: page
permalink: /
  - id: ibm5150
    type: pcx86
    resume: 1
    name: "IBM PC (Model 5150) with Monochrome Display"
    config: /devices/pcx86/machine/5150/mda/64kb/machine.xml
  - id: demoC1P
    type: c1p
    config: /devices/c1p/machine/8kb/large/machine.xml

Then the following lines are inserted at the points where the machines should appear:

{% include machine.html id="ibm5150" %}
{% include machine.html id="demoC1P" %}

For more information on all the machine options supported in a Markdown file, see the project's Jekyll include file machine-engines.html.

From The Command-Line

The PCx86 client app can also be run from the command-line mode using Node, making it possible to script the application, run a series of automated tests, etc:

cd modules/pcx86/bin
node pcx86repl.js

The pcx86 script in modules/pcx86/bin loads all the PCx86 browser scripts listed in machines.json and then starts a Node REPL (read-eval-print loop). The REPL handles a few special commands (eg, load, quit) and passes anything else to the PCx86 Debugger component. If no Debugger component has been created yet, or if the Debugger didn't recognize the command, then it's passed on to eval(), like a good little REPL.

Use the load command to load a JSON machine configuration file. A sample ibm5150.json is provided in the bin directory, which is a JSON-ified version of the machine.xml displayed on the pcjs.org home page.

The command-line loader creates all the JSON-defined machine components in the same order that the browser creates XML-defined components. You can also issue the load command directly from the command-line:

node pcx86repl.js --cmd="load ibm5150.json"

In fact, any number of --cmd arguments can be included on the command-line. A batch file syntax will eventually be added, too.

When a PCjs machine runs in a browser, an XML machine configuration file is transformed into HTML with a set of DIVs for each component: an object DIV whose data-value attribute provides the initialization parameters for the corresponding component, along with a set of optional control DIVs that the component can bind to (eg, a Run button, or a visual representation of DIP switches, or whatever).

When a PCjs machine is run from the command-line, there is no XML, HTML, or DIVs involved; this is basically a headless version of the machine, so there is no simple way to view its video display or interact with its keyboard, mouse, etc. You have to use Debugger commands to dump the machine's video buffer.

Since I was not inclined to add XML support to my Node environment, this has created some divergence between client and server operation: PCjs machines on the client supports only XML machine configuration files, whereas PCjs machines on the server supports only JSON machine configuration files.

I haven't decided whether I'll add support for JSON configuration files to the client, or add some XML-to-JSON conversion to the server, or both.

Debugging PCjs

NOTE: The following information assumes you're running Node as your local web server, not Jekyll. You can certainly debug PCjs while running Jekyll (ideally with --config _config.yml,_developer.yml), using http://localhost:4000/ and your favorite web browser's Developer Tools, but none of the special server or client features discussed below will be available.

Server Components

To help test/debug changes to PCjs server components (eg, DiskDump, HTMLOut), you can start the server with some additional options; eg:

node server.js --logging --console --debug

The --logging option will create a node.log that records all the HTTP requests, --debug will generate additional debug-only messages (which will also be logged if --logging is enabled), and --console will replicate any messages to your console as well.

If you want server.js to use a different port (the default is 8088), set PORT in your environment before starting the server:

export PORT=80

or add --port to your command-line:

node server.js --logging --console --debug --port=80

A complete list of command-line options can be found in server.js.

Client Components

A special command parameter (gort) can be appended to the URL to request uncompiled client source files, making the PCjs emulators much easier to debug, albeit much slower:


The gort=debug command is unnecessary if the server is started with --debug; the server always serves uncompiled files when running in debug mode.

Conversely, if the server is in debug mode but you want to test a compiled version of PCx86, use:


and the server will serve compiled JavaScript files, regardless whether the server is running in debug mode or release mode.

Another useful gort command is gort=nodebug, which is like gort=debug in that it serves uncompiled files, but it also sets the client-side DEBUG variable to false, disabling all debug-only runtime checks in the client and allowing the simulation to run much faster (although not as fast as compiled code):


Regrettably, the gort command Klaatu barada nikto is not yet recognized. Fortunately, there are no (known) situations where PCjs could run amok and destroy the planet.

Other parameters that can be passed via the URL:

  • aspect: a numeric value >= 0.3 and <= 3.33 modifies the default aspect ratio of a machine's screen on the specified page; e.g.:

  • autoMount: overrides the machine's diskette autoMount settings; eg:

    http://localhost:8088/?autoMount={A:{name:"PC-DOS 1.10"}}
  • autoStart: true allows all machines to start normally, false prevents all machines from starting, and no prevents all machines from starting unless they have no Run button; e.g.:

  • drives: overrides the machine's hard drive settings; e.g.:

    http://localhost:8088/?drives=[{name:"10Mb Hard Disk",type:3,path:"/pcjs-disks/pcx86/drives/10mb/PCDOS200-WIN101-EGA.json"}]
  • autoType: a string of keys to inject into the machine after booting; e.g.:

  • mobile: true or false to override PCjs' mobile browser detection, which affects things like soft keyboard layout; e.g.:

  • resume: a numeric value (0-3) overrides a machine's resume setting; e.g.:

  • softKeys: true to enable the machine's soft keyboard (if included); e.g.:


More information about the resume attribute is available in the documentation.

Updating PCjs


To start developing features for a new version of PCjs, here are the recommended steps:

  1. Update the version numbers in package.json and machines.json
  2. Run the gulp version task to bump the version in all the machine XML files
  3. Make changes
  4. Run gulp to build new versions of the apps (eg, /versions/pcx86/1.x.x/pcx86.js)

You might also want to check out the blog post on PCjs Coding Conventions.

You may also want to skip step #2 until you're ready to start testing the new version. Depending on the nature of your changes, it may be better to manually edit the version number in only a few machine XML files for testing, leaving the rest of the XML files pointing to the previous version. Run gulp version when the new version is much closer to being released.


In the course of testing PCjs, there may be stale index.html files that prevent you from seeing application updates, changes to README.md files, etc. So before running Node, you may want to touch the default HTML template:

touch modules/shared/templates/common.html

The HTMLOut module compares the timestamp of that template file to the timestamp of any index.html and will regenerate the latter if it's out-of-date.

There's a TODO to expand that check to include the timestamp of any local README.md file, but there are many other factors that can contribute to stale index.html files, so usually the safest thing to do is touch the common.html template, or delete all existing index.html files, either manually or with the modules/htmlout/bin/delete_indexes.sh script.


The PCjs Project is now an open-source project on GitHub. All published portions are free for redistribution and/or modification under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

You are required to include the following copyright notice, with a link to pcjs.org:

PCjs 2012-2018 by Jeff Parsons (@jeffpar)

in every source code file of every copy or modified version of this work, and to display that notice on every web page or computer that runs any version of this software.

See LICENSE for details.

More Information

Learn more about the PCjs Project and PCx86. To create your own PCx86 machines, see the PCx86 Documentation for details.

If you have questions or run into any problems, feel free to tweet or email.

pcjs open issues Ask a question     (View All Issues)
  • about 4 years PCjs 80386 boot hangs
  • about 4 years Tiny386BSD floppy doesn't boot
  • over 4 years Win95 won't load
  • over 4 years Win95 MS-DOS prompt: keyboard don't work after a while
  • over 4 years Two BIOS beeps on 386 machine
  • over 4 years "emm386 off" then "emm386 on" don't work
  • over 4 years 386 SS has wrong behavior after reset
  • over 4 years Create boot disks for DOS versions >= 5
  • over 4 years Add READMEs to all web-accessible folders
  • over 4 years Windows 3.1 (VGA) color palette is incorrect
  • over 4 years OS/2 1.x serial mouse driver does not work
  • over 4 years OS/2 1.1 fails to start correctly
  • almost 5 years Implement option to switch FPU to 80-bit precision
  • about 5 years FEATURE: Another 386 CPU architecture (C&T Super386)
  • over 5 years Checkout and integrate Gitter.im
  • over 5 years Documentation on how to create an empty disk image from sources
  • over 5 years Support JSON machine definition files
  • over 5 years PCjs runs on IE8 despite the lack of canvas support
  • almost 6 years CAPS-LOCK still an issue on Windows (Chrome)
  • almost 6 years Feature: floppy activity LED and track display
  • about 6 years IBM Diagnostics 2.20 erroneously reports 3.5-inch external diskette drive
  • about 6 years The "clean" Grunt task doesn't work on Windows
  • about 6 years FileDump needs a "map" option (both API and command-line)
  • about 6 years XMLHttpRequest.send() doesn't return if server is dead
pcjs open pull requests (View All Pulls)
  • Updated things
  • Changed some parts
pcjs latest release notes
v1.50.4 Assortment of PCx86 Fixes

I haven't been tagging releases as often as I should. Consider this a roll-up release which:

  • Fixed an HSFLOP VxD bug in Windows 95 by delaying FDC interrupts
  • Fixed CAPS-LOCK management for Windows-based browsers
  • Disabled speaker clicking on COMPAQ machines (it was annoying and intermittent)
  • Added support for CTRL-ALT-PLUS and CTRL-ALT-MINUS (special COMPAQ keys)
  • Delayed ALT notifications until at least one other key is pressed
  • Fixed a Parallel Port bug that locked up DOS when CTRL-P was pressed
  • Improved 8042 keyboard support for WIndows 95 (resolves dropped/hung keys)
  • Added support for mounting disk images via third-party URL (CORS permitting)
  • Archived a few more disks (eg, CP/M-86 1.0, QEMM-386)
  • Archived a new early COMPAQ DeskPro 386 ROM, now used by the COMPAQ EGA configurations
TI-55 TI-55 Programmable Calculator

Building on the PCjs TI-57 Emulator, the TI-55 Programmable Calculator can now be emulated as well.

See this blog post for details.

TI-57 TI-57 Programmable Calculator

The new TI-57 Programmable Calculator emulator is the latest addition to the PCjs Machines collection. It emulates a TMS-1500 chip at the register level, and uses an original TI-57 ROM, providing about as perfect a simulation as you can get.

Even though it's my smallest JavaScript-based emulator to date, it's still packed with goodies:

  • Faithful speed and LED simulation
  • Built-in disassembler and mini-debugger
  • Works on desktop and mobile devices
  • Saves and restores state automatically

Since it saves your calculator's state whenever the web page is closed, and restores that state when the page is reopened, you shouldn't lose your work. However, just like a real calculator, if you turn it off and on again (using the Power button), then everything will be reset.

The mini-debugger is connected to the Diagnostics window, so you can type commands there as well. As the ? command will tell you, available commands include:

b[c]            break on condition c
bl              list break conditions
g [addr]        run (to addr)
h               halt
r[a]            dump (all) registers
t [n]           step (n instructions)
u [addr] [n]    disassemble (at addr)

Clicking the Halt button is equivalent to the h command, the Run button is equivalent to g, and the Step button is equivalent to t. The Reset button has no equivalent; it's just a shortcut for cycling the Power button. If you use the t command to step through a large number of instructions, the Step button becomes a Stop button, allowing you to terminate the step operation.

In addition to supporting touch and mouse events, keyboard shortcuts are supported, too. The set of shortcuts is configurable, based on the button map passed to the emulator. The default map looks like this:

"map": [
    ["2nd",  "inv",  "lnx",  "\\b",  "clr"],
    ["lrn",  "xchg", "sq",   "sqrt", "rcp"],
    ["sst",  "sto",  "rcl",  "sum",  "exp"],
    ["bst",  "ee",   "(",    ")",    "/"],
    ["gto",  "7",    "8",    "9",    "*"],
    ["sbr",  "4",    "5",    "6",    "-"],
    ["rst",  "1",    "2",    "3",    "+"],
    ["r/s",  "0",    ".",    "+/-",  "=|\\r"]

Any button that corresponds to a single character can be triggered by typing that character (eg, + for the Add button). Escape sequences are allowed, too; for example, \\b represents Backspace, which will trigger the CE button. Buttons can have multiple mappings, too; for example, the Equals button can be triggered by typing either = or the Enter key.

The LED display is configurable as well. The default JSON properties for the LED Device look like this:

"display": {
    "class": "LED",
    "type": 3,
    "cols": 12,
    "rows": 1,
    "color": "red",
    "bindings": {
        "container": "displayTI57"

So if you prefer green or blue digits, change the color property. A backgroundColor property is supported, too, but if it's omitted, a transparent background is used.

All properties listed in a configurations overrides array may be overridden with a URL parameter. Currently, that includes:

  • cyclesPerSecond (default speed is 650000)
  • color (default LED color is red)
  • backgroundColor (default LED background color is none, for a transparent background)

So, for example, this URL loads the TI-57 with green LEDs.

Since this emulator is still hot off the press, don't be surprised if there are still a few lingering bugs. If you run into any, or you have a browser or device where it doesn't work as expected, send me a note. If your web browser is old though, please try a newer browser first.

Other projects in XSLT
Powered by Autocode - Instant Webhooks, Scripts and APIs
Autocode logo wordmark