Your first steps to creating Sketch plugins

Kevin Gutowski
Design + Sketch
Published in
13 min readMay 27, 2019

Sketch plugins open up so many opportunities for creative and new ideas. As you probably have found, plugins can do a wide variety of things such as creating new layers, automating existing features, provide new interfaces, and more! Let’s dive into some of the very basics of plugin development and make some fun shapes along the way.

The Script Panel

Getting started is super simple. You don’t even need to download anything other than Sketch itself. Open up Sketch and navigate to Plugins > Run Script...

This is the script panel. It’s a little space to test your ideas quickly.

The JS API — Breaking down the example code

Since the JS API is written in Javascript, lots of what you might know from building websites can translate over. If you haven’t written any Javascript before, that’s ok, I’ll be going over everything every step of the way.

Let’s look over that starter code. There is some awesome stuff going on there:

console.log('This is an example Sketch script.')

This logs some text (or String) to the console. You will often use console.log('something') for checking to make sure your code behaves as expected.

The next line is this

var sketch = require('sketch')

This is the way you import the JS API. It has all the translation bits to convert our Javascript objects into things that Sketch can understand.

var document = sketch.getSelectedDocument()

getSelectedDocument is a method defined from our variable sketch. It returns the selected document or null if there are no documents selected.

var selectedLayers = document.selectedLayersvar selectedCount = selectedLayers.length

Here we get the selected layers from the selected document. This is a very, very common pattern so be sure to remember that to get the selected layers you will need to do so through the document object. The length property gets the number of layers that are selected.

*One small note here for those that have a bit more Javascript experience: selectedLayers isn’t an array but rather a Selection class. If you want to get an array of the layers selected you can do so with this:

document.selectedLayers[0] // This doesn't workdocument.selectedLayers.layers[0] // This does

Last but not least, is checking to see if there are any layers selected and if so, logging the names of the layers.

if (selectedCount === 0) {
console.log('No layers are selected.')
} else {
console.log('Selected layers:');
selectedLayers.forEach(function (layer, i) {
console.log((i + 1) + '. ' + layer.name)
})
}

First, we check if the number of layers is 0. If true, then we log the String “No layers are selected.”

If the number of layers isn’t 0, we then log the String “Selected layers:” to help mark in the console what we are going to log later.

After that, for each layer we log the layer number and their layer name. More specifically, we use the forEach method on selectedLayers. We pass in a function which takes two inputs: the layer and the index. Since the first layer index starts at 0 we add 1 to it so we can get the log to look like this

1. First Layer Name
2. Second Layer Name
etc...

Hit the Road Running

Now that you know how the code works, hit the run button in the bottom right! If you had no layers selected then you should see the corresponding message in the console. If you did have some layers selected before running the scrip then you will see their names reported in the console. Pretty cool huh? Ah, we are just getting started…

Let’s draw some shapes shall we? This is what we will make:

Oo purty shapes 🤩

In this next part we will learn how to create an artboard, make some shape layers, group them together, and reorder them. Follow along and let’s go!

  1. Import Sketch & Get Common Objects

Once you have your script panel open and ready to go, the first thing that we need to do is to import the JS API with. Remember, this is the translation part that the Sketch team upkeeps to make sure that the code you write here will translate to the correct underlying code.

var sketch = require('sketch')

Then, we will need to get the current document and page. These are the fundamental components of a Sketch document. Getting the selected document should look familiar since we did it earlier. Also, getting the selected page is very similar to getting the selected layers.

let document = sketch.getSelectedDocument()let page = document.selectedPage

(Remember how to get the selected layers from the example earlier? document.selectedLayers Getting the selected page is super similar.)

2. Create an Artboard

The other neat thing that you can do with the JS API is to pull out various classes from it. I like to think of it like a utility belt which has lots of neat tools. Here is how we can pick one of them out:

let Artboard = sketch.Artboard

To use one of the tools we can initialize it like this:

let myArtboard = new Artboard()

and if you log myArtboard you will see that you successfully created an Artboard object!

✔︎ Checkpoint

What does myArtboard look like? Your code should look like this so far:

let sketch = require('sketch')
let document = sketch.getSelectedDocument()
let page = document.selectedPage
let Artboard = sketch.Artboard
let myArtboard = new Artboard()
console.log(myArtboard)

And the output should look like this:

{         
type: 'Artboard',
id: '82732522-D929-4896-B98B-950E9E1EB7A8',
frame: { x: 0, y: 0, width: 100, height: 100 },
name: 'Artboard',
selected: false,
exportFormats: [ ],
sharedStyleId: null,
layers: [ ],
flowStartPoint: false,
background: {
enabled: false,
includedInExport: true,
color: '#ffffffff'
}
}

So now that we created the artboard you might be thinking, “Well… where is it exactly?” If you look underneath your script panel you should see that nothing got added to the canvas (you can also close the panel and look around to be sure).

It turns out, that we will need to explicitly attach the artboard to the correct page. Otherwise, the artboard object that we made will be thrown away once the script is done running. This is why if you keep hitting the Run button over and over the unique id value of the artboard will change. Sketch is creating a brand new artboard object each time your script is executed.

To attach the artboard to the page we will need to specify a parent

let Artboard = sketch.Artboard
let myArtboard = new Artboard()
myArtboard.parent = page

Or if we want to be a bit more succinct about it we can pass the parent property when we initialize the artboard.

let Artboard = sketch.Artboard
let myArtboard = new Artboard({ parent: page })
Look! There it is! A marvelous artboard

Sweet! We got our artboard on our canvas. But, our artboard is a little small. In fact, the default size is 100 by 100. Perhaps you have an idea how to make the artboard larger already. If we look back to when we logged myArtboard then you might have noticed this property:

frame: { x: 0, y: 0, width: 100, height: 100 }

So to resize our artboard to 400px by 400px we can modify myArtboard like so:

let Artboard = sketch.Artboard
let myArtboard = new Artboard({ parent: page })
myArtboard.frame = { x: 0, y: 0, width: 400, height: 400 }

Which we can also move into the initializer:

let Artboard = sketch.Artboard
let myArtboard = new Artboard({
parent: page,
frame: { x: 0, y: 0, width: 400, height: 400 }
})

Nice work! By now you have clicked the Run button a few times and it’s likely that you have created a few artboards on top of one another. Or maybe you have been deleting them every time you wanted to run the code again. That is a bit tedious and something we can do programmatically! To clear everything within a page you can do this:

page.layers = []

If we add that before we create our artboard then each time you run the script the previously made artboards will be removed.

So if we put everything together so far we should have something like this:

let sketch = require('sketch')
let document = sketch.getSelectedDocument()
let page = document.selectedPage
page.layers = []let Artboard = sketch.Artboard
let myArtboard = new Artboard({
parent: page,
frame: { x: 0, y: 0, width: 400, height: 400 }
})

Great job! Now let’s add some shapes!

3. Creating a Square

Creating a square is very similar to creating an artboard. We will specify a frame, a parent, and now a fill! Here is how we do it

let ShapePath = sketch.ShapePathlet mySquare = new ShapePath({
parent: myArtboard,
frame: { x: 53, y: 213, width: 122, height: 122 },
style: { fills: ['#35E6C9']}
})

Like we did with the Artboard class, let’s pick out the ShapePath class. To use the class we then create a new instance of ShapePath and pass in some setup properties — parent, frame, and style.

style is the newest of the bunch. If we take a look at the inspector panel inside Sketch we can kind of get an idea of what our code is doing.

When you select a layer, there are a bunch of properties like Resizing, Prototyping, Appearance, Style, Shadows, Inner Shadows, Blurs, etc. We want to add a fill which is under the Style property.

Fills can be disabled or enabled, have a blend mode, a hex value, and opacity. You can also have multiple fills as well!

Since you can have multiple fills the fill object holds a list of them, or an array. That looks like this:

myFillsArray = [fill 1 ,fill 2, fill 3, etc]

Or more specifically for our use like this:

myFillsArray = ['#00FF00', '#FF0000','#0000FF']

But since we really only want one fill we just need to pass in one hex value.

style: { fills: ['#35E6C9’]}

Before we move on to creating other shapes I want to point out one subtle detail with frames:

let mySquare = new ShapePath({
parent: myArtboard,
frame: { x: 53, y: 213, width: 122, height: 122 }
})

Since we specified the parent artboard, the frame that we provide will be relative to the artboard that we made (it also inserts it inside the artboard as well). If we made the parent the page like we did when creating the artboard then its coordinates would be relative to the page.

✔︎ Checkpoint

So, to review what our code should look like at this step, it should look like this:

let sketch = require('sketch')
let document = sketch.getSelectedDocument()
let page = document.selectedPage
page.layers = []let Artboard = sketch.Artboard
let myArtboard = new Artboard({
parent: page,
frame: { x: 0, y: 0, width: 400, height: 400 }
})
let ShapePath = sketch.ShapePathlet mySquare = new ShapePath({
parent: myArtboard,
frame: { x: 53, y: 213, width: 122, height: 122 },
style: { fills: ['#35E6C9']}
})
That’s a nice square there.

*Note: If your square has a border around it then its likely that your Default Layer Style is causing this. To ensure that a border isn’t being drawn you will need to pass in an empty array for borders like so.

style: { fills: ['#35E6C9’], borders: []}

4. Creating Other Shapes

Triangles

Creating other shapes like triangles, pentagons, and circles are really similar to drawing rectangles. We need to specify a parent, a frame, and a fill (well a style that contains a fill). The only difference now is that we need to specify a ShapeType

let myTraingle = new ShapePath({
shapeType: ShapePath.ShapeType.Triangle,
parent: myArtboard,
frame: { x: 84, y: 62, width: 98, height: 80 },
style: { fills: ['#00d5ffb3']}
})

ShapePath contains an object called ShapeType. If you log ShapePath.ShapeType you can find a list of all the different types of shapes you can create. Here we want to use the Triangle option.

Also, you might have noticed that there is a funny looking Hex code here. Normally Hex codes are 6-digits in Sketch and correspond to R,G,B values (two digits for each color channel). 8-Digit hex codes have some extra bit of information and use the last two digits to encode opacity. Specifically, the b3 part of the string corresponds to 70% opacity.

*If you are looking do learn more about hex codes then check out these resources:

Pentagons

Now that you know how to change the shapeType how might you be able to create a pentagon? The trick is to use the Polygon option.

let myHex = new ShapePath({
shapeType: ShapePath.ShapeType.Polygon,
parent: myArtboard,
frame: { x: 218, y: 142, width: 120, height: 120 },
style: { fills: ['#FF00B366']}
})

The default number of sides of a polygon is 5. Unfortunately, you can’t change the number of sides with the JS API just yet so we are stuck with hexagons for now.

Circles

Circles, of course, are created with the Oval shapeType. Hah! You thought it was going to be Circle, eh? I made the same mistake when writing this post out 🙃. In hindsight it makes sense though because ovals are more generic than circles. To create a circle rather than an oval we just make the width and height the same.

let myCircle = new ShapePath({
shapeType: ShapePath.ShapeType.Oval,
parent: myArtboard,
frame: { x: 106, y: 102, width: 172, height: 172 },
style: { fills: ['#0006FF66']}
})

This draws a circle perfectly fine, however we wanted a border rather than a fill.

style: { borders: ['#0006FF66'] }

This will create a 1px border. To specify a border width we will need to change things a little. Rather than just specifying a hex value for the border properties we also need to pass in the thickness.

color: '#0006FF66',
thickness: 16

Putting it all together it looks like this:

let myCircle = new ShapePath({
shapeType: ShapePath.ShapeType.Oval,
parent: myArtboard,
frame: { x: 106, y: 102, width: 172, height: 172 },
style: { borders: [
{
color: '#0006FF66',
thickness: 16
}
]}
})
Voilà! Your masterpiece is complete.

Additional Topics

Reordering Layers

Often times you want to put your shapes in exactly the right order. There are a few ways to go about doing this.

  • Move the layer to the front or back
layer.moveToFront()
layer.moveToBack()
  • Move a layer forward/backward
layer.moveForward()
layer.moveBackward()
  • Specifying the index
let index = layer.index
//the layers current position
layer.index = 2
// assigning the index to a particular position

Note that the layer at the back of the parent (visually) will be layer 0. The layer at the front will be layer n - 1 (if there are n layers).

Grouping Layers

Grouping layers will feel really similar to setting up an artboard. First we have to pull Group out like so:

let Group = require('sketch').Group

Just like creating an artboard, we create a new group like this

var group = new Group({
name: 'my name',
layers: [myLayer1, myLayer2, etc..],
parent: myArtboard
})

Note that we don’t need to specify a frame here. The layers inside the group will determine the frame if we use a special little method called adjustToFit

However, if you attempt to add all your layers to a group at the end of the script that we have been working on you might notice some funny business.

let Group = sketch.Grouplet myGroup = new Group({
name: "My Group",
layers: [mySquare, myTriangle, myHex, myCircle],
parent: myArtboard
})
myGroup.adjustToFit()
Woah, its almost like we made a “Symbols” feature here.

Honestly, I’m not entirely sure what is going on here but somehow when making a new group and specifying the layers of that group, it is creating new instances of each layer rather than referencing the old layers that were initially created. There are a few ways to go about fixing this:

  1. Create the group object first. Then for each layer the parent should be the group rather than the artboard. Link to code
  2. Don’t specify the parent when creating each layer. Putting them inside the group object will automatically assign the parent property for each layer for us. Link to code
  3. Remove the parent for each layer before creating the group. Link to code

Next Steps

You have accomplished a lot so far! Now you might be wondering how to take it a step further. Here are a few suggestions:

  • See what cool art you can make. If creative coding is something you want to dive into then I would highly recommend Processing, a language dedicated to making graphics and animations programatically. (Here is a piece I made for this article)
Code is at: https://gist.github.com/KevinGutowski/ca5e894770aff1a8371c37a83c9a6ff4

Lastly, if you have an idea for a plugin but just aren’t sure how to write it, share it in the comments below and I can point you in the right direction. If enough people have similar questions, I’ll write a blog post about it!

Until next time! 💎

--

--