Patrick Collins
6 min readJun 20, 2023

--

How to put NES games on Bitcoin with recursive Ordinal inscriptions.

A few days ago, I saw this tweet, and responded:

I started off by inscribing the JSNES emulator along with its license. The next task was to build the supporting application code to launch the emulator, making Web Audio API available for sound playback, as well as allowing keyboard interaction to be properly forwarded to the emulator for player 1 and 2.

some of the code that knows whether to send keyboard input to player 1 or player 2’s controller “port”

I created a keyboard configuration page allowing you to customize the keys you want for player 1 or player 2. As I wanted it to be somewhat comfortable for two people to play multi-player games simultaneously with one keyboard, I decided to set the keyboard defaults to this:

But you can change the keys to whatever you want in the control setup screen. Just click on any of the assigned keyboard keys, you will see that key flash, and you can change it by pressing whatever key you want it to be. Your customized key choices are persisted in the browser’s local storage so it should maintain your configuration across multiple sessions of different games.

Next after that, I implemented the Gamepad API, so you can configure which gamepad is assigned to which player, and similarly with the keyboard customization, you can customize the gamepad buttons to your liking, in case you are using a non-standard joystick that has a different layout. Though the default gamepad button configuration should match most gamepads similar to how the NES controllers were originally laid out.

If you see a message that no gamepads are detected, you just need to press a button on your gamepad and it should find them.

So, the inscription id for JSNES and its license is: 3a4575b2a8fe6e7968146f290d494c2346d40ff692314050babcaa7268347f4bi0

the inscription id for the application code I wrote is: 89aaae01a47dd2d26f13513a797d99612db4b504412bbb2ac94e0c39e1c80369i0

the inscription id for the UI stylesheet is: f90c74f6a2f4cf6ba73312b444596c4f34641d72ba9dda049d26751ee1a908e8i0

and lastly, a cute little “favicon” asset for the browser tab: 0e377734f883a5abd9a89478facc028b747d6766a11de4effc2990fc8bc81d4ci0

Putting all of this together, inscribing your own playable 8-bit NES game is incredibly simple! I will demonstrate by creating an inscription for LJ65 (formerly known as Tetramino), a Tetris clone: https://tetris.wiki/LJ65.

Before doing anything, one of the things the application code does is, it looks for an HTML element that has the attribute id="cover" and when it finds this, it will take it and inject it onto the initial title screen. Again, a title screen of some sort is necessary because the Web Audio API requires a user interaction to allow sound to start playing.

So I first have to inscribe the “box art” for LJ65, and that inscription id is: 6d4d193a29b18ad4b9be4321bf70fbe84e3e950270d5d66d13cc91fa874ada03i0

Alternatively that image could have just been base64 encoded and put directly into the HTML, but since this post is all about recursive inscriptions, I just decided to do everything recursively. Also, the cover does not have to be an <img> it can be whatever you want, as complex as you want it to be. For example, you could make an <iframe> that references another inscription that is an animating 3D model or whatever you want. All you have to do is make sure that you give the element aid="cover" attribute.

First, we will have our .html file that should look like this:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="type" content="game/NES" />
<title>LJ65 [NES]</title>
<link rel="stylesheet" media="screen" href="/content/f90c74f6a2f4cf6ba73312b444596c4f34641d72ba9dda049d26751ee1a908e8i0" />
<link rel="icon" type="image/png" href="/content/0e377734f883a5abd9a89478facc028b747d6766a11de4effc2990fc8bc81d4ci0" />
<body>
<img id="cover" src="/content/6d4d193a29b18ad4b9be4321bf70fbe84e3e950270d5d66d13cc91fa874ada03i0" />
<script type="text/javascript" src="/content/3a4575b2a8fe6e7968146f290d494c2346d40ff692314050babcaa7268347f4bi0"></script>
<script type="text/javascript" src="/content/89aaae01a47dd2d26f13513a797d99612db4b504412bbb2ac94e0c39e1c80369i0"></script>
<script>
const rom = ... // <-- base64 encoded string containing the rom image goes here.
insertCartridge(rom);
</script>
</body>
</head>
</html>

Quick note: If you look near the top of the HTML, I have added a meta tag with content=”game/NES” with the intention of helping the indexers of ordinal explorers recognize that 1) it’s a game, and 2) in the future, if explorers offering the ability to filter by game type, they can look for NES but as of right now, that’s really not going to do anything.

So back to the HTML… We’ve set the page title, loaded the stylesheet, the favicon, the cover image, the JSNES emulator, and the application code, and then…

This is almost everything we need to get it working. If you look, the rom variable is not yet assigned. We need to set that variable to a base64 encoded string of the actual ROM file. The public domain LJ65 ROM file can be found and downloaded here. As far as encoding it, there are many different approaches for doing that, but one of the easiest ways (to me) is just on the unix command line by typing:

base64 /path/to/rom | tr -d '\n'

If you use a text editor like vim, you can just read the output of that command directly into the html file:

entering the command to base64 encode the rom DIRECTLY into vim

and now, as you can see below, we have our base64 encoded rom variable set, ready to be passed into the application code’s insertCartridge() function.

The last thing I should note is, in the spirit of modularity, I also inscribed separate functionality to allow future inscribed games to optionally (by including the recursive inscription) let the user play ROMs that they have locally on their system. Since one MUST be careful about what they put on the blockchain for legal reasons, I figured it would be nice to make it still possible to play actual Nintendo classics, while making use of the work I did with customizable multi-player controls. That is, if the inscriber wants that functionality.

So, if you want to allow your inscribed NES game to open local ROM files, you will also want to include another script tag prefixed with /content/pointing at inscription id: 31914136d569ffbfd24241bb5af43d98e89c185fbd1d0254a5252ad6c3998729i0

Once that script has been loaded, when the application code launches and you see the cover image, you can press: CTRL + O, and an open file dialog window will appear and you then can select any .nes ROM file and click the start button (or if you prefer, press your gamepad’s start button) and it will launch the emulator.

The very last IMPORTANT thing to do is to be respectful of other developers and attach whatever license or README.txt file is associated with the rom that you’re uploading. For what I am inscribing, I am adding it to the top of the document, commented out, before the HTML.

And here is our playable inscription for LJ65 (formerly Tetramino):

https://ordinals.com/preview/c6040c06144c8c95276e34b889cd28cc916425525ec7711a969f17f2c8ef9bd9i0

In addition to LJ65, I also inscribed two other public domain Homebrew games:

Solar Wars:
https://ordinals.com/preview/dfd397839c9fc0a83c07e74212a9acd91afc61204f32f10e2bf1d480b1b91364i0

Bomb Sweeper:
https://ordinals.com/preview/8df203482bf4c9d260a1c050a6af3ef999abc55f3586eac7997a5f8f5f7a64a5i0

Enjoy!

--

--