Embedding and Encoding in JavaScript

A crude JavaScript implementation of the first stage of Super Mario Brothers has been making the rounds today. It’s roughly playable but misses many key aspects (no mushrooms, no flag, no one-ups, etc.). However, that’s not what’s particularly interesting about the game.

Perhaps the most interesting part of the application is not within the game mechanics itself but in the fact that all of the game contents are embedded within the game script: This includes all game sprites and music.

This is an interesting feat and one that’s possible to accomplish within your own code. Let’s take a step through how this was done to understand how we can better use this within our own sites.

Music Embedding (base64)

Surprisingly, how the music is embedded within the application is, perhaps, the easiest to completely understand. The application makes use of data: URLs, encoding the Mario music MIDI files using base64.

We can see the result within the source file:

aSounds = [
  // very small, very simple mario theme. Sequenced by Mike Martel.
  "data:audio/mid;base64,TVRoZAAAAAYAAQAEAMBNVH...",
  // game over. Sequenced by John N. Engelmann.
  "data:audio/mid;base64,TVRoZAAAAAYAAQADAHhNVH..."
],

data: URLs work by encoding the entire contents of the specified files within the URL to the file itself. This can even be used for images (embedding PNGs, JPGs, GIFs, etc.). In this case it’s being sent to an <embed/> element, which is capable of playing the midi file. We can spot the resulting injection code here:

playMusic = function(iSoundID, bLoop) {
  if (!bMusic) return;
  var oEmbed = dc("embed");
  oEmbed.src = aSounds[iSoundID];
  oEmbed.id = "sound_" + iSoundID;
  if (bLoop) oEmbed.setAttribute("loop", "true");
  oEmbed.setAttribute("autostart", "true");
  oEmbed.style.position = "absolute";
  oEmbed.style.left = -1000;
  appChild(document.body, oEmbed);
},

Which simply creates an embed element, sets it to automatically start, and injects the data: url as the src. The result is an auto-playing MIDI file (assumedly a similar result could be achieved with another universal file format, such as WAV).

data: URLs are capable of playing in all browsers but Internet Explorer (they’re being introduced in Internet Explorer 8). In the case of this application Internet Explorer users simply don’t receive audio for the game.

Image Embedding (binary and ascii)

The second, interesting, portion of the application is the embedding of the various sprites used in the game. This includes the mario character, the blocks, pipes, and even the background images.

The application uses a number of interesting techniques in order to compress the size of the resulting images. Rather than using the data: url technique (which is completely applicable, in this case, to applications that can use them) the game, instead, uses the <canvas/> element (and regular div/spans for Internet Explorer). Because of this dual platform target the individual pixels of the sprites must be saved and retrieved.

In order to meet this target all of the individual pixels must be stored in a way that is space efficient, and yet, easy to access.

To start, all available colors must be mapped out and reduced. All sprites within the game have, at most, 4 colors (some have less). We can see this reduction process in the following graphic:

This reduction, and mapping into a binary grid, is a useful way to create a portable sprite (each sprite is reduced to the binary and associated colors). The next step is to convert the binary grid into an easily-transportable string, like the following:

The end result is a string representation of the entire sprite – which is quite small (byte-wise) while still being translatable back to its original representation.

Both of these encoding techniques can prove to be quite useful in your JavaScript code – especially if you’re striving to encapsulate as much within the base code, itself, rather than in external files.

Posted: April 9th, 2008


Subscribe for email updates

19 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.