How to Clone HackerTyper

If you have never stumbled upon the delightfully hilarious site, HackerTyper, I wonder indeed if you are a user of the internet. It is simple enough. You type anything at all, and a very complicated tangle of C code streams onto the screen at a blistering pace. A very accurate parody of what most of the world seems to think of what hackers look like.

I was in need of a short term project, so I decided to make a clone of the website, and in the process actually tried to make something a bit better. You can access the project on Heroku here:

HackerTyper Clone
A clone of the popular HackerTyper. hackertyperclone.herokuapp.com

HackerTyper Overview

The best research that you can do before heading into battle is to study your opponent. In this case, I decided to examine how HackerTyper does this. After a relatively brief stint codediving, I was able to uncover that contrary to what I previously thought, HackerTyper does not generate the code it presents on the fly. It sends an AJAX call for a code.txt file, and then uncovers that file’s contents 3 characters at a time. After it gets to the end of this file, it just stops. Albeit, it does take a good amount of time to finally reach the end of the file, and the general user will never get here. I was disappointed to see how simple it all was.

All of this functionality (and more) is wrapped inside a pretty insane Typer object that I decided to forego for my implementation, as it just seems to add a lot of weird complexity to the code. Who’s to say, though?

My Implementation

So I decided pretty early on that I wanted all of displayed code to be procedurally generated. Since this was running in a browser, I obviously need to keep the whole process pretty computationally light. With this restraint in mind, I decided to use a list of preset grammars defined in JSON to create the lines of code. The grammars are saved in the following format:

{code: “ZZZ[ZZZ] = ZZZ.ZZZ();”, vars: “VIVM”}

Additionally, I maintain a list of variables and types that can be dropped into the grammars during grammar evaluation. So whenever I need to cerate a line, I randomly select one of the grammars, read what types are necessary from the “vars” string wrapped in the object, and create an array of Strings that are of the proper type, which are spelled out below:

V = variable; I = integer; M = method;

I can then iterate through the grammar and replace every instance of “ZZZ” with the proper item from the array. I decided to decouple the generation of variables from their insertion for simplicity’s sake and personal preference. While I could have used VVV, III, and MMM in the actual code insertion, it would have made the regular expression a little more complicated and then I would have had to include the logic for variable generation in the variable insertion section of the code. It seems much cleaner to me to do these two actions in two distinct steps.

I maintain a Queue (using Stephen Morley’s Queue.js) of generated lines because this is useful when trying to use control structures or functions. You can pre-generate all the lines, with the various changes in indentation, and then pop them off as needed, and generate new lines whenever the Queue is empty.

I then just maintain a reference to the current line:

var curLine = Queue.dequeue();

and the current index that marks what portion of this line is being displayed. Which is incremented and compared to the length of curLine to determine whenever a new line is needed from the Queue.

I would also like to think that my implementation of the blinking cursor is cleaner than the original’s. I created an separate <span> element that contains the cursor, and toggle it’s visibility on a set interval. The original grab’s the innerHtml content, uses substring() to remove the last character, and then readds the shortened string to the page. After a few hundred more milliseconds, ‘|’ is readded to the end of the page. I think my method is way easier both to read and to implement.

I wrote the backend in Django, and all the source code is available on Github. Feel free to use it, or build on it.