A guide to using the Flash-beating JavaScript graphics library, from one of its creators

Getting animated with Bonsai
Kommentare

What is Bonsai and some History

Bonsai is an open source graphics library that intends to make creation of graphical content easy.

Back in the days when developers started to realize the power of mixing JavaScript with HTML and manipulating content on the fly, the temptation to use JavaScript to create graphics from scratch by creating simple things such as a rectangle or a circle (shapes) or manipulate animations became very tempting. But the technologies that allowed to do that had not yet been embedded in browsers or had been hard to access. SVG was one of the first of those technologies, along with its counterparts VML (in Internet Explorer), that allowed to do these kinds of things. In 2005, Apple started to use some pixel manipulation technology for their Dashboard that they had integrated into OS X Lion. That was the point in time when graphics in the browser with JavaScript really took off.

Canvas became a standard, SVG found its way into the toolset of every developer, all major browsers supported it and the “design department of the internet” became aware of the power of SVG as a vector based format, which made blissfully non-pixelated graphics easy.

During that time, Flash had already taken the lead when it came to graphics, animations and so on. HTML5 had to catch up, and it is doing well right now.

With Bonsai we created a library that with a focus on being pleasant to use for any JavaScript developer and enabling creativity by providing an API that makes the creation of any kind of graphical content easy.

Why is the Bonsai architecture important?

While creating Bonsai we had one big goal in mind: put all the power of graphics in your hands. Bonsai was created as part of our “big plan”, which was to create pixelplant.com – a service for converting Flash to HTML5. The minimum feature requirements, therefore, was to provide all what Flash offers too, but in HTML5.

We knew that there were challenges ahead that we needed to take into account when designing the library, not around the feature set of graphics and the power of it but of the following:

  1. There are multiple graphics interfaces provided and probably more to come, such as SVG, Canvas, WebGL and HTML/CSS itself.
  2. The computing power of JavaScript in a browser is limited to one thread, which on top also interferes with the rendering engine of the browser.

Those two problems had been high on our list to be solved. And we baked them right into Bonsai from the very beginning.

Item 1 we solved by abstracting out the renderer into its own layer, which only should take care of using the according API of the rendering service. In the current version of Bonsai we decided to implement SVG first due to its simplicity for accessing each of its layers and maintaining that structure. This made manipulation of objects easy, since there is no separate maintenance layer required but we can edit a rectangle we’ve already created, apply a filter to it, move it around etc. just with the pure power of SVG. In canvas a bit more work is required to do that, since you are writing all objects into one element and there is no direct reference to the rectangle you once created. If you put another shape on top, you have to redraw the entire canvas or apply some additional intelligence in order to update the view correctly. Another thing that makes SVG easy to use is the event handling. Every object created via SVG can have its own event handlers and therefore can receive events, including the correct behavior when such an element is covered by another one.

One drawback exists though: SVG has received little love with native GPU acceleration yet (IE10 is the only browser to have implemented it so far). But hey, Bonsai’s architecture allows for replacing the renderer with one for Canvas or WebGL, so even hybrid solutions are possible.

Using WebWorkers

The single-threadedness of JavaScript, item 2 on our list, was one of the most exciting things we wanted to solve well. That we have to separate the renderer (described in item 1) from the runner was clear early on. We use the word “runner” to describe that part of the code where all calculations for animations etc. take place, so that the runner just spits out rendering messages for each frame, which are very similar to the feature set of SVG. A frame’s rendering data looks something like this:

  • draw a rectangle at 100×100 in red
  • move circle1 to 200×200, set its border color to blue
  • remove image2

All calculations that lead to those instructions are done in the runner. If there is just a simple animation or a complex physics engine behind it, the runner does the job and just passes on “stupid” rendering messages.

We put the runner into a WebWorker and all existing execution time of the main thread of our browser is available to the renderer for rendering operations.

Renderer and Runner communicate by sending messages.

Figure 1: Renderer and Runner communicate by sending messages.

In other words, that means if your game implements the logic to calculate where and when the ball in your pong game is rendered, this does not interfere with the actual rendering thread. The renderer is the only thing that runs straight in the browser’s main execution thread, and it pulls rendering messages from the WebWorker whenever it is done rendering a frame. This way the synchronization of those two layers is done as fast as the renderer can handle it. The WebWorker is running in a parallel thread that executes the JavaScript and mostly is much faster than the rendering thread. For a pong game this separation might not have huge advantages, but just imagine a physics engine spitting out rendering messages, and calculating user events into the rendering result: that’s when the real power of this architecture comes to life.

If you want to go one step further you can try bonsai’s node runner, which executes the runner part on a NodeJS server and the renderer pulls the data from it, so the browser has nothing else to do but render. Of course the latency of the network becomes important here! But you can serve multiple clients at once, and with a little work multiplayer games can be a great use case.

One Runner (on node.js) can also serve multiple renderers.

Figure 2: One Runner (on node.js) can also serve multiple renderers.

You may ask: what about browsers that don’t support WebWorkers? Well, in that case you can lean back and use the iframe runner, which works just the same, but does just not have the advantages of the parallel thread. In most cases, though, it does the job well enough.

Show me some bonsai

Now that you know the architecture of bonsai, you want to see some code. The best way to get familiar with bonsai is definitely to go to orbit.bonsaijs.org and try it out yourself. Orbit is a live editor where you can edit the bonsai code and see the resulting graphics in a live preview. Make sure to try all the examples.

The live bonsai editor, orbit.

Figure 3: The live bonsai editor, orbit.

Anyway, to get a feeling for bonsai, here is probably one of the simplest things you can do with bonsai, draw a red rectangle:

var r = new Rect(100,100,100,100).fill("red").addTo(stage);

The code above draws a rectangle of 100×100 at the position 100×100, fills it with red, and the most important part, so you can see the rectangle: it adds it to the stage. The stage is the drawing canvas where all things you create have to be added to, or will stay invisible otherwise.

After knowing how bonsai is built under the hood, you can imagine that everything until the addTo() call happens in the runner. That does also answer why this example is so bad in using namespaces, because the code gets loaded into the runner environment with its own scope and executed there. And this runner environment exposes things like Rect and stage. So we can take the secure shortcuts of leaving out the bonsai namespace prefix, since everything under bonsai is exposed into the scope which your bonsai movie runs in. So we can safely be that bad in using namespaces.

But a static rectangle is boring, so let’s at least make it look as if it kinda falls down.

r.animate('1s', {x:200, y:500, easing: 'bounceOut'});
r.animate('1s', {rotation:Math.PI/2, easing: 'expoOut'});

Of course it doesn’t stop with shapes. You can load images and modify them, like so:

new Bitmap('bg.jpg')
        .addTo(stage)
        .attr('filters', [
            filter.opacity(0.13), filter.grayscale(1)
        ]);

The image is loaded, added to the stage in order to show it, and modified with some simple filters. You can see one of the powerful functions here, attr. This allows you to modify all attributes of the object it’s applied to. Let’s see it in action by applying it to mouse moves and grabbing that position to modify the rectangle’s x position and its color (yes, you can also calculate with colors).

stage.on('pointermove', function(e) { 
        r.attr({
            x: e.x, 
            fillColor: color('#FF0000').darker(e.x/2000)}); 
    });

Depending on the x position, the rectangle is moved and the color is adjusted to a red that gets darker the further your mouse moves to the right. Now you have a start for a pong game. You can play and read about our bonsai pong game at bit.ly/bonsaipong.

Now you know enough to start playing with bonsai! There is so much more to it, but let me just list a couple of things to get you hooked: gradients, audio, video, timeline control, paths, text, grouping, filters, masks, events, matrix, clipping and scaling.

Bonsai in Action

Pixelplant is the platform that kicked off bonsai. On pixelplant we are converting Adobe Flash files (SWFs) to HTML5 and, as you can probably guess, all the resulting code uses bonsai. So bonsai is the heart of our platform. But before a binary SWF file (the Flash files distributed on the web) is turned into a running HTML5 file, lots of work has to be done.

But first, let’s look back a bit. Tobias Schneider (@tobeytailor) once had this crazy idea to load SWFs in the browser and run them with web technologies – and not with Adobe’s Flash plugin. Five years ago this sounded like a really crazy idea. And back then SVG was also the best option to use, as it was so old, mature and there was no GPU accelerating canvas yet. Back in the present: we moved to a server side conversion from the original in-browser solution, which is what pixelplant does now. But it’s all written in JavaScript! The entire server-side runs on node.js and in the browser we rely on bonsai. The process is built on multiple node-modules we have been building, a SWF parser, that takes apart the binary file and extracts all assets and the structure of the raw SWF data, which is basically what you can create with the Flash IDE, those are translated into JSON data that we send through our runtime that generates bonsai objects.

The more sophisticated part is the integration of the scripting language that Flash ships with. From the bytecode contained in the SWF file, we generate JavaScript which can even interact with the data contained in the JSON.

One of the features that is about to ship is the translation of this bytecode back to real editable JavaScript code. Since ActionScript is based on EcmaScript, we can provide code that the actual developer will still feel comfortable with, because it is the source he once wrote and compiled into the binary SWF file.

Under the Hood

Looking under the hood, we are making very much use of bonsai’s features. Flash files live for effects, animations and interactions. Lots of those features, simply speaking, map 1-to-1 to bonsai. And the bonsai.Movie is an object that provides control for any kind of graphical object on a timeline just like ActionScript MovieClip class. So when an animation involves moving and blurring the text in Flash, as you can see in the example on bit.ly/pixelplantSample we can use the bonsai functions to replicate that exactly. And on pixelplant we also provide the ActionScript libraries as JavaScript libraries. The converted Flash movies and interactive code looks nearly the same as the original one. We are giving users the assets that seemed lost, due to the fading of Flash’s relevance, back into their hands, so all the work that had been invested into creating Flash movies is not wasted.

Get Creative

Bonsai as an open source project is intended to move the web forward, to make the creation of graphical content easier and abstract away technology. On top of that, we are also proving again that a business around open source is very much doable, and we hope to continue growing bonsai and pixelplant into even more mature and further-reaching tools that will allow creative people to easily express their ideas.

Wolfram Kriesing co-founded uxebu in 2008, where he does high-end JavaScript consulting. In 2012 uxebu started pixelplant a Flash to HTML5 converter, which made him probably one of the last people on earth to learn Flash, but all just in order to use the extensive HTML5 knowledge gained over the years in order to automatically convert Flash to HTML5. He is a coder by heart, applies TDD to everything he codes and practises lean on his business.

Bonsai image ©Software & Support Media GmbH

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -