My Sister’s Birthday, Perlin Noise, and Ancient Mammals

The Beginning

A few years ago a bought a domain name for my sister for her birthday. Every year since, I’ve been making a sort of interactive birthday card there for her and in the process, teaching myself something new.

Last year, I made a little app that would display videos from a few of her favourite k-pop bands, using om.next (since that was something we’d been considering using at work).

This year, I decided to do something a little more interesting, both for me and her and make something actually interactive. I was thinking that it eventually could even be a game, time allowing (maybe next year?).

To start, I was thinking I’d have a picture of a baluchitherium1 on the page that one could move around with the arrow keys (and later, could be like, dodging obstacles or whatever). One of the things I’ve been trying to practice this year is being comfortable drawing stuff, so I used the fantastic pixel art tool aseprite to draw an animated gif of a baluch:

Figure 1: A majestic flying baluch

It’s simple enough to put this on the page, the use the arrow keys to move it around. This was probably good enough for a birthday card, but I wanted to do something more challenging…

Perlin Noise

I had read a great post by eevee about Perlin noise not too long ago and thought it was interesting, but I didn’t full get how the algorithm worked. The best way to understand an algorithm is to implement it, so I decided I’d make the background that the baluch was flying over be Perlin noise generated on-the-fly.

I started by trying to do a straightforward port of eevee’s python implementation to ClojureScript. It took me a while to get things working properly, but it was mostly a mechanical transformation of Python to ClojureScript (it was pretty fun to translate mutating loops into reduces and such though).

The tricky part was dealing with the fact that the algorithm was quite computationally expensive - it takes a significant amount of time to generate each frame. Since this is running in the browser, which only executes Javascript on a single thread, it would block constantly, so you wouldn’t be able to move the baluch around at all!

This obviously would not stand, so I had to find a way around this. I didn’t feel like trying to optimize the algorithm (although that would definitely be a good thing to try to do), so I needed to somehow move the computation off the main thread. I first thought I could just use core.async (which is a great library), but realized quickly that that wasn’t the right approach – core.async is great for asynchronous I/O, but it’s still Javascript, meaning while it can do concurrency, it still isn’t parallelism!

Luckily, there’s a (relatively) new Javascript API for WebWorkers that actually allows Javascript to run on multiple threads! Reading how it worked, it seemed like it was going to be kind of complicated to use, especially since I wasn’t writing Javascript directly, but compiling from ClojureScript.

Fortunately, there’s a solid ClojureScript library called servant that wraps WebWorker stuff and makes in fairly easy to have some ClojureScript code run in a background thread! I remain slightly unclear about how data gets passed in and out of the servant functions, but eventually I got things working by just passing in primitive data and encoding the return values of the functions using transit.

The background updates fairly infrequently (depending on how fast your browser can render each frame), but it works!

Figure 2: Check out that sweet random – but smooth! – noise

Check out the site2 (and use the arrow keys to fly the baluch around) and have a look at the code.



Long story, but basically we have a family tradition of everyone having an animal, and for some reason my mum’s branch of the family has weird animals - my sister and one of my brothers are baluchitherium, these weird prehistoric creatures. I happen to be a pterodactyl.


Probably don’t leave it open too long though - it will devour as much CPU as it can to push out the noise.