JavaScript: Microbenchmarks and their pitfalls - trig, random numbers, sqrt, and lookups

In the midst of all the depressing news about coronavirus what better way to cheer everybody up than with a post about JavaScript microbenchmarks. That’ll never start a flamewar, will it? But whilst I was doing some work on arcade.ly recently I thought it was worth revisiting my decision to go with lookup tables for trig functions and the like, and see if perhaps I shouldn’t instead be using functions provided by JavaScript’s global Math object instead.

Before we get into it, let’s get this out of the way: I know microbenchmarks are fraught with pitfalls. It’s super-easy to write a microbenchmark, particularly if a tight loop is involved, that any half-competent compiler or JIT will be able to optimise away to pretty much nothing, and thereby end up with incredibly skewed results.

Other people know this as well. Here’s a comment on a recent Hacker News discussion about an article that claimed "JITs are un-ergonomic":



Comment on 'JITs Are Unergonomic' discussing the looping pattern common in JavaScript microbenchmarks

Absolutely spot on: as pizlonator says, the antipattern is real. A few years back I read a blog post - that I wish I could still find find - that covers a similar topic as it relates to C++.

So why am I bothering to write this?

Well, because I suppose my position is that as with many things in software development and life, it’s not so simple.

A few years ago, when I first started working on arcade.ly, I made the decision to use lookup tables for common trig functions (sine, cosine, tangent), along with square roots, rather than use the built-in Math.sin(), Math.cos(), Math.tan() and Math.sqrt() functions.


(N.B., I also avoided Math.transform(), but I think that one’s worthy of another post because this one is already going to be quite long enough!)

This made sense at the time (2015) because, back then, JavaScript performance across the different browsers and platforms varied wildly.

Read More

How to debug NaN and NaN propagation bugs in JavaScript

Debugging NaN (not a number) related bugs in JavaScript can be frustrating. NaNs propagate, which means they can spread themselves around your data structures very quickly under some circumstances, and it can be time-consuming and somewhat tedious to track down the root cause. If you’re just building CRUD apps you may never encounter any NaN related issues, but the moment you start working on apps that involves a reasonable amount of numerical manipulation they can start to appear much more regularly. In this post I’ll share what I’ve learned through debugging numerous NaN related issues I’ve encountered whilst building games for arcade.ly.

In this post I’m going to outline some basics (e.g., what is NaN?), then work through common causes and manifestations of NaN related bugs, describe NaN propagation with an example, show how you can verify that you do have a NaN bug, and then look at three different strategies for debugging that you may find helpful.

So let’s start with the basics: what is NaN?

NaN is a special global property value in JavaScript whose value means “not a number”.

Any time you use a variable whose value is NaN in an expression, the result of that expression with be NaN, or false if it was any kind of comparison. You also can’t really do meaningful comparisons with NaN: for example, the expression NaN === NaN will always return false.

Fortunately you can check for NaN by calling isNaN(expression), which will return true if and only if the value of expression is NaN. This will come in handy later on when we look at debugging strategies.

In a typical CRUD app you may never encounter NaN, but as soon as you get into any form of numerical manipulation it’s pretty likely you’re going to run into it sooner or later.

Examples of such apps are:

  • Games

    • Particularly anything real-time: arcade games, shooters, platformers - anything that involves real-time movement or collision detection
    • Turn-based games can also experience NaN issues where numeric data is involved (RPGs, RTS games, etc.), but their slower pace tends to mean that these bugs are often easier to reproduce and debug: you can often isolate an exact sequence of steps required to reproduce a bug, especially if you can replicate a particular state in the game
    • I’ve run into NaN issues in both my games, Star Citadel (a version of Star Castle), and Shoot The Rocks (a version of Asteroids) which make extensive use of arithmetic, trigonometry, along with basic mechanics and some matrices
  • Data visualisation

    • Such apps will often take a feed of data from the back end, either on demand or in real-time: if that data is manipulated in any way beyond just throwing it at a charting library the possibility of NaN bugs creeping in exists (in theory it still exists with the library, but the probability of problems arising is much lower), and especially where custom visualisations are used
Read More

Shoot The Rocks: tips and tricks for dealing with black holes in my version of Asteroids

There are a few things about the modern variant of Shoot The Rocks that aren’t really reflective of the original arcade games on which it’s based.

Shoot The Rocks is perhaps most similar to Asteroids Deluxe, which is a fairly basic evolution of the original Asteroids. We still don’t have the satellites in Shoot The Rocks yet: I do intend to add them, it’s just a case of finding the time.

The greater use of colour is reminiscent of Space Duel, and the (soon to be implemented) availability of power-ups is somewhat reminiscent of Blasteroids - although my power-ups are very much focussed on fairly simple weapons upgrades only.

I suppose I do like to think that Shoot The Rocks has its own character though, particularly when the modern variant is played. The graphics, whilst similar and very much tipping a hat to the original vector games, are different from the original, as are the game dynamics and some of the features.

For example, something that doesn’t appear in any of the arcade games or their ports, as far as I’m aware, are black holes.

A black hole - admittedly more of a blue hole - shown near the player's ship during a game of Shoot The Rocks. Note the asteroids in close proximity

Note the black hole (yes, admittedly it’s blue, but I felt like it needed to be visible to keep the game fair!) below the player’s ship. Note also that it’s drawn a number of asteroids towards it. It took me several attempts to get this screenshot as my ship kept getting destroyed by asteroids that were being sucked in towards the black hole (see tips below).

These are very much based on the star that appeared in the grandsire of all shooters, Spacewar!, in that they implement a gravity well that influences the movement of all other objects in the game.

They add another dimension to the game, which you can either use to your advantage, or which can be your undoing, depending upon how you deal with them.

So here are some tips and tricks:

Read More

Making gravity fun: adding black holes to Shoot The Rocks, my version of Asteroids

Well, it’s been a while (!) since my last blog post here but, you know, life intervenes. Still, I’ve started working on the site and improving the games again.

I had this idea that I wanted to inject a little chaos and variety into Shoot The Rocks by adding black holes with associated gravity effects. This is something the original Asteroids didn’t have, and I don’t believe they’re in Asteroids Deluxe either. Still, I thought they might make for a fun addition.

If you want to jump straight in an see what effect this has all had on the game, just click here to play.

I want the classic version of the game to be quite close to the original arcade game so black holes only appear in the modern game variant. (I’ll probably add satellites to both classic and modern variants though because Shoot The Rocks is more like Asteroids Deluxe than the original Asteroids!)

Whilst black holes didn’t take ages to implement - really only a couple of afternoons - the road wasn’t totally straight. Much of the time was spent tweaking behaviour until it felt right: it’s more important for any game mechanic I add to be fun than it is for it to be realistic.

Gravity is obviously a real phenomenon so I did start off with a fairly realistic model, in the form of Newton’s Law of Universal Gravitation:

\[F = G\frac{m_1m_2}{r^2}\]

Where:

  • \(F\) is the force in Newtons
  • \(G\) is the gravitational constant
  • \(m_1\) is the mass of our black hole
  • \(m_2\) is the mass of whatever other game object we’re interested in
  • \(r\) is the distance between the black hole and the other object (Strictly, I believe, it’s the radius of the circle whose origin is the centre of mass of the black hole and whose edge would intersect the centre of mass of the other object, or vice versa. Details, details, etc.)

In simple terms, the gravitational force between two objects:

Read More

Perceived performance part 2: load assets asynchronously or on-demand

When I started my arcade.ly side-project, for such it is, I had a variety of motivations. One of them was that I was a bit fed up of all these low-rent Flash versions of classic arcade games that I’d loved as a kid tarnishing my nostalgia with their long load times, pages covered with ads (yes, there are ads on this site, because I want it to pay for itself, but I try to keep things tasteful), and generally sub-par experience.

I even felt pretty smug and superior about the idea of building games with HTML5, CSS, and JavaScript that would load instantly, or pretty close to, compared with their bloated Flash equivalents with their interminable loading progress bars. Then, of course, reality came calling, complete with its usual payload of disappointment - something I posted about in a comment on Hacker News. There I identified some fairly obvious reasons why games can take a while to load that go some way beyond “Flash is an awful nineties/noughties horrendo-tech abortion that should be blown into charred corpse fragments with dynamite”:

  • Loading games assets takes time, particularly on slower connections (like mobile)

    • Graphics (background images, sprites, textures, logos, etc.)
    • Sound effects
    • Music
    • Fonts
    • Maps and other metadata (game objects, etc.)
  • Creating procedurally generated content can take a while

Now this is frustrating, because it turns out these are big problems for me in that I have a combination of downloaded assets and procedurally generated content. So how do I get around this?

It’s really a combination of two techniques:

  1. Asynchronous loading of non-essential large assets after DOM content has loaded, and the page has rendered, which happens immediately after.

  2. Immediate feedback to the user that something is happening upon page rendering.

Neither of these results in anything being loaded any quicker, but it does get the loading "out of the way", and at least shows the user that something is going on whilst the procedurally generated content is being created. I’ll talk about (1) in detail below, and address (2) in a follow-up post.

Now both Star Castle and Asteroids are vector based arcade games so in my versions, Star Citadel or Shoot The Rocks, we don’t need to worry about downloading any bitmaps or textures for either. The graphics for all the game objects - spaceships, asteroids, flying saucers, mines, etc. - are specified using a simple vector-based notification as JavaScript objects, so they’re just part of the source code. These specifications are just based on designs I knocked up quickly in OmniGraffle.

Using JavaScript objects is not really super-efficient in terms of space but uglify does a good-enough job of compressing them, and they’re not very large or complex anyway. The player’s ship in Star Castle is 8 blue lines, for crying out loud!

If I did have a lot of bitmaps, textures, pixel art, 3D models, or whatever, I’d probably have to load a lot of them upfront because they’d be needed to actually play the game, and there’s not much avoiding that. The one thing I could do, if I were using different graphics for different levels, for example, is load only a minimal set of graphics up front, and then load the rest on demand later on.

Read More

Perceived performance part 1: what is perceived performance?

I have this talk I first gave late last year called Client-side performance for back-end developers, of which those slides are just the first iteration. A notable topic I haven’t included, is the importance of perceived performance. Yet it’s something I’m very conscious of, and I’ve been working continuously to improve it for arcade.ly. My basic question is always, “How does it feel to use this?” And this is a principle that cuts across the whole site, especially the games. I want it to feel great: I want it to feel slick, fast, responsive on all devices and browsers.

Running across this piece by Brian Jackson (formerly of keycdn) the other day brought the topic of perceived performance back to the forefront of my mind, and reminded me was something I should write about. So in this series of posts I want to cover what perceived performance is, and how I’ve improved it on arcade.ly.

OK, so let’s start off with perhaps the most important question: what is perceived performance?

Well, one way to look at it is it’s the answer to the question, “How fast does this feel?” So, it’s not about how fast some process really is, but about how fast a user perceives it as being. And so it can sometimes be surprising when real, objective, measurable performance and perceived performance don’t always correlate. Now with that being said, it should be obvious that in many cases improving real performance can often help with the perception of performance too, but sometimes you can improve perceived performance significantly without improving real performance in any way (and sometimes whilst making it slightly worse).

You might legitimately wonder why this matters but, when it comes to the web, the fact is that slower websites lead to dissatisfied visitors who don’t hang around, and fewer conversions (however you define conversion for your site). And never mind how fast it is or isn’t, if your website even feels slow, you’re going to lose out. People will vote with their attention by directing it elsewhere.

The key point I’d like to make - and I hope this isn’t too controversial - is that your users’ perception of your web app’s performance is actually more important than its real, measured performance. Like I say, perceived performance is key to a great user experience.

How have I approached this for arcade.ly? Well the first thing to say is that I have, and continue to, expend effort on making everything actually, measurably, really faster, and these are things that I’ll talk about in other posts. Beyond that, and it’s really something you do when you’re out of options for making something measurably faster, I’ve used a few tricks and techniques to improve perception:

  1. Load assets resources out of band/asynchronously or on demand.

  2. Load key above the fold content as quickly as possible, and give the user immediate feedback that something is happening.

  3. Gracefully degrade the experience on slower devices to keep performance up.

  4. Load and render key above the fold content first, delay everything else, even if this means the page load takes multiple seconds overall.

I’m going to talk about each of these techniques in more detail in the follow-up posts, so you can see exactly what I’ve done. I’ll also highlight areas where improvement is still needed (I’m nothing if not honest!).

For now though, I’m just going to leave you with this take home…

Read More

Is that Star Castle in The Expanse on Netflix?

A few days ago I started watching the excellent new series, The Expanse, on Netflix. They claim it as a Netflix Original, but both IMDB and Wikipedia claim it’s an Alcon Entertainment and Sean Daniel Company production, originally for SyFy, so I don’t know.

Anyway, I don’t want to say too much about it for fear of revealing spoilers. Suffice to say back in the day I was a big fan of series like Cowboy Bebop, Firefly (and, of course, Serenity), and Battlestar Galactica, and The Expanse goes some way toward scratching that itch in a way that hasn’t really happened since BSG ended. If you’re a fan of sci-fi or space opera with a bit of an edge to it I’d highly recommend you check it out.

Anyway, I’ve been watching this in the evenings for a few days, and towards the end of episode 8 I spotted something interesting on a holo-display. Here’s the shot with enough of the dialogue to set the scene:



Do we think this officer is actually playing Star Castle in The Expanse and not, as she claims, analysing a space battle involving the Donnager? Hmm.

Oh, really?

Well, you can call it whatever you like but it looks to me like your boss just busted you enjoying a good old fashioned game of Star Castle when you should have been working.

Still, it was probably worth it, don’t you think? And if you fancy a game yourself just click here.

How good is Cloudflare's Always Online™ technology?

If your site goes down, exactly how good is Cloudflare’s Always Online™ technology at bailing you out?

Rather good. But…

We’ll get to the “but” in a minute. Let’s deal with the “rather good” first. Here’s arcade.ly‘s homepage when the site is down:

The arcade.ly homepage when the site is down. Note that Cloudflare is still serving it up, which is great.

By down, in this case I mean the service that runs the site is down, although the instance it normally runs on is up.

Now apart from that banner, which is basically an ad that says, “Cloudflare is awesome and you should use it!”, everything looks normal. I could probably get rid of that by giving Cloudflare more money, and maybe one day I will. Nevertheless, my dodgy web design skills aside (and this page is going to get a makeover), everything that should be on the homepage has loaded and is working fine because Cloudflare has been able to serve it up from its cache.

So can I play the games?

Yes, I can. My Asteroids remake, Shoot the Rocks, works fine. Here you can see it loading as if nothing is amiss:

Shoot the Rocks loading like nothing's wrong - awesome.

The main menu looks a bit gimpy because the banner messes with the layout a bit, which might be more problematic on iOS than on desktop or Android, but everything still works:

Read More

How to run a Node.js app as a service on Ubuntu

One of the things I’ve needed to do with arcade.ly for a while is start running node as a service.

It’s easy enough to run background tasks directly from bash with a command like:

1
sudo nohup node index.js &> /dev/null &

And if you run that command and log out of your ssh session, node will carry on running just fine in the background. But what happens if node falls over? For arcade.ly this has never happened, but that’s likely because the site hasn’t been under much stress up to now.

(By the way, if you want a detailed discussion of running bash commands in the background it’s definitely worth checking out Running Bash Commands in the Background the Right Way.)

Realistically at some point the site is going to go down, and whilst Cloudflare will to some extent bail me out, I’d like it to come back up again without a manual intervention, especially if it’s due to something as simple as the node process crapping out.

Here you can see the effect of Cloudflare’s assistance. It’s not bad but that banner (basically an advert) at the top isn’t ideal. I suspect I could get rid of that by paying for a more expensive plan.

Here's Cloudflare dragging my backside out of the fire when I'm testing what happens when node goes down. It's not ideal, but at least you can still play the games.

The great thing is that you can still play the games so if you need a fix of Asteroids or Star Castle you can go ahead and fire up Shoot the Rocks or Star Citadel and they’ll (probably) still run. (I’ll blog on this topic in due course as well.)

So how do we make sure it runs as a service and recovers without intervention?

Read More

Welcome to the arcade.ly blog

Welcome to the arcade.ly blog, where we’ll be talking about games, game dev, and web performance.

All our games are built with HTML5, JavaScript, and CSS. That’s right: no Flash. Which means they work on mobile and tablet, as well as desktop and laptop.

So far we only have a couple of games:

We hope you enjoy playing them!

For anyone who’s interested, our behind the scenes tech stack is express.js and node.js running on Bitnami, currently in Amazon Web Services’ with Cloudflare as CDN. The blog is generated by Hexo using the excellent alpha-dust theme from Jonathan Klughertz.

We recommend you subscribe to our Atom feed for posts and updates on new game releases.