The web is a great place to make things, and it's also a great place to showcase your creations. A pixel art editor is a fun project to test your web development skills. It lets you showcase your creativity and has a large potential audience.

So what is pixel art, you might ask?

Pixel art is a form of digital art, created through the use of software, where images are edited on the pixel level.

We will be using many modern web technologies to build this project which will be helpful for you in your future endeavors as well. So let's get started.

Technologies Used

We will use the following web technologies in our project:

  • HTML5 Canvas
  • CSS media queries for responsive design
  • gif.js library for GIF creation
  • progressive web apps (PWA) for an app-like experience
  • Object-oriented design

Features of Our Editor

The web app we will be creating will have the following features:

  • Responsive design (mobile-friendly)
  • Set dimensions of pixel art
  • Basic drawing tools like line, circle, ellipse, paint and so on
  • The ability to create frame-by-frame animated GIFs.

What is HTML5 Canvas?

Canvas is an HTML element which can be used to draw graphics in webpages. It allows us to form both simple and complex graphical objects.

Before Canvas, developers had to use Flash to create such animations, which were embedded in webpages. Canvas has many advantages over Flash and is widely used for displaying graphics in web pages.

You can create a canvas using the <canvas> tag, for example:

<canvas id="drawing" width="500" height="500"></canvas>

This will create an empty 500 X 500 canvas. Since canvas is an HTML element, all CSS properties can be applied to canvas as well.

There are other options for displaying graphics in HTML pages, for example, SVGs. But we will be using canvas as it is more suitable for bitmap images, and pixel art is essentially a bunch of bitmap images.

How to Design Our Editor

We will be calling our app PixelCraft. You can find the complete source code and demo of our app here.

The first step in creating our app will be designing the user interface. A good UI should adapt to all screen sizes and should be easily accessible.

The UI for our app will look something like this:

Desktop layout

This will be responsive, meaning it will automatically adapt to smaller screen sizes like mobile devices.

How to Make the Dialog Box

When we open our app, it will show a dialog box which will ask for dimensions.

Dialog box asking for dimensions

The HTML code for our popup will be as follows:

<div id="popup">
<h3>Select the Dimensions Of the grid</h3>
<input type="text" id="width" value="16">X<input type="text" id="height" value="16">
<button id="close">OK</button>
</div>

and its CSS will be as follows:

#popup {
  background-color: #332f35;
  color: white;
  font-size: 20px;
  padding: 30px;
  box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5);
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.1, 0.1);
  text-align: center;
  max-width: 420px;
  width: 70%;
  transition: 0.2s all;
  z-index: 2;
  border-radius: 5px;
  display: none;
}

The important properties here are, position: fixed which will allow us to place the dialog box anywhere on the screen. left: 50% and top: 50% will place the upper left corner of our dialog on the center of our page.

To align the center of our dialog box with page center we use transform: translate(-50%, -50%) which will place it on the center of the page.

Initially, the display property will be set to none on page load. So we will change it to display: block to show the dialog box.

How to Draw the Canvas

Once the user chooses the dimensions, a canvas element will be created based on those dimensions. The canvas element will be in the center of the page.

<canvas id="canvas"></canvas>

That's the only HTML code required for canvas. All other properties will be set using JavaScript. All the drawing operations are also done using JavaScript which makes canvas very useful for displaying graphics.

The CSS required for the canvas element is as follows:

#canvas {
  box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5);
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 75%;
  max-width: 550px;
  display: none;
  cursor: crosshair;
  touch-action: none;
}

The CSS properties you need to center the canvas on the page are the same as that of the dialog box. The touch-action: none property will be useful in mobile devices as it will disable other swipe actions while drawing on the canvas.

How to Build the Toolbar and Color Palette

The other UI elements we want to create are the toolbar and color palette. They are aligned on the left edge and right edge, respectively.

But on smaller screens, the horizontal space is smaller compared to desktops. This means that we will have to move them to the bottom and top of the screen on mobile devices, as shown below.

Mobile layout

For this, we will be using CSS media queries. They allow us to use a specific set of CSS rules only on certain screen sizes, which means that we can add CSS that will only run on mobile devices.

This will make our app mobile-friendly for people on their phones, but it will also be able to use all available space on the desktop version.

The toolbar's HTML will look as follows:

<div id="toolbar">
<span class="item"><i class="fas fa-pencil-alt"></i></span>
<span class="item"><i class="fas fa-eraser"></i></span>
<!-- for every toolbar item -->
</div>

The <i> tag is for font awesome icons, which contain many general-purpose icons. The CSS for this toolbar will be as follows:

#toolbar {
  position: fixed;
  top: 50%;
  left: 0%; /* align to left */
  transform: translateY(-50%);
  padding: 0px;
  color: white;
  max-width: 150px;
}

#toolbar .item {
  display: inline-block;
  float: left; /* toolbar items stack to left */
  padding: 15px;
  border: 1px solid #FFF;
  cursor: pointer;
  height: 32px;
  width: 32px;
  font-family: Arial, FontAwesome;
  font-size: 24px;
}

To use CSS media queries, we have to add the following to our CSS:

@media only screen and (max-width: 600px) {
  /* CSS added here will only be used on screen-width smaller than 600px */   
}

Within this media query, we are adding CSS to align the toolbar to the bottom of the screen.

Similarly, the color palette will be aligned to the right of the screen on desktops and at the top of the screen on mobile devices. With these three components, the design part of our UI is done. I highly recommend trying to use your own creativity when creating the UI.

How to Create the App's Functionality

The design of our app is ready, so now we will be adding functionality to it. We will use the object-oriented nature of JavaScript which makes it easier to add new features in the future.

Object-oriented design implies that all the properties and methods associated with an object should be grouped together.

In our design, Canvas will be an object, so all the properties of the canvas element and its methods should be together in a single Canvas class.

class Canvas {
  constructor(width, height) {}  // initialize all canvas properties
    
  draw(x, y) {}  // method to draw a pixel on canvas
    
  erase(x, y){}  // method to erase a pixel on canvas
    
  setcolor(color) {}  // method to set the current color
    
  setmode(i) {}  // method to set the active tool
    
  save() {}  // method to save pixel art as image

  clear() {}  // method to clear canvas

  addFrame() {}  // method to add current frame to frame list

  deleteFrame(f) {}  // method to delete a specific frame

  loadFrame(f) {}  // method to load a specific frame onto canvas

  renderGIF() {}  // method to render a GIF using frames

  undo() {}  // method to undo a given step

  redo() {}  // method to redo a given step

  addImage() {}  // method to load an image as pixel art
}

The constructor is executed whenever an instance of a class is created. It is used to initialize properties of the object. In our case, the canvas's width and height will be set in the constructor.

To draw on the canvas using mouse movements or swipe actions, we need to add event listener to the canvas. The event listener for detecting mouse movements on desktop is mousemove. On mobile devices it's touchmove.

The event listener can be set as follows:

var canvas = document.querySelector("#canvas");

canvas.addEventListener("mousemove", e => {
      if (this.active) {
        var rect = canvas.getBoundingClientRect();
        var x = e.clientX - rect.left;
        var y = e.clientY - rect.top;
        x = Math.floor(this.width * x / canvas.clientWidth);
        y = Math.floor(this.height * y / canvas.clientHeight);
        if(tools[Tool.pen]) {
          this.draw(x, y)
        }
        else if(tools[Tool.eraser]) {
          this.erase(x, y);
        }
      }
});

When we set an event listener and the event occurs, a parameter e is passed to our event handler which contains data associated with the event.

In our case, the coordinates of the mouse can be found in this parameter. These coordinates are referenced with respect to the page, but we need them with respect to the canvas. For this, we use the getBoundingClientRect() method.

Bounding Rectangle

This gives the bounding rectangle of the canvas element which we can use to find mouse coordinates with respect to the canvas. These coordinates are still in pixel units.

When we initialized our canvas, we gave it a certain width and height as dimensions. These are the number of pixels we want in horizontal and vertical directions. So, the mouse coordinates need to convert to these units.

The coordinates we found using JavaScript are in pixels with respect to the page. For example, if the CSS dimensions of our canvas are 320 X 320 and we created a 16 X 16 pixel image, then each pixel will be about 320/16 = 20 pixels.

So if the coordinates found using JavaScript are (40, 60), then the pixel coordinates will be (40*16/320, 60*16/320) which is (2,3). All coordinates need to be converted like this.

How to Use the draw Method

We'll use the draw method to draw a pixel at a given coordinate on the canvas. To draw a pixel of a given size, we will use the fillRect() method of canvas context. For example,

var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext('2d');

ctx.fillRect(10,10,50,50);  

// creates a 50 X 50 rectangle with upper-left corner at (10,10)

How to Use the setcolor Method

The setcolor method will use the active color for the canvas which will be used for all drawing operations. We will use the fillStyle property of canvas context.

var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext('2d');

ctx.fillStyle = "rgba(255,0,0,255)";

// Sets the canvas color to red

How to Use the addFrame Method

We'll use the addFrame method to create a frame from the current state of the canvas. This frame will later be used for rendering the GIF. All the frames will we stored in an array. The canvas can be stored as an image using the toDataURL() method.

How to Use the setmode Method

The setmode method will store which tool is currently active. This is important because it will determine what action will take place on a mouse event. A mouse event could be a pencil, eraser, circle, ellipse and so on based on the active tool.

How to Use the undo and redo Methods

the undo and redo methods will revert or redo a step. You can do this by storing all steps in an array. Whenever undo is called, one step is removed from the steps array and added to a redo array. When redo is called, one element is removed from the redo array and added to the steps array.

How to Make an Animated GIF

One very important feature of our app is the ability to create animated GIFs. But canvas does not give us any methods to create animated GIFs. Instead, we will have to use an external library for this purpose.

We will be using gif.js for our app. It is a fast and popular library for rendering GIFs from frames.

To use gif.js, you have to download the library and import it into your page. Once imported, you have to initialize the GIF worker as follows:

var gif = new GIF({
  workers: 2,
  quality: 10,
  width: width,  // width of GIF
  height: height  // Height of GIF
});

gif.on('finished', function (blob) {
  var url = URL.createObjectURL(blob);
  var link = document.createElement('a');
  link.download = 'canvas.gif';
  link.href = url;  // download GIF after rendering
  link.click();
});

The above code will initialize the GIF worker and download the GIF once it finishes rendering.

To create GIFs, we will have to add frames to this worker. We can do it like this:

gif.addFrame(img, {
  copy: true,
  delay: 100  // Delay of frame in milliseconds
});

We will keep adding frames to our GIFs. Once we are done adding frames, we can render the GIF from them using the gif.render() function. On calling it, a background worker will render the GIF from the frames. Once the GIF is ready, it will be downloaded.

With this, we have finished creating our pixel art editor. You can use it to create images as well as animated GIFs.

Conclusion

In this tutorial, we created a pixel art editor using HTML5 canvas. While making our editor, we used many web technologies. We learned how to create a responsive UI and how to use Object-oriented design to help us write maintainable code.

Once again, you can find this project here. It also contains a working demo of our app with all of its features.

What we discussed in this article is still very simple compared to what is possible. You can add many features to make the app much more fun. Have fun doing that.

Hey, I hope you loved this article and learned something. You can find me at my internet home, theabbie.github.io or on my Github. Do check out my other articles. Thank you.