Making an Instagram Stories graphic generator with fabric.js — Part 1

In this tutorial I’ll show you how to make an image generator that’s perfect for producing graphics for Instagram Stories. We’ll be using the HTML5 canvas along with the fabric javascript library and it’s going to be super straightforward.

Here’s a link to a live version of what we’re going to make.

Here’s a link to all the code on GitHub with a different file for each part.

I’ve got Instagram Stories in mind, but you can use the ideas and code in this tutorial to make any kind of image editing app. The next two parts of this tutorial series will show you some of the more complicated designs you can achieve and we’ll also look at how to export video. I haven’t written them yet but I promise I will.

For now, down to business.

1. Make the page structure for our app

We’re just setting up a basic html page with a sidebar that’s going to hold all of our options like image upload and download buttons plus a main area where the canvas will sit. We’re not going to worry about mobile for now, this tutorial is just about fabric and javascript, so this is for desktop.

I’ve also added a header area where we’ll put our app title — that’s also where you could put login buttons if you wanted. This tutorial was inspired by a work project and I used auth0 for the login process there. So this is our starting point code, the scaffolding we’re going to be adding to throughout this tutorial.

2. Add a canvas and import fabric.js

We need a canvas in the main area, we’ll make it 360px x 640px, that’s a perfect ratio for Instagram Stories… it’s a little on the small side but we’ll get to that later.

Then just add a link to fabric.js which is a brilliant javascript library that makes working with the canvas a lot easier. Add the CDN link just above the closing body tag.

3. Add an image and some text

Now we’re ready to load an image and some text onto the canvas. This is just a placeholder image, the user will be able to change this but we’ll get to that later in this tutorial.

Here’s a link to the image we’re using — https://www.acwe.co.uk/tutorials/story-maker-tutorial-part-1/img/birdbox.jpg

To do that we add this code below the link to the fabric library we just added…

The code is commented explaining what every section does. If you’re wondering why I’ve put the template code in a function of its own, well that just makes things easier in the future when we want to add more templates. So this is what we have now…

Our empty sidebar on the left and the canvas on the right with an image and a line of text loaded onto it

4. Loading web fonts

Fabric takes care of the text for us, people can just edit the text, resize and position it however they want. But we do have a problem, the Open Sans Google font hasn’t loaded before the canvas is rendered.

To fix this problem, we can use the webfont library which detects when our webfonts have loaded. Add a link to the webfont library below your link to fabric.js

Now we can wait until those webfonts have loaded before loading our canvas using this bit of code. Remove the template1(); line and replace with this…

5. Uploading an image

Fabric also takes care of resizing our images but, of course, we want people to be able to upload their own image.

First of all, let’s add an image upload button in the sidebar. Replace the aside tag with this code…

And add these rules to the CSS…

Now we need to add code so that when someone uploads a new image, it replaces the existing image on the canvas. Pop this code at the end of the template1() function, but make sure it’s inside the function…

So here’s what the app looks like now…

6. How to save the image

So we’re all set, we’ve got a basic image maker that’s super simple to use. There’s only one image and one bit of text but we’ve got the basics done and I’ll be writing the next tutorial soon to show how we can take this further. In the meantime, we’re going to make a Download Image button to… well, I think you can guess.

Add these rules to your CSS…

Add this link into the aside sidebar…

Finally, add this javascript code, put it outside of the template function, just above the webfont loading function…

Here’s what we have with the Download Image button in place…

7. The handles outside of canvas problem

So we’ve got a perfectly good image maker there but there is one thing than we could improve. Have you noticed that when you resize an image bigger than the canvas, the handles of the image disappear. That’s because they’re outside the canvas which is not great for the user experience.

Handles can’t go outside of the canvas

To solve this issue we’re actually going to make the canvas a lot bigger — 800px by 800px. To do this we’ll use fabric’s setOverlayImage method and then clipto the working area. For the overlay image we’ll use a png with a 360 x 640 hole in the middle.

Here’s a link to the image we’re using — https://www.acwe.co.uk/tutorials/story-maker-tutorial-part-1/img/overlay-bg.png

One last thing to do here is set controlsAboveOverlay to true to make sure we can see those handles above the overlay…

First of all change your canvas tag so it’s 800 x 800…

Then replace this code…

with this…

This just takes the overlay-bg.png image and, well, overlays it over the canvas, that’s why the png has a hole in the middle and clips the canvas to our original size which means we can now see the handles.

Now, if you’ve been thinking that a 360px x 640px image is a bit small for Instagram stories, you’re right, but fabric helps us out here too.

Let’s add a multiplier to the save image functionality. Multiplier is an argument you can use with fabric’s canvas.toDataURL method and it basically multiplies the size of the canvas so if we use multiplier: 3 we’ll end up with a jpg 3 times the size of our 360 x 640 image which is 1080 x 1920 which is just what we want for Instagram Stories… it’s almost as if that was the plan all along.

We also need to remember that we have that overlay so you can also use toDataURL arguments to crop the image to our active area.

Replace the save image code we added earlier with this…

The dataURL toBlob function is the same but the code under // Save Image has changed quite a bit. What we’re doing when the download button is press is removing the overlay and clipping, saving the multiplied and cropped version of the image and then resetting the overlay and clipping.

8. Positioning everything on the new canvas

You may have noticed that things are appearing in a different position now, that’s because our canvas is now a different size, so let’s fix that by changing the values for positioning in the birdboxImg section to left:200 and top:80 plus the textbox value to left:240.

As a finished touch I’ve added put a transparent png overlay showing the Instagram gui to give you some idea of how your image would look in Instagram. This overlay is not a part of the canvas so it’s not a part of the downloaded image.

Here’s a link to that Instagram gui overlay png — https://www.acwe.co.uk/tutorials/story-maker-tutorial-part-1/img/gui-overlay.png

So our finished file with the html, css and javascript in place now looks like this…

And our final app looks like this…

9. How to upload to Instagram

And that’s it, we’ve got a working image maker. This demo is for desktop so to post the images you make, you’ll have to share them and upload them to Instagram using your phone. You can of course load up Instagram in Chrome on desktop, enter Inspector mode to get the mobile view and upload from there — that will be perfect for most users however doing it this way you can’t add a swipe up link.

I’m planning on making this the first part of a three-part tutorial. For the next two parts I’ll cover…

Part 2 — Different templates, cropping images into shapes and adding emojis.

Part 3 — Using video in fabric.js and exporting as webm / mp4.

Why’s this image here? It’s because I needed a featured image and I use a cropped version of this image in the tutorial so it seemed like the thing to use

I hope you enjoyed this tutorial and found it useful, it’s the first tut I’ve ever written but I’ll definitely be doing at least two more.

All the code for this project can be downloaded from my GitHub here and you can see a working version of what we’ve just made here.