arkm
Share

How to Animate Sprites on the Web

The other day I was thinking back on the my early days building small games with RPG Maker and I was thinking about all the cool sprite sheets I would download and make. I wasso fascinated by sprite sheets and how you could get such complex animations with relatively little. Of course, now that I'm grown up and understand quite a bit more about animation and film in general I know that those sprite animations weren't all that technically advanced. But that doesn't mean I'm any less enamored with them.

I was curious how easy it would be to load a sprite sheet an animate on the web. Turns out it's super easy, barely an inconvenience. Check out my sweet animation:

To create the animation I need to know 2 things: how many individual spites make up the animation (or frames in the animation) and the dimensions of each sprite.

First, I'm going to create a box that is the dimensions of a single sprite and set it's background-image to out sprite sheet.

<style>
	#sprite {
		display: block;
		width: 80px;
		height: 80px;
		background-color: #333;
		background-image: url('https://cdn.glitch.com/f39fa1a5-5693-46f3-ba29-dd9d43879a63%2Fsonic-walk-cycle.png?v=1614057158459');
		background-position: 0 0;
		background-size: auto 100%;
	}
</style>

<div id="sprite"></div>

Next we're going to animate this using the Web Animations API. Why use the Web Animations API here instead of just writing the animation in CSS using @keyframes? Well, I've never used the Web Animations API and wanted a chance to play with it a bit. This could totally be done with just CSS as we'll discuss further down. Thankfully, unlike of JS-based animations, the Web Animations API is optimized in the browser and is as peformant as a CSS animation. So you can safely use either depending on which works best for your situation.

Here's what that code looks like:

const keyframes = new Array(numFrames)
  .fill(0)
  .map((x, i) => ({ backgroundPosition: (i * -1 * frameWidth) + 'px 0' }));

sprite.animate(keyframes, {
  easing: 'steps(' + numFrames + ', jump-none)',
  duration: 400,
  iterations: Infinity
});

And boom, you're done! Behold as your sprite comes to life; you might need to adjust the easing and duration until it looks right. And with little tweaking, this can work for any sprite of any size and any animation of an complexity as complexity is merely the number of frames.

But how practical is something like this? Well, a gif or and SVG can actually end up being very expensive especially if your animation is small in size and contains a lot of moving parts. Making a sprite sheet can actually be more performant than other methods.

In fact, Twitter uses this exact style of animation for their like buttons! Check out this great article detailing that animation. You'll notice they do it using CSS.

With this technique, there a whole new world of animation possibilities that opens up on the web. I look forward for a chance to actually use this on a real project at some point.