Your first steps to creating Sketch plugins
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:
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!
- 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.selectedPagelet 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 })
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.selectedPagepage.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.selectedPagepage.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']}
})
*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:
- The Code Side of Color by Ben Gremillion
- Hexes and Other Magical Numbers by Vaidehi Joshi
- 8-Digit Hex Codes? by Chris Coyier
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
}
]}
})
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 positionlayer.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()
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:
- Create the group object first. Then for each layer the parent should be the group rather than the artboard. Link to code
- 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 - 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)
- Learn more about the Sketch API. This is how I learned what functions and properties are available with each of the objects. https://developer.sketch.com/reference/api/
- Get involved in the community. Lots of designers and developers are asking questions and sharing code over at https://sketchplugins.com and at https://spectrum.chat/sketch/plugins
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! 💎