Curtis Lassam: Horse Drawing Tycoon: The World’s Best Horse Drawing Simulator | JSConf EU 2015
Articles Blog

Curtis Lassam: Horse Drawing Tycoon: The World’s Best Horse Drawing Simulator | JSConf EU 2015

August 22, 2019


Hi. I’m Curtis Lassam. You can also find me
on Twitter, I’m classam. I work at a company called Sauce Labs, they let me come to this
conference without burning holiday PTO, take a moment to take in this slide, I produce
cube drone.com, before I start the presentation, JavaScript, very confidently a couple of times,
in case we get a DJ again next year, JavaScript, JavaScript, JavaScript!! Ok {Laughter}. So this presentation is called HorseDrawingTycoon,
the world’s best horse drawing simulator, or how I turned the world’s dumbest JavaScript
into time off work, yes my presentation full title is 31 years long, that’s how you know
you will get a lot of bang for buck, nobody will offer this density, nobody that’s who. I’m from Vancouver Canada, VanJS is a small
meet up local to Vancouver, I’m talking with a friend at the pub, he wants to make video games, he has a bunch of ideas, they’re all
really good, I took it upon myself to suggest games that would never take on, like Breakout
where you play with bricks. An indie game generator produced incredible ideas, like
a horror came where you ride horses with Ninjas, or FGS where you stab researches, these ideas
too were obviously much too could, I would play any of the games it described, eventually
it came to an idea so bad nobody would ever want to play that game, a tycoon game where
you draw horses indefinitely it’s the worse idea for a game I ever heard, I had to build
it, in order to finish it before everyone forget the bar conversation I had to build
it really quickly, obviously it didn’t need to be could, my VanJS companions had many
questions, questions like, how are you going to build it, canvass. How are you going to
know people are going to draw horses, isn’t this just going to be an obscenity drawing
game, I would discover the answers to these questions. Although I did not at any point
know that the horse recognising artificial intelligence. So before I go any further into
this presentation, I have to tell you this is an actual piece of software that exists,
I’ll do a short demonstration for you, HorseDrawingTycoon, I can stamp horses, pick a colour, brush size,
I can scribble, it’s got everything. Ok. This is a horse that somebody drew with
HorseDrawingTycoon, this application has been running uninterrupted since I launched it,
it’s pretty ‘Stable’!! {Laughter} that brings us to chapter 2, canvass. The most interesting
part of a horse drawing simulator would be of course the drawing part, which gives me
an opportunity to talk about the HTML 5 canvass element the canvass tag allows you to create
an element in the DOM you can draw horses on. While I’m certain there may be other uses
for the canvass element, say video games or stuff involving graphics I can’t see how any
non-horse drawing use of canvass is worth acknowledging, it exposes something called
a rendering context to the page’s JavaScript, it encapsulates all the actions you can perform
on the canvass, the entire canvass API, you can get a rendering context with code that
looks like this. Then, you can do stuff to the canvass element using the API defined
by the rendering context, here we are drawing a rectangle that is blue, note that we are
specifying a 2 D context here, is also has a 3 D rendering API, using it for the horse
drawing application might be a bit out of scope the primary things to draw are paths,
rectangles, text and Bitmaps, – this is the sort of tooling that lends itself to building
a game engine for a stupid horse drawing application it’s a little bit complicated the create JS
libraries are for building rich content in JavaScript applications, PreloadJS, SoundJS,
between JS, EaselJS is the part we’re interested in, it allows us to work with the HTML 5 canvass,
it contains convenience methods for working with a bunch of things like sprites, blurs,
buttons points and strokes, the bitmap object is really useful for stamps, I don’t have
much to say about stamps, if you dynamically set the cursor and use a bitmap, we have horse
stamps, horse stamps in action. Now stamps are all well and good this is of course stamping
is this is into stamping tycoon, it’s HorseDrawingTycoon, when figuring out how to draw horses, I tried
to draw a circle under the pen while it detected a movement while the user was clicking, the
problem with that, the mouse can move much quicker than the sample rate of the browser,
so instead of flowing lines we get dots everywhere, the first thing I tried didn’t work. We can
connect those dots with lines to complete the drawing, it works pretty
well, but fast movements will still result in drawings with hard edges. I remember the
deviant art mirror simulated covers by connecting lines to previous points instead of just the
last line, it was a beautiful affect but not really what I was going for. The technique
I used was one I found in demo, between every two points I created a mid-point, when I reached
the next point in the drawing I create a quadratic curve from the last mid-point to the next
point, it’s kind of complicated in this draw. Quadratic Bezier covers are more complicated
than they sound, here we are just curving between the mid-point of the last slide to
the next point in our drawing, ending up creating a nice smooth curve. Here are some more horses
that actual people have drawn using HorseDrawingTycoon. Ok, so we’re done with canvass for now. That’s takes us to chapter 3, LucidJS, at
the VanJS presentation I just attended a talk on Twitter’s flight, a component shading event
driven framework, it was interesting in the point of being my application as a collection
of components that send and receive events appealed to me, flight itself wasn’t the right
framework for me, months earlier I attended a talk on LucidJS, pretty much the same thing,
but I was paying more attention during the LucidJS, JavaScript has the own baked in events,
but we need to maintain separation between elements like click and things like clear
canvass. Let’s look at a simple LucidJS event emitter, we can create an emitter to manage
events, then we can combined function to an event, we’re binding it to the super awesome
event, then we can call the function by emitting the function 0 come event, passing any events
to the function. LucidJS that has a lot of functions above and beyond a standard event
emitter, you can bind specific events to one another, name space events so that only specific
listeners will receive those events and even create meta listeners and listen on the very
act of binding itself. HorseDrawingTycoon comfortably ignores all of these features
but they are all potentially useful for larger applications. So how is those better than defining global
functions and then calling them? Well more than one function can be bound against an
event, the canvass function can behind it to the current brush stroke, at the same time
the component that manages the cursor could also behind to that event and change the colour
of the cursor when it receives the change colour event. Both components are responding
separately to the change colour event and neither of the components needs to know about
the other or what the component is doing with the event. The other benefit of the vent stream
this events become a stream of objects you can manage, it’s possible to see realise all
events and store them for later, keeping a complete history of very event in your application,
or a component that listens for events that change the application state and keep track
of it using local storage, that same component could reemit the events when the application
boots up. Now if that sounds like a needlessly convoluted way to handle story in your application
I can assure you it is, that’s how HorseDrawingTycoon stores data and it’s a bad idea. One of the problems with this sort of implementation
the components can tie what ever they want to an event, replaying those events we might
only want to trigger some of those effects, there is no granular way to control them,
it’s one of the places where more of the advanced features would have come in handy like name
spacing for example, if I was to rewrite the serialisation of HorseDrawingTycoon I probably
wouldn’t have done it that way, I still think events are awesome though. One more time,
yeah! That ends our chapter on LucidJS, I have more
horses to fill the gaps between chapters. Really cool horses. ! {Laughter} . It brings me to chapter 4, local storage.
When it comes to stashing things on the browser side there are few options that are well supported,
web SQL that only works on Chrome and safari, indexedDb that works in Chrome and sort of
safari, local storage that works absolutely everywhere, but at the expense of being dumb
as a rock. Actually the simplicity of local storage is exactly what I’m looking for when
building such a simple application as HorseDrawingTycoon. Let’s look at the local storage API, you can
write to local storage with set item, everything you write is saved against a key, in this
case we’re saving the string JSConf, against the key, hi, we can read from local storage
with get item. When you write to local storage that data sticks around every time the user
returns to your website on the same browser. There are multiple ways to access local storage,
using get item and standard object interfaces. Considering how the key, I don’t exist, does
not in fact exist, all three of these calls are going to fail. In this case, because the key doesn’t exist,
x is no, but y and z are undefined, the different ways of accessing local storage data operate
differently. Another important thing local storage can only deal in string data if you
are dealing with anything not a string you have to serialise and deserialise, use JSON
string and JSON parse. Self referential data structures, in JavaScript self referential
data structures like this one right here, are unserialisable, there are a few options
for avoiding this, the first is making it possible to realise – your other options just
not to write code that has a cycle in it. Another thing that to potentially concern
yourself with is what happens when you run out of space in local storage, it varies from
browser to browser and per domain you might have 2.5Mb, 5Mb or unlimited space, these
are the most common quotas, there are others. If you go over your quota, your browser will
throw a quota exceeded error, I bet you are excited to hear how I built my application
to cleverly avoid the problem of cyclical data structures. How I manage to keep my storage
needs in check. I completely ignored these things. As it turns out in application as
small as mine it’s easy
so that’s chapter on local storage. Chapter 5, horse rank one feature of my application
is that every horse drawing is run from a complicated artificial intelligence algorithm
that ranks had horse like every image is. It’s much dumber than I make it out to be.
It’s possible to use the get image data function of a context to get raw data that’s been displayed
on the screen as any given pixel. The function produce and object, the object have very,
very long array that containing red green blue,
each pixel takes 4 spaces in the array, information is laid out 4 at a time in red, green, blue
and alpha for each pixel, alpha being a fancy graphics word for transparency. When you get
to the end of the row it continues with the next row with that established it’s super
easy the his toe cram of the colours that the player you had even display that hest
gram to the user so that the terrible secret of horse rank has been revealed. So, while we’re talking about cool things
that we can do with the entire canvas, let’s talk about saving the users horse. Which is
actually really easy with the 2 data URL function. This function converts the whole canvas into
a URL, but a URL that contains all of the data for the entire image encoded in base
64. These strings are very, very long but they contain all of the data of your entire
image. Just going to take a quick sip of this water. These things are down right magic you can
just slap them into an image tag bam! there’s your image. Once the image is serialised like
this is really easy to save, but it’s also really easy to Tweet. Which brings us to chapter
7, secretly tweeting every single thing the users draws. If you navigate to Twitter.com/infinite
horse you will see a strong of every single horse ever drawn with the application. I will
take you on a live tour if somebody one has drawn an obscene horse in the lass 20 minutes
I will shine an unpleasant light on the presentation. It works about how you imagine I. I am going
to leave the details of the server large unexplored, this JavaScript built the server machinery
in python the whole thing fits into about 160 lines on Google app energy for free, it’s
python it’s not really what we want to call the (inaudible) because I hosted the tweet
machinery on a different server I have to make a cross origin request to save that tweet
which brings us to our chapter on CORS. As you know making a request from one domain
to another is forbidden in JavaScript. The first way to get round that the first JSONP
loads this theoretical horse drawing application that might use JSONP. You are always allowed
to do this regardless of the origin in this example we’re visiting the server horse.picks
with the data foo there’s an error don’t look too closely, the server responds with a script
that contains a call back function that contains any requested data to application. In this
example we’re calling back with the return data bar, this will call a function you have
defined globally, returning control to your application with any data you have requested.
JQuery will abstract most of these details away from you if you tell to it make a JSONP
request to a server all you need to do is make sure your server properly returns a call
back. There is some problems with the strategy though for one thing it’s only capable of
sending get requests. If you’re a reuqest fanatic the thought of using it hurts you
to very core on top of that in order to fit our entire image, our URL would have to be
over 50,000 characters long. Theoretically there’s no limit on URL size many standards
compliant servers browser start to choke our about 2000 characters having a crazy long
URL will make logging very difficult. It seems like a bad idea to use JSONP this way which
takes us to other strategy. CORS. CORS, or cross origin resource sharing is a relatively
new feature now supported in all browsers. It’s really simple before making a call to
your browser it will check to receive your URL returns a special access control allow
origin header containing the domain you are now browsing
from or a while the card which will allow the resource to from any script. Once the
browser has checked it’s ok it will gladly lift the barriers of the same origin policy
for you. So this again can be abstracted away with a jQuery option as long as you spend
5 minutes or so making sure you server supports it. That’s it. That’s all the technical detail
I have for you now let’s look at some horse drawings. Now you might imagine the distribution of
horse drawings might look like this. {laughter} 5% actual horse drawings, 95% obscene drawings
but in fact after looking at a sample of 100 horses the actual numbers look a lot more
like this with 11% incomprehensible scribbles, 23% recognisable horse which is a surprisingly
large number, 1% of obscene drawings, 30% with some stamps and 36% with way too many
stamps. It’s really common for people to discover the stamp tool right away then draw we something
that looks like this. Some of the horses that were drawn were simplistic. Minimalistic,
other horses were complicated, rich in detail. {laughter} some people were quite talented
at horse drawing. This person seemed to have a lot of trouble drawing a horse. Their next
drawing supported this theory. {laughter} some horses were magical, some were fat, some
people had trouble drawing really compelling horses some horse artist were very literal
just writing the word horse. Quite a few of them actually. Horse yo. I draw a horse, this
one looks like an engineer drew a horse. One user went in a clever direction and actually
drew a horse drawing a tycoon. {laughter} another user drew me an ancient cave painting.
I have many more interesting horses I could show you. There are over 2000 that have been
posted since I built the application, but after all this talking, I am feeling a little
hoarse. Hah, hah another horse pun. So that’s the presentation. I understand that I have
thrown a lot of information up on these slides so if you want to see anything you have left
you can get the whole slide deck off of this URL. There are also available from my home
page at Curtis.Lassam.net but my home page is served out California it’s not behind a
CDN, the whole presentation could take you several days or years to actually load which
is why it put it up here behind my CDN. Thanks for watching everyone. {applause}

Leave a Reply

Your email address will not be published. Required fields are marked *