Embedding assets with Spine Web Player

April 6th, 2020

Sometimes, all you want in life is a simple .html file that contains all the assets needed to show off your fine Spine skeleton, its animations, and its skins. No pesky web servers required. Just double click the .html file and your browser will show your beautiful art.

We've added this capability to Spine Web Player and by proxy spine-ts and all its backends for WebGL or Canvas! Let's see how it's done.

Data URIs - Preparing your assets

When you want to tell your browser to load an asset, like a .png file, you specify an URL, for example:

<img src="https://mydomain.com/images/myimage.png">

Or a relative URL, for example:

<img src="/images/myimage.png">

When the browser encounters such a URL, it asks the server to send the data for that file.

We need to find a way to avoid talking to the server at all. Thankfully, modern browser standards give us a tool to do just that: data URIs.

A data URI is a long text that starts with data:, followed by a MIME-type, followed by the actual data of the file. The data itself is Base64 encoded. This way, even binary data can be safely dumped into an HTML file.

To convert a file to a data URI, we can use one of the many data URI encoders. The basic principle is always the same:

  1. Specify a file or URL to a file.
  2. Click "Upload" or "Encode" or whatever button is shown.
  3. Copy the data URI text.

I did just that for the atlas page of our Raptor example, which is located at http://esotericsoftware.com/files/examples/raptor/export/raptor-pma.png. Using this HTML element:

<img src="http://esotericsoftware.com/files/examples/raptor/export/raptor-pma.png">

We end up with this nice image:

raptor

If we used the data URI version of the file, the tag would look like this instead:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhE....">

Note that I cut off most of the data URI above, as it's very long. The size is the price to pay when we want everything to be embedded in a single .html file.

Now that you know about data URIs, it's just a few steps to get your exported Spine assets prepared for embedding:

  1. Open your Spine project in Spine and export the skeleton data to .json or .skel, and your atlas to a .atlas and one or more .png files.
  2. Encode each file with the data URI encoder and store each resulting texts somewhere, e.g. a file or temporarily in a text editor of your choice.

That's it! You are now ready to embed your assets together with the Spine Web Player.

Setting up the Spine Web Player with embedded assets

We've previously discussed the Spine Web Player on this blog. If you are rusty on the details, I suggest you quickly head over to that blog post and refresh your memory.

Here's a basic .html file that uses the Spine Web Player to display the Raptor:

<script src="https://esotericsoftware.com/files/spine-player/3.8/spine-player.js"></script>
<link rel="stylesheet" href="https://esotericsoftware.com/files/spine-player/3.8/spine-player.css">
<div id="player"></div>
<script>
new spine.SpinePlayer("player", {
jsonUrl: "https://esotericsoftware.com/files/examples/raptor/export/raptor-pro.json",
atlasUrl: "https://esotericsoftware.com/files/examples/raptor/export/raptor-pma.atlas",
animation: "walk",
backgroundColor: "#666666",
});
</script>

We can see that we tell the player to load 2 files: raptor-pro.json and raptor-pma.atlas. When the player reads the .atlas file it sees that it also needs to load another file, raptor-pma.png, the image making up the first (and only) atlas page.

All these files are loaded from our servers. To avoid that and instead keep everything in a single .html file, we can use the new configuration property rawDataURIs. I have converted the files raptor-pro.json, raptor-pma.atlas, and raptor-pma.png to data URIs as described in the last section. Next I rewrote parts of the script above:

<script src="https://esotericsoftware.com/files/spine-player/3.8/spine-player.js"></script>
<link rel="stylesheet" href="https://esotericsoftware.com/files/spine-player/3.8/spine-player.css">
<div id="player"></div>
<script>
new spine.SpinePlayer("player", {
jsonUrl: "raptor-pro.json",
atlasUrl: "raptor-pma.atlas",
rawDataURIs: {
   "raptor-pro.json": "data:application/json;base64,ewoic2tlbGV0b...",
   "raptor-pma.atlas": "data:application/octet-stream;base64,CnJhcHRvc...",
   "raptor-pma.png": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU..."
},
animation: "walk",
backgroundColor: "#666666",
});
</script>

I have again cut off the data URIs in the above snippet as they are super long. Let's see what we changed.

First, we rewrote the jsonUrl and atlasUrl properties. Instead of specifying a full URL, we just specify a file name (relative paths). Next, we added the rawDataURIs property. It consists of "filename": "data URI" pairs, one for each file we need to load and render the raptor. That's it!

The Spine Web Player will then try to load the jsonUrl. Since the raptor-pro.json data is given in the rawDataURIs property, the player takes the data directly from there instead of asking a server to provide it. The same happens for the raptor-pma.atlas file. When the atlas file is loaded, the player sees that the atlas needs the image raptor-pma.png. And since we specified that in rawDataURIs as well, there is not a single request to a server, except for the player JavaScript and CSS, which you can also embed.

Of course this also works with binary skeleton data:

<script src="https://esotericsoftware.com/files/spine-player/3.8/spine-player.js"></script>
<link rel="stylesheet" href="https://esotericsoftware.com/files/spine-player/3.8/spine-player.css">
<div id="player"></div>
<script>
new spine.SpinePlayer("player", {
skelUrl: "raptor-pro.skel",
atlasUrl: "raptor-pma.atlas",
rawDataURIs: {
   "raptor-pro.skel": "data:application/json;base64,ewoic2tlbGV0b...",
   "raptor-pma.atlas": "data:application/octet-stream;base64,CnJhcHRvc...",
   "raptor-pma.png": "data:image/png;base64,iVBORw0KGgoAAAANSUhEU..."
},
animation: "walk",
backgroundColor: "#666666",
});
</script>

Instead of using the jsonUrl property, we use the skelUrl property. In the rawDataURIs section we specify the data URI for the .skel file.

Binary skeleton files are quite a bit smaller on average than their corresponding .json files, so use binary skeleton files if possible.

Note: When embedding data URIs for skeleton .json or .png files, your editor of choice might freeze a little or be sluggish because the lines are so long. Turning off line wrapping may help. An alternative solution is using an editor like Sublime Text or Visual Studio Code, which work well even with long lines.

Up next

We'll include a new export option in the next version of Spine, giving you a one click solution to do all the above. The end result will be a .html file you can open from disk with any web browser. This way friends and co-workers to easily view your work. Stay tuned and keep an eye out for our next release!

Share your thoughts on the Spine forum.

Skin constraints for different proportions

March 11th, 2020

Skin constraints are a great way to increase the expressiveness of your skeletons. In this blog post we'll explore how to use skin constraints to alter the proportions of a character using the Mix-and-match example project.

The Mix-and-match project is part of our set of example projects that come installed with Spine. The project can be found by opening the welcome screen, then clicking Examples. Alternatively, the project can be downloaded from the example page. The example page contains detailed explanations of the project's inner workings. Go ahead and open the project in Spine!

The goal of this exercise is it to create a skin variation that not only affects the set attachments, but also the proportions of the character. Specifically, we want the skin to make the character smaller. The technique described below can of course also be applied to create taller, skinnier, or fatter characters, and anything in between.

Constraint setup

Let's get started! With a change in proportions, the location of the hips also changes relative to the root of the character. This can be done via a transform constraint.

Select the hips bone and create a new transform constraint with the root bone as target. Call the constraint small-hips.

With the small-hips constraint selected in the tree, check the Relative option and set the translate mix to 100. The constrained hips bone will now follow the translation of the root bone. The hips bone will be offset relative to the root bone by the translate offset set on the small-hips constraint.

The legs of the character will not look nice after the creation of the small-hips constraint. This is due to the constraints order. We want the small-hips constraint to be applied before all other constraints. To fix it, drag the small-hips constraint to the very top of the list under the Constraints node in the tree.

To see the effect of the constraints, modify the translate offset on the small-hips constraint, e.g. set it to -85 on the y-axis to make the character squat.

It is time to turn our character into a tiny, adorable human! Select the 8 bones called arm-front-up, arm-front-down, arm-back-up, arm-back-down, leg-up, leg-down, leg-up-back, and leg-down-back, as in the image above.

Next, create a new transform constraint called small-limbs with the root bone as its target.

As before, we need to fix the constraint order. Drag the small-limbs constraint right below the small-hips constraint under the Constraints node.

In order to make these 8 bones smaller, check the Local option and set the scale mix to 10.7. We can then set the offset scale value on the x-axis such that the character's legs straighten out. A value of -2 works nicely.

Skin constraints

We can now add the small-hips and small-limbs constraint to a skin, which means the constraints will only be applied when that skin is active.

Create a new skin and name it small. Drag and drop the small-hips and small-limbs constraint nodes to the small skin under the Skins node.

Alternatively, first select the small skin, press the Add to skin button, select the constraints small-hips and small-limbs, then press the button Add to skin again to complete the process.

Done!

To create a tall, skinny, or fat variation, simply repeat the above process. Each variation will require its own constraints and skin. Multiple skins can be active at the same time using the Skins view, so you can combine skins that change proportions with other skins that change attachments. You could even have separate skins for changing the proportions of the legs, arms, torso, etc and combine them however you like.

This simple technique can be applied to more than just proportions! It is a powerful way for skins to affect not just which attachments are visible, but the skeleton's bone transforms.

Discuss this blog post and share your experiments on the [Spine forum]().

Unity Universal Render Pipeline support

March 9th, 2020

Animated Universal Render 2D Demo

We are happy to announce support for Unity 2019.3's Universal Render Pipeline and its 2D Renderer feature set in our spine-unity runtime!

The Universal Render Pipeline (URP) is a prebuilt Scriptable Render Pipeline (SRP) optimized for delivering high graphics performance and is the successor of the Lightweight Render Pipeline (LWRP). It scales seamlessly from mobile platforms to high-end PCs and consoles. It adds a new 2D Renderer workflow, providing a flexible 2D lighting system designed specifically for 2D games.

There is now an additional Unity Package Manager (UPM) package com.esotericsoftware.spine.urp-shaders available for download which extends the spine-unity runtime by adding URP support.

Why a separate package

Unity has moved many of their optional modules to the new Unity Package Manager (UPM) ecosystem. Their URP base shader files are also provided as a UPM package under the name Universal RP and not part of every new Unity project out of the box.

Including our URP Spine shaders in the spine-unity runtime would lead to confusing error messages and additional configuration steps in case Unity's Universal RP package has not been installed in a project. By providing our URP Spine shaders as a UPM package, such dependencies are automatically resolved, making it easier to use this additional functionality.

Going forward, we will provide separate UPM packages for other spine-unity features that depend on Unity's optional packages.

Installation

You can download the UPM package via the download page or find it in the spine-unity/Modules subdirectory in the Git repository. Please follow the guidelines on Installing Extension UPM Packages on our spine-unity documentation pages on how to install the package.

URP examples

URP shader selection

The package contains two example scenes similar to the animated GIFs above at com.esotericsoftware.spine.urp-shaders-3.8/Examples/2D/URP 2D Shaders.unity and com.esotericsoftware.spine.urp-shaders-3.8/Examples/3D/URP 3D Shaders.unity for you to check out. These demonstrate how to use the URP shaders in the respective 2D and 3D renderer setup. Note that the scenes react to changing the settings of your current UniversalRenderPipelineAsset, set under Project Settings - Graphics.

Usage

The standard Spine shaders in the spine-unity runtime Spine/Skeleton Lit, Spine/Sprite/Vertex Lit and Pixel Lit are not compatible with the universal render pipeline. Instead, the Spine Universal RP Shaders package provides shaders specifically built for the universal render pipeline, including 2D Renderer support:

  1. Universal Render Pipeline/2D/Spine/Skeleton Lit

    Universal 2D Renderer variant of the Spine/Skeleton Lit shader.

  2. Universal Render Pipeline/2D/Spine/Sprite

    Universal 2D Renderer variant of the Spine/Sprite/Vertex Lit and Pixel Lit shaders.

  3. Universal Render Pipeline/Spine/Skeleton

    Universal variant of the Spine/Skeleton shader.

  4. Universal Render Pipeline/Spine/Skeleton Lit

    Universal variant of the Spine/Skeleton Lit shader.

  5. Universal Render Pipeline/Spine/Sprite

    Universal variant of the Spine/Sprite/Vertex Lit and Pixel Lit shaders.

The shaders can be assigned to materials as usual via the Shader menu in the material properties:

URP shader selection

The universal render pipeline shaders will respect your settings of the assigned UniversalRenderPipelineAsset under Project Settings - Graphics. The following GIF shows how the characters in the scene are affected by changing these settings:

Project settings - URP asset

URP asset settings live update

Restrictions

Like all other Spine shaders, the LWRP shaders do not support Premultiply alpha (PMA) atlas textures when using the Linear color space. If you are using the Linear color space, please export your atlas textures as straight alpha textures by disabling the Premultiply alpha setting. See these instructions for straight alpha export and import settings for more information.

If you are unsure you can check the currently active color space via Edit > Project Settings > Player > Other Settings > Color Space.

Player Settings - Gamma

We hope that these additions to the spine-unity runtime let you create even more impressive games and apps for both high- and low-end devices. Share your thoughts on the forum.

Distance limit setup for eyes

February 24th, 2020

final result

Flexible eye rigging can bring even more life to your characters. In this tutorial we'll create an eye rig that always looks at a target, without the iris and pupil going outside the bounds of the eyeball. This is the long form version of a tip we previously published. Let's go through it step by step!

Images setup

circle

For the purpose of this tutorial, we'll keep things simple. The eyeball is made up of a white circle image located in our image path. We drag it from the images node into the viewport, then duplicate its slot.

circle

We'll turn this second circle into the iris of the eye. All we need to do is change the color of the attachment to an iris color we like. Images can be scaled and translated independently of bones in setup mode, so we'll scale the copy down to make it smaller in proportion to the eyeball. To establish the limit beyond which iris should not move, we also translate it so that it touches the border of the white circle beneath it.

circle

Next, we duplicate the iris slot to create the pupil. Pick a new color for the image attachment and scale down the attachment as before.

Lastly, let's also add a tiny reflection of light on the pupil. Duplicate the pupil slot, make it smaller, change its color to white and place it on top of the pupil.

Finally we are ready to start creating some bones!

Bones setup

bones

To get the desired effect, we need to create 3 bones. The limiter bone originates from the center of the eyeball and extends to its border. It's angled at to make alignment easier later on.

The pupil bone is placed in the middle of the pupil, which also aligns with the midpoint of the limiter bone. All the images except the white eyeball are parented to this bone. The pupil bone itself is parented to the limiter bone.

Lastly, the target bone is placed along the axis the other two bones are placed at. It is parented to the root bone.

IK setup

ik

Time for the magic trick! As a first step, we create an IK constraint, with the limiter bone as its parent and the target bone as the target. This causes the limiter bone to always point at the target bone.

By enabling the IK compress option on the IK constraint, we allow the limiter bone to shrink and grow as the target bone comes closer to or gets farther away from it. This way, the iris and pupil can move freely within the eyeball instead of being constrained to the eyeball's border.

If we move the IK target bone around, the iris and pupil will get distorted. This is due to the parent bone's rotation and scale being applied to the pupil bone. To fix it, we simply disable the rotation and scale inheritance on the pupil bone.

inherit

Result

final result

This simple setup lets the pupil and iris follow the target bone nicely, without distortion or going outside the eyeball!

You can download the finished project here.

The setup presented above is a general way to limit movement of elements to a circular area. Can you think of other use cases? Share them on the Spine forum!

Older