Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
JSConf US 2015 Track A Transcript for Simon Swain: Cold War

JavaScript brothers and sisters! Come on! JavaScript brothers and sisters! Yeah! Growing up as a teenager in the '80s wasn't all it's cracked up to be. Sure... We had the video game boom. The home computing revolution, and the last decade in which pop music was still truly cool. But we had zero fashion sense. None of the music had any bass. And everything was in 4x3. Worst of all, though... We grew up through the peak of the Cold War. Under the shadow of nuclear oblivion. The stuff of teenage nightmares. For an entire generation. But we made it through. And generation X emerged with a pretty extreme sense of gallows humor along the way. In the '80s, if you were nerdy enough, and lucky enough to even have a modem, download speeds maxed out at 1200 baud. But this era still gave us some great breakthroughs in technology, many of them driven by the military. In fact, we all owe our jobs to Cold War networking technology.

This network evolved from the communication links that enabled SAGE North American commanding control system for air defense. It was comprised of computers built of vacuum tubes distributed amongst the continental US. It had the aggregate computing power of a 386. In its time, it was impressive, but it seem almost laughable now. One tab of a web browser running on a 21st century mobile phone has more computing resources than billions of dollars of Cold War tech. If that's the case, maybe in this futuristic age we live in, just for kicks, we could create a simulation of a little bit of the '80s. Now, I know there are men and women who dedicated their lives to keeping us safe. Hopefully I'll never know what it's like to be involved in such a thing. But the least I can try and do is have an understanding of the role they played. This talk is a little tongue in cheek. But I mean no disrespect, and I would like to thank them for their sacrifices.

This animation is called minimum viable warfare. At the bottom, we have a base. It can fire a single shot to defend itself. Raining down from the sky are missiles. Their sole intent is to destroy the base. This is the foundation of some kind of game or simulation. It has the basics, but it's kind of boring, so let's tweak the parameters. Here the sky can fire two missiles at a time to try and destroy the base. This changes the odds considerably. The sky is going to win quickly every time. So let's tweak again. This is more like it. The bases can fire as many shots as they want to try to defeat the missiles raining down from the sky. An impregnable barrier. Until you run out of bullets, and then it's just a matter of time. So let's tweak again. Full blaze! Everybody can fire as many shots as they want to try and defeat their enemy. It looks like fireworks.

But the astute audience member will notice... The browser is starting to jank. Jank? What's that? That's when we ask the browser to do too many things in too little time. And everything starts getting shaky. Let's see some diagnostics. There are two things we are doing. We have an update phase and a paint phase. In the update phase, we do all the math required to work out where our things should be on the screen. In our paint phase, we draw them to the screen. To achieve smooth animation, we have to do this 60 times a second. This gives us approximately 16 milliseconds to do all of our work, actually a little less, because the browser needs some of that time for itself. When we exceed this time budget, our diagnostics go red and the browser starts to jank. In more detail, we're doing something like this. Forever and ever, we go update, paint, update, paint. Update, paint. We call this the game loop. But don't do it this way, because you're going to burn out your CPU. We use window.request animation frame. We paint, lodge a callback request to the browser and the process repeats. In an ideal world, the browser will call it 60 times a second and we'll get smooth animation. We have a set of variables we use to represent the universe we have created. We update these variables according to some rules. We use the values of those variables to paint stuff on the screen. Easy. Job done. But real life is never simple. There's no guarantee the browser will call us 60 times a second. It has other things to do and we're not that important. So we have to work out a time difference between now and the last time the browser called us and use that to create a scaling factor for all of our physics. If we do this right, and not all use cases are covered here, we will get smooth animation. When it comes time to paint, we use html canvas, the great unloved canvas tag. But canvas is amazing, supported everywhere, except some obscure version of Opera mobile. And IE8. We have an HTML tag, canvas tag, reference to the DOM, drawing content from that reference, call some methods on the context to paint stuff in the canvas, in the browser on your screen. We clear our painting surface, paint some stuff to it. Easy.

But to truly understand html 5 canvas, we must understand how a computer display works. In the '80s, computer displays were made of glass tubes. On the interior surface was painted phosphor. An electron gun would strike electrons and when they struck the phosphor, they would glow temporarily. Wrapped around this is a set of magnets. They can cause the beam to be deflected horizontally and vertically. If you read values from memory and use the values to modulate the electron gun on and off, as you scan it across and down your screen, you can cause a representation of the values in your memory to be painted to the front of your glass tube. This is how a bitmap display works. A raster scan display, the foundation of all computer displays today.

But there is another way to do it. In SAGE's era, computers were much less powerful. You would send a list of drawing instructions, which would cause an electron beam to go around your glass tube, much like lines drawn with a pencil. This is called a vector display. They have one amazing property. Simply by multiplying the intensity of the magnets that deflect the beam, you can scale the image up and down with incredible ease. You're just modifying one or two bytes. To do the same thing with a raster scan display requires a lot of complex maths. For a computer of SAGE's era, way out of its league. Tragically, this method has been lost to the mists of time, but html canvas gives us the best of both worlds. We can rotate and scale images while throwing bitmaps around the screen with incredible abandon. And you can see vestigial moveto, lineto commands, which correlate to the instructions for scanning an electron beam around the front of your glass tube. To truly start mastering html 5 canvas, you have to understand these transform commands. It starts on a grid, origin 0x0, top left of your canvas. The transformation commands, translate, rotate, scale -- let you modify this grid before you draw stuff. For example, translate, if you translate half the width and half the height of your canvas, your origin moves to the center of the canvas. It will appear at the center. Rotate and scale operate in similar ways. So use these. You transform the state of your canvas, apply transformations, draw the image, restore the state of the canvas back to how it was. You can apply these on top of each other, transform, save, and restore, operates like a stack. Save, save, save, restore, restore. Master these, you're well on your way. Canvas is reasonably well performing. We can get nearly 3,000 shapes in 5 milliseconds. Each shape is translated and rotated before it's drawn. You still have 10 milliseconds left to do your math. So what have we got?

The game loop, update, paint, update, paint, request animation frame, 60 times a second, HTML5 canvas. Reasonably good way to put it on the screen. Let's look at the simulation. This is called flocking. Each of the things flying around the screen is an independent actor, minds its own business, discovers the world around itself and determines which action to take. These do not want to crash into their neighbors. They will turn away if they get close. They don't want to get eaten. If the predator gets close to them, they will turn tail and run. The red ones are simpler. They turn towards the position of the white things. This looks spookily organic. This could be fish in the sea, avoiding sharks. What we didn't do is program the behavior we wanted to see. We created a set of rules and behavior came from those rules. We may or may not be able to predict the kind of behavior we get. We call this emergent behavior. It's the foundation of many simulations and even actions inside games you play.

But let's try and predict what's going to happen in this simulation. Let's see. I predict... Everybody dies. And those who do not die... Die a horrible death of radiation poisoning. Yeah. So what the heck is going on here? If you want to have a war, you have to have a nation state. In fact, actually you need two of them, because if you've only got one, there's no conflict. The heart of the state is its capital. If you use your capital, it's game over. A capital commands and controls and in our case also detects incoming attacks. We have a set of defensive perimeters. As these are breached, we escalate our response towards the enemy. But the nation is made of its people. People live in cities, are born, work, pay taxes, die. They provide the labor for our military industrial machine, which makes munitions at factories, people go to work at factories, build stuff, munitions are stock piled at bases, and the command from the capital determines how to employ those. People work at factories. We have bombers, fighters, antiballistic missiles, intercontinental ballistic missiles. When the capital determines it's time to go to war, the base will deploy these against the enemy. If you have a hegemonic enemy sitting over your border, stockpiling weapons, you are probably going to want to destroy them. Bombers are big and powerful, fly long distances, and unleash oblivion on your enemy's assets. If you see bombers screaming over your horizon, you will assemble your fighters. They're not very powerful, but if you have enough of them, they can swarm and overcome incoming bombers. First line of defense. Pretty soon you get sick of this air war business. You will have scientists develop intercontinental ballistic missiles. Which will fly to the outer reaches of space and scream down oblivion on your enemy. Whoever is under this will have a bad day. But you're not going to let your enemy lob missiles at you. You'll develop a defensive system. Ballistic missiles are crude and relatively effective. They try to destroy enemy ICBMs. And if successful, the ICBM is taken out and radioactive debris rains down on your farmland. Unlike the '80s, your scientists have developed effective killer satellites. At a cost of mere billions to the taxpayer, these sit in low orbit and take out enemy ICBMs with high powered lasers. So let's have a look. Two hegemonic empires, quietly minding their own business. Until one quiet morning, one of them launches a sneak attack. Who will it be? Sneaky blue enemy. That's a pathetic bomber squadron, if you ask me. Let's see what happens. Breach the outer defenses. Fighters scramble. Can they stop the incoming blue hoards? Effective defense. An effective counterattack. Blue is sneaking around through the North. One factory, two factories gone. At DEFCON1, missiles launch, yellow satellite, take out a few. Who will win? This is going to turn into a war of attrition.

We'll let it play out. Yellow is pushing through the middle. Can they get to the factories? One down. Two down. You lose your factories, you lose the ability to make munitions. Also billions of people die. Another million or two. Tragedy. Tragically, only the politicians are left on the yellow side. You want to see another one? Yes or no? Yeah, okay. We'll let it play again. These things are pretty hard to call, actually. Blue again. You don't learn the first time. We penetrate the air defenses. Start at DEFCON5, go to DEFCON4, fighters launch, DEFCON3, you can randomly launch nukes, 1s and 2s. When you get too close, DEFCON2, satellites launch. If a bomber destroys factories and cities, all the missiles fire. If the enemy fires all their missiles, you do the same thing. Looks like yellow might take this one out, but you never know.

Placing bets? Come on. It's yellow all the way. Yeah. They got it. You never know. You might get a strike straight to the capital. I think it's all over. Only the politicians left. Okay. So we've seen how it works. Let's look at what's going on, on the inside. We have a set of variables we use to represent the universe we have created. We will not be so greedy. We will just create a world. A fixed size, area, and airspace. We create a world with these parameters. Grab these options and make them available. The world initializes. It creates a bunch of collections for all the actors in our simulation. Capitals, bases, bombers, explosions, heaps of other things that are not shown here. We add our capitals. The foundation of our simulation is the nation state. At the heart of a nation state is its capital. We make a capital, which has all the assets to make up a nation state. Factories, cities, and bases. We make a new capital, give it a reference to the world, a team color, a location on the map, altitude of zero because it's on the ground, put it onto the world's list of capitals, it initializes. We have some maximums. How many bases can you have. Count up to the base, give it a reference to the world, tell what the capital is, and use some algorithm to tell its position, some strategic location in relation to its capital. When we've made all our actors, cities, bases, factories, all the assets of a nation state, we start our game loop. Update, paint, update, paint, 60 times a second in an ideal world. We go through all our collections.

Iterate through them. All our capitals, our bases, our factories. Give each of them a chance to update themselves. Feed in a delta, which is our time scaling factor. It's not guaranteed to be 60 times a second. Base updates. Should I be launching an attack against the enemy? I'll make a new bomber, put it on the world's list of bombers. I'll give it a reference. It knows who its capital is. Pick a target for it. Position is the location of the base. That's where it starts from. And the base depletes its stock of bombers so it does not launch an infinite number of them. We make a new bomber. It captures these things. Knows who its target is, knows it's alive, and manage its position using a vector class. X, Y, and Z. This is how we manage the location of all of our actors. We update the bombers, go through the list, give them a chance to update, if it's been destroyed, we splice it off the world's list of bombers and it gets garbage collected. Crash and burn. So the update code for the bomber and the fighters are probably the most complex bit of the whole sim. I'm not going to deny the joy of you writing this yourself. But -- I'm a bomber, I have a target. If it's been destroyed by someone else, I pick a new one. If there's a friendly nearby, I make sure I don't crash into them. If there's an enemy nearby, I avoid them but if they're near enough, I'll destroy them. These are great for more than just position. You can use them for things like velocity, or distance and direction to a target. The best thing about these is you can express the intent of your code. Rather than the mechanics. Write the mechanics, put them in there, and forget about them. When you come back in 6 months time, you can easily understand what you're trying to do. You don't have to decode the math. So I'm a bomber. I have a target. I subtract my position from the target's position, normalize that by unit length, multiply my thrust and add it to position. Simple algorithm for flying towards a target. Not a very good one, but good enough. Same with shooting. What's the difference between me and my target? Three-dimensional version of the Pythagorean theorem. Is the range close enough to destroy the target? Makes it easy to see your code. When we draw, html 5 canvas. Before we start the game loop, create a DOM element, get a reference to it, get the drawing context from it, but most importantly, we don't know how big the screen is. Could be any size. We maximize the canvas to fit the screen. Find out how big that is. The world has a fixed size, we figure out a scaling ratio between the world and the size of the canvas. We're going to use this every time we draw. Clear the painting surface, save the transform state, and scale it. Now when I'm drawing on the canvas, I'm using world, not canvas coordinates. I can think in terms of the data I've got on my actors. We iterate through each actor, give them a reference to the context, let them draw themselves, and when we finish, we restore. 60 times a second. Draw a bomber. It receives the context, transforms the state of the canvas, and transforms its position, and restores back to where it was. The next bomber on the list is going to do the same thing. That makes the drawing easy. We can draw around our origin, 0x0. It's been positioned and rotated. We can think in easy terms of how to draw our shape.

So let's have a look at another one. Two nation states, they're going to go toe to toe, straight away. People go to work, to the factories, make stuff, launch the bomber strategies. Who will win? I'm taking bets. You guys are cheering for blue and you guys are cheering for yellow. I think yellow's got it. Come on.


Yes! We will see. Version two is coming. He asked why the satellites couldn't shoot each other. Bombs away. A tragedy! Okay. Round two. You see some emergent behavior here. The bombers want to fly apart from their friends but further from their enemies. Sometimes they split up and go around and sometimes do this. If you change parameters like how far apart they want to fly, it seriously changes the behavior of the sim. Resource, yeah. Little square ones -- that's how many munitions they have. It's all over. See you, buddy. Okay. We've got one more scenario. I wasn't going to include this one, but I think it's important. This is what happens when you have four nation states. Entering all our nuclear conflict. Just watch this one in silence. It's all over pretty quick, isn't it? Just meditate on this one more time. I think this shows us... Why we don't ever want to really have a multi-nation nuclear conflict. Because if we do... It's going to be the end. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment