I Made A Thing: Pixel Art Creator

Darryl Dixon
Jul 24, 2017 · 6 min read

Recently I’ve been working on things that I think are cool. Mostly for no reason other than they were interesting at the time. So I’m gonna tell you about those things and how I did it (and if they ever get updated I’ll make a new post about it).


Today’s thing that I made is a simple pixel art gif creation tool.

The interface. Not that nice, but I did make the icons myself using Gravit Designer

I came across this idea after observing the art of many indie games, most of which feature a pixel art style. It almost made me want to make my own pixel art! Almost… but I’m not a creative person. But what I can do is program, and somehow this observation inspired me to explore HTML5 canvas by creating a tool to make animated pixel art.

Very early development of the tool

Having never used the canvas API before I wanted to know how it really worked. So I decided to not use any libraries or frameworks for this project.

Getting it to paint on the canvas was one thing. Getting it to paint in squares and in a grid-like fashion was another. Getting it to paint in squares in a grid-like fashion on a grid of varying size was yet another thing. I suck at math so I thought this would take longer than it actually did, but once I figured that out I could move on to something better (math makes me anxious).

The next thing I needed to work on was making the created images animate-able, otherwise this project is nothing and entirely too easy. Well, the solution to this part seemed pretty obvious:

  • make an array for the frames
  • make a variable to track the working frame
  • create a function that would store the image data in the array

Okay, that’s done. Sick.

Lastly I made a function to create a visual representation of the frames and put them in the DOM. I can click on these frames and see the image data for that frame.

Neat!

Now what’s the point of making a pixel art gif creation tool if you can’t make gifs? Well, that’s where Graphics Magick comes in (with the help of the GM Node package). Having already experimented with GM before I already new how to use it… server side. How would I get the image data to the server to process and make a gif? Well, the steps are as follows:

  • get image data URL for each frame
  • put that image data in an object
  • send said object to the server
  • convert the image data into binary for each frame
  • ask Graphics Magick nicely to turn the binary data into a gif

Then at this point I had the option of either immediately sending the gif back to the client, or store it and send a URL that they can use to access it. I don’t know why I chose the latter… I should probably change it to the former… but, anyway, I went with the latter, which deletes the gif from the server once requested.

Now, at this point I realized that I was really enjoying this project. I did not plan on working on this project much longer than I already have. But here I am… and I got this crazy idea that I should add a selection tool.

Okay, so all I need to do is use the API to move pixels around… right?

Nah.

The canvas API does not have any such method of moving pixels around… uhh… what do I do now?

Well, the only option was obvious… I had to restructure my data. I needed an object to maintain the pixel data so that I could manipulated later.

Here’s what I came up with:

This frame data object would hold the pixel data for every frame. Seems legit. Now that I had data I could work with this selection tool.

I think this would be a good time to explain a bit about how the grid works:

  • the canvas is x width and height (canvasWidth = x)
  • the grid will be y by y pixels
  • the position of the pixel needs to be offset by the position of the mouse: e.g., offsetX = Math.floor( (mouseX / canvasWidth) * x)
  • the left of the pixel will be (offsetX / y) * canvasWidth
  • a pixel will x / y width and height (height = width = x / y)
  • the center of a pixel is pixelWidth / 2 (e.g., centerX)

Okay, that took me a while to explain. I hope I explained it well. Here’s the whole function:

https://gist.github.com/piecedigital/73094baeb81447e1961b83e4a0dbffd8

So now that I have this data all I need to do is get the coordinates for the pixels. I wont go into details here but here’s the basic idea: by manipulating the x and y coord numbers (they’re key’d as “centerX” and “centerY” in the object) and recreating the coordinate key in the frame data ([centerX]_[centerY]) I can select all of the pixels in an area, move them around, and reset their position in a frame.

Neat!

Layers. This was a little tough but not as tough as tough as moving pixels. Basically I had to move what I was already doing one level deeper, if that makes sense.

Here’s that frame data I showed before but with layers taken into account:

https://gist.github.com/piecedigital/d4d45f303a0d9b82b6a49409dcf2e7df

For this I had to:

  • create a variable to maintain the current layer
  • create a simple function that gets the current layer
  • alter the rest of my code so that references to the frame data also take the layer into account

Aight, coo’.

Okay, this one was the most frustrating. It’s somewhat similar to the selection tool in that I needed to search for pixels but this one was different.

  1. The first thing I need to do is remember what color pixels I’m replacing. I do this when the user clicks on an existing pixel. If there is no existing pixel, well, essentially “null” is the space we’re filling
  2. After that’s set I needed to search in 4 directions: up, down, left, and right, and capture those pixels that match the above criteria
  3. Store a reference to the captured pixels so that hey can’t be searched again
  4. Repeat steps 1–3 until the program stops capturing pixels
  5. Draw new pixels in place of the captured pixels
The time it takes for it to start painting is when the algorithm finishes. The time gets slower the bigger the available area is.

For performance reasons this algorithm should not run if the color of the pixel matches the draw color (the color you choose to draw pixel with). Also I am using a web worker for this operation so it doesn’t block the main thread. Even still it’s a slow operation in it’s current form, but it works without issue.

Dope.

The last thing I’ve added was the ability to swap layers.

This isn’t very deep. It’s basically this:

this:

  • layer0: [originally layer 0 data]
  • layer1: [originally layer 1 data]

becomes this:

  • layer0: [originally layer 1 data]
  • layer1: [originally layer 0 data]

Dassit.


Allllllrighty then! That’s the current state of the project. It’s been an interesting project to work on but I’m liking the way it has turned out. If you wanna give it a try you can try it here.

If you wanna say hi my twitter is @PieceDigital, but I don’t post much about web development or anything like that.

Made with Pixel Box

Alright, nothing more to see here. Scoot!

Darryl Dixon

Written by

24. Job searching | #Programmer | #NERFStack | #WebDeveloper | #JavaScript | #CodeNewbie | contact@piecedigital.net

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade