Introduction to Stage.js
Stage.js is a lightweight and open-source JavaScript library that you can use for cross-platform 2D HTML5 game development. This library uses a DOM-like model to manipulate the canvas and manages the rendering cycles of your application all by itself.
In this tutorial, I’ll introduce you to this library, trying to cover everything you may need to know how to start using it with ease.
Let’s start!
Setup and Usage
Firstly, you have to download the library. You can get the latest version of Stage.js from its GitHub repository (here are included a few examples to get you started). If you prefer, you can also load it directly from a CDN. After including the core file, you have to add your own JavaScript file but be careful to not include your application files before the library.
<script src="https://cdnjs.cloudflare.com/ajax/libs/stage.js/0.8.2/stage.web.min.js"></script>
<script src="path/to/your/stage/application.js"></script>
Applications in Stage.js are created by passing callback function to Stage()
. The library will then load all the required components. Finally, it’ll call the callback function and render everything on screen. Every app you create will have a tree, and stage
will be at the root of that tree. All the other elements such as images or strings will be its nodes. The application tree is redrawn while the nodes are updated during each rendering cycle.
Pinning
Pinning determines how the nodes are attached to their parents. You can set a lot of options with pinning. A few of these are size, positioning, alignment, and transformation. Below you can find a simple example with the explanation of what it does.
Stage(function (stage) {
stage.viewbox(700, 700);
Stage.image('wheel')
.appendTo(stage)
.pin('handle', 0.5);
});
Stage({
name: 'wheel',
image: 'wheel.png'
});
We begin by specifying the viewbox size. We have appended the image wheel.png
referenced as wheel
to the stage. After that, we set the initial position of this image or node using handle
. The handle
on any node, places itself at a specified offset from the align point on its parent. Both handle
and align
are specified as relative units. For example, 0 is top-left and 1 is bottom-right. The above code positioned the wheel at the center of the viewbox.
A live demo of the example is available on CodePen and shown below:
See the Pen YyKQLx by SitePoint (@SitePoint) on CodePen.
To position the image at a specific horizontal distance from the center you can use ‘offsetX’ as shown below:
Stage.image('wheel')
.appendTo(stage)
.pin({
handle: 0.5,
offsetX: 300
})
);
Please note that the distance above is not 300px, but it’s 3/14
times the viewbox size. You can also set other values for nodes like scale
, skew
, and rotation
. To scale in a specific direction (horizontally, for instance), you can use scaleX
. The code snippet below will scale the wheel horizontally by a factor of 1.4.
Stage.image('wheel')
.appendTo(stage)
.pin({
handle: 0.5,
scaleX: 1.4
})
);
Here is the CodePen demo with scaled wheel applied.
Rotation, scaling, and skewing by default will happen with the node center as pivot point. You can also set a different pivot point for nodes using:
node.pin({
pivotX: x,
pivotY: y
});
To sum it up, pinning the elements gives you the ability to move them around and scale or rotate them.
Mouse and Touch Events
To update nodes on user interaction you can use various mouse and touch events. Moving a step forward with the example of our wheel above, we could write the following code:
var wheelNode = Stage.image('wheel').appendTo(stage);
wheelNode.pin({
'handle': 0.5
});
wheelNode.on('click', function () {
// Do something with the wheel here.
});
Alternatively, you can define these events like Stage.Mouse.CLICK = 'click';
. The updated code would be:
wheelNode.on(click, function () {
// Do something with the wheel here.
});
Another example would be Stage.Mouse.MOVE = 'touchmove mousemove';
.
Tweening
Tweening applies smooth transitions to pinning values. This prevents abrupt changes in location or size of concerned nodes. For example, the code below will rotate the wheel abruptly by PI
radians and change its position by 600
on each click.
var wheelRotation = Math.PI;
var wheelPosition = 300;
wheelNode.on('click', function () {
wheelRotation = -wheelRotation;
wheelPosition = -wheelPosition;
this.pin({
rotation: wheelRotation,
offsetX: wheelPosition
});
});
This is the demo without tweening which is also shown below:
See the Pen YyKQvx by SitePoint (@SitePoint) on CodePen.
However, adding the tween method makes the transition smooth.
wheelNode.on('click', function () {
wheelRotation = -wheelRotation;
wheelPosition = -wheelPosition;
this.tween(3000)
.pin({
rotation: wheelRotation,
offsetX: wheelPosition
})
.ease('bounce');
});
Here you can find a demo with tweening and easing applied, also shown below so that you can see the difference:
See the Pen XmrgBb by SitePoint (@SitePoint) on CodePen.
There are a lot of available options like easing method, duration and delay. In the code above, I have set the duration to 3000 ms and easing function to bounce
. Moreover, you can use several easing functions such as linear
, quad
, cubic
and quart
.
Setting a delay will start the transition after a specified delay. If there is no need of a node after the animation completes you can call tween.remove();
to remove the node. To perform some other operations, you can execute a callback function after tweening has completed using following snippet:
tween.done(function () {
//Perform your actions here.
});
Texture Atlas
Textures are used by tree nodes to draw graphics on the canvas. To display graphics on the canvas you can use a sprite sheet also called “texture atlas”. Setting the name of texture atlas is optional. A sprite sheet needs to have a set of named textures. To use these in an application we can reference them by name. You can create animations using an array of textures as frame. An animation or anim
itself is a node. Here is an example with an animated warrior:
Stage({
name: "warriorsprite",
image: {
src: "warriorsprite.png"
},
textures: {
w1: {
x: 0 * 120,
y: 0,
width: 120,
height: 320
},
w2: {
x: 1 * 120,
y: 0,
width: 120,
height: 320
},
w3: {
x: 2 * 128,
y: 0,
width: 128,
height: 320
},
w4: {
x: 3 * 128,
y: 0,
width: 128,
height: 320
},
warrior: ['w1', 'w2', 'w3', 'w4']
}
});
To animate the warrior you need the following code. To make it faster you can increase the fps
. :
Stage(function (stage) {
stage.viewbox(320, 320);
Stage.anim('warrior')
.appendTo(stage)
.pin('align', 0.5)
.fps(8)
.on('click', function () {
this.play();
});
});
To see the warrior animated, take a look at this demo or at the demo below:
See the Pen RWbgBj by SitePoint (@SitePoint) on CodePen.
anim
also has a lot of other methods like gotoFrame(n)
, which will take you directly to the n-th frame. Depending on the value of n, you can also move n frames forward or backward using moveFrame(n)
.
Conclusions
In this introductory tutorial, we covered everything that you need to know how to get started with Stage.js. The concepts discussed should help you creating basic character animations using sprites and interact with user. You can learn more about the library from the official website. I would also suggest you to download the files from its GitHub page. The included demos in downloaded file will further clear things up.