I present to you my latest hack: Muon Baryon for JavaScript/WebGL. (Note: requires an HTML5/WebGL browser, a decent graphics card, and the pre-calculation time before the demo actually starts is quite long).
The Original
So, what is Muon Baryon? It’s a Windows 4k demo originally created by Youth Uprising, Ümlaüt Design and Outracks. More precisely, it’s the winner of the Assembly 2009 4k contest (so it’s a bit old – but still one of my absolute favorites). You can find out more here.
The HTML5 Port
Now, Muon Baryon was low hanging fruit for an HTML5 port, since:
- Most of it is written in GLSL, which is available through WebGL.
- The most complicated non-GLSL part was the music synth, and it has already been ported to JavaScript.
So, to begin with I started out converting the remaining C code to JavaScript, which mostly consisted of replacing things like glUseProgram() with gl.useProgram(), etc (a no-brainer). I also had to replace the handy desktop OpenGL call glRect with slightly more bloated vertex buffer code. When trying it out for the first time, nothing worked (black screen)… of course. I suspected the GLSL code and inserted the following lines after compiling the shaders:
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
alert(gl.getShaderInfoLog(shader));
I quickly realized that the original GLSL code was written for the older desktop GLSL 1.x (using ftransform etc), while WebGL uses GLSL ES, which has dropped a few functions. Here are a few things I had to do to convert the GLSL code to GLSL ES:
- Replace ftransform with a “custom” position attribute (quite simple, since the demo didn’t use any transformations).
- Include the line precision highp float; in the fragment shaders.
- Replace the while-loop with a fixed length for-loop, i.e:
while(g<1.){ ... }
becomes:
for(int j=0; j<999; j++){if(g>=1.)break; ... }
Not sure about how good this solution is, but at least Firefox and Chrome do not complain. Another thing I did was to make the shader resolution independent (the original was hard-coded to a certain screen resolution). Other than that, it was quite straight forward work.
The Result
The size of the original Windows demo was 3977 bytes. I did not expect to be able to squeeze the JavaScript port down to 4k, but I hoped to get it below 8k at least. And the final result, after using Google Closure Compiler and CrunchMe to compress the code, is: 5846 bytes!!
The un-packed code can be found here: demo-unpacked.js
…and the (unreadable) packed code can be found here: demo.js
Getting it to run
Ok, I have tried this in Firefox 5 and Chromium 13+ under Ubuntu with an NVIDIA 9600 card (fairly old by now), and it works just fine.
Windows users may find that it will not work by default (seems to be an issue in the ANGLE GLSL->HLSL conversion). To make it work, enable the OpenGL back-end.
In Firefox, go to about:config, filter out “webgl” and change webgl.prefer-native-gl to true.
With Chrome, you have to start the program with an extra argument, like this: chrome.exe –use-gl=desktop.