Programming
Programming is a powerful way to express interaction. It allows you to express complex behavior like logic, variables and loops by using simple building blocks. But while programming becomes easier over time, it can be challenging to get started. This guide is meant to help you take the first steps, as well as teach you how to improve in an efficient manner.
The most important thing to remember is that you do not have to know everything to begin. Start with the foundations of a programming language and aim to continually improve. A key thing to remember is that in programming, there is usually a smarter way to solve a problem and chances are, there is documentation to prove it. Even the most advanced users pick up new tricks from inspecting other people's code.

If you get stuck, don’t be afraid to search online or ask for help. The Framer community is full of programmers of all levels, most of whom will be happy to help. Remember, there's no such thing as a stupid question in programming.
It's also not bad to make mistakes. In fact, this is the very essence of programming – code, run into error, solve error, continue. No matter how far you advance, this will become a natural workflow for you. In the beginning, you’ll spend a good amount of time being frustrated by small syntax errors, mostly because programming relies on precision. Any wrong ., ,, [ will result in an error and you’ll often have no idea why. But push through and master the syntax. You'll be surprised at how quickly you get better at it.
Many of our users choose to start with Framer like they would with CSS. Just some simple layers with styles will get you far. From there you can pick up calculations, variables and functions. Start small, build on your foundation and don’t be afraid to ask for help.
Primer
CoffeeScript
Framer is built on top of CoffeeScript. CoffeeScript is a simplified version of JavaScript that makes it more legible and efficient to write. It also helps avoid common mistakes that are easily made in JavaScript.
We chose CoffeeScript for Framer because its properties neatly align with the goals that designers typically have when building interactive work. As a bonus, learning CoffeeScript will give you an edge when it comes to learning similar languages, like JavaScript or Swift.
One of the most important syntax differences is that CoffeeScript uses whitespace (tabs and spaces) for its language structure, as opposed to curly brackets. This makes code generally more readable, but can also cause errors in your code.
Whitespace
Whitespace (tabs and spaces) is an important part of CoffeeScript. Though convenient to use, it makes you more prone to making errors, most of which you may miss (although we lightly visualize them in your text editor). So try not to mix up tabs and spaces.
Capitalization
In general, programming languages are very case sensitive. Simply put, if you have a variable named box, it is not the same as Box. This takes a little getting used to, but it will start to come naturally after awhile.
Inspecting
You can quickly inspect values by printing them. This is a common way to learn what exactly is happening within a program. See below.
print "Hello" # Prints Hello print 10 + 1 # Prints 11
Variables
Variables are used to store information that you use or change later. They can be labeled with descriptive name, so the code makes sense if you read it. It is helpful to think of variables as containers that hold information.
A variable in its simplest form looks like this. The word Framer is saved in a variable named box. From here on, we can reference it at any point.
container = "Something in it"
You can give a variable any name, as long as it’s a single word.
boxA = "Something"boxB = 12345 # A variable can be a number too
To make this more Framer specific, we have to introduce how you create Layers. They are the building blocks for pretty much everything in Framer. You can learn more about them in the guide. But for now, let's create one with the new keyword and store it in a variable.
myLayer = new Layer
Say you want to create multiple layers with the same width. You can fill in the same number repeatedly, but what if you want to change the value later? Ideally, you would only have to define and edit it once. This is where variables come in.
screenWidth = 400 myLayerA = new Layer width: screenWidth myLayerB = new Layer width: screenWidth
Both layers now use the variable screenWidth as their width, and you can change both by only editing one number.
Numbers
When working with values, you will often use numbers to define postition, size, opacity and much more. Numbers can also be used for calculations.
Many layer properties are expressed as numbers. If you are familiar with CSS, you will notice that you don’t have to add units like “px” here. The numbers make sense by themselves, depending on where they’re used.
layerA = new Layer width: 200 height: 200 opacity: 0.5
You can also calculate with numbers by using +, -, *, / and more. In programming these are called operators.
print (400 + 100 / 10) * 6
This is great for calculating layer properties, too.
layerA.width = 500 / 2
You can even combine numbers and properties in calculations. Say you want the layer width to be half the width of another layer.
layerA.width = layerB.width / 2
Sometimes you may want to change a variable based on itself. Like when offsetting a layer slightly, moving it to the right in this example, by adding 100 to the original value.
# layerA.x is 200 by default layerA.x = layerA.x + 100
Strings
Strings are pieces of text wrapped within quotation marks. In Framer, they are often used to define color values, layer names and HTML content. They can be single words or entire sentences.
layerA = new Layer name: "button" html: "click me"
Like numbers, you can add strings together with +. In the case of a string, that means that the text is concatenated, without a seperator.
# This code: print "click" + "me" # Is the same as: print "clickme"
You can combine variables and strings together too.
name = "Koen"city = "Amsterdam" print "Hello my name is " + name + " and I live in " + city# Hello my name is Koen and I live in Amsterdam
This is very powerful, but you can see how this could get hard to read. Luckily, you can also use templates.
print "Hello my name is #{name} and I live in #{city}"# Hello my name is Koen and I live in Amsterdam
You can even add simple logic to templates.
age = 25 print "I’m #{age} now and #{age + 10} in ten years from now."# I’m 25 now and 35 in ten years from now.
Booleans
Booleans are values that can only be true or false. You can think of them like a light switch. They are often used to enable or disable features.
Some properties can simply be toggled on or off. For example, you can hide a layer using the visible property. Or you can make a layer draggable by using draggable.enabled.
layerA.visible = falselayerB.draggable.enabled = true
With the not keyword, you can reverse a boolean.
# Switches the visibility of a layer layer.visible = not layer.visible
You can combine booleans with the and and or keywords. This means they either both have to be true or one of them has to be true.
print layerB.visible and layerC.visible # false print layerB.visible or layerC.visible # true
Conditionals
To make decisions in your code, you can use logic. We call these parts conditionals, as they only run a specific part of the code, when a condition is met.
Say we want to toggle a layers visibility when clicking another layer. With an if-statement, you can check if a layer is visible or not.
button = new Layer # Place a layer in the center layerA = new Layer point: Align.center button.onClick -> if layerA.visible layerA.visible = false else layerA.visible = true
Besides checking for properties, you can also check for values by comparing them. Typical comparisons for numbers are smaller than and larger than. These are called comparison operators. Below, layerA will turn red once you drag it below the marker.
layerA = new LayerlayerA.draggable.enabled = true marker = new Layer x: Align.center y: Align.center layerA.onDrag -> if layerA.y > marker.y layerA.backgroundColor = "red"
Because if-conditions are always booleans, you can also check for multiple conditions at once, by combining them with and or or.
layerA.onDrag -> if layerA.x > marker.x and layerA.y > marker.y layerA.backgroundColor = "red" else layerA.backgroundColor = "green"
Loops & Arrays
Loops and Arrays help you to create and edit multiple elements at once. Think lists of layers, properties or animations. If you learn to use them well, they can help you to avoid writing repetitive code.
Below, we’ve created 3 layers, all sharing the same properties.
layerA = new Layer size: 50 backgroundColor: "blue" layerB = new Layer size: 50 backgroundColor: "blue" layerC = new Layer size: 50 backgroundColor: "blue"
This looks pretty repetitive, and can be simplified by using a for-loop. First, we need an array with as many numbers as we need layers. We can generate this with the syntax [1..3], which is a shorthand for an array like [1, 2, 3]. You can obviously make these as big as you like.
for index in [1..3] layer = new Layer size: 50 backgroundColor: "blue"
The index is a variable that represents the number in the array for that iteration of the loop. It starts at 1, then becomes 2, and finally 3.
Because it is a number, we can use it to do calculations and position the generated layers in the form of a list.
for i in [1..3] layer = new Layer size: 50 backgroundColor: "blue" y: i * 200
The code above will position the top of the layers layers at y positions 200, 400 and 600. You can make arrays of practically everything, but a common use case is to put layers in an array, and loop over them. This is an easy way to change properties of multiple layers at once.
layerA = new LayerlayerB = new LayerlayerC = new Layer # Put all the layers in an array so we can loop them layers = [layerA, layerB, layerC] for layer in layers layer.size = 50 layer.backgroundColor = "blue"
Events in Loops
There is a very common error when using loops to set up layers and event handlers. In the code below you might expect the layer you click on to change color, but instead only the last layer ever will.
layerA = new Layer x: 0layerB = new Layer x: 220layerC = new Layer x: 440 layers = [layerA, layerB, layerC] for layer in layers layer.onClick -> layer.backgroundColor = "blue"
This is due to something called Scoping and you can read more about it below. But if you run into this, you can get it to work like this.
for layer in layers layer.onClick -> this.backgroundColor = "blue"
Functions
Functions allow you make blocks of code that you run at a specific point, or use multiple times. They are often used in Events and for general organization.
The basic syntax for a function contains an arrow -> and whitespace. Once defined, you can execute the function with paranthases. Let's create a very simple function and execute it a few times.
sayHello = -> print "Hello!" print "How are you?" sayHello()sayHello()sayHello()
Notice how all the lines inside the function are indented. We call this the function body. Now instead of executing the function ourselves we can tell Framer to do so. This can be on click, tap or any other Event.
layerA = new Layer layerA.onClick -> layerA.rotation = layerA.rotation + 10
You might notice that the function above has no name like the sayHello function. But it also works with a name.
layerA = new Layer rotate = -> layerA.rotation = layerA.rotation + 10 layerA.onClick(rotate)
Just like a mathematical formula, a function can have multiple inputs and an output. Say you wanted to convert y = x * 10 to a function.
y = (x) -> return x * 10 print y(10) # Prints 100
But a more programmatic way to write this is with sensible names. Notice how nothing except the names changed compared to the function above, but it is a lot more readable.
timesTen = (someNumber) -> return someNumber * 10 print timesTen(10) # Prints 100
The function inputs are called parameters and the output the return value, hence the return keyword. As an example in Framer, we might want to make a function to rotate layers and use it on multiple layers.
layerA = new Layer layerB = new Layer x: Align.right rotate = (layer) -> layer.rotation = layer.rotation + 10 # Now, we can pass in any layer! Neat. layerA.onClick -> rotate(layerA) layerB.onClick -> rotate(layerB)
Multiple parameters are seperated by commas. Another parameter we could add is the amount of rotation.
# Multiple parameters rotate = (layer, degrees) -> layer.rotation = layer.rotation + degrees layerA.onClick -> rotate(layerA, 10)
If you find yourself often using the same value in a function, you can specify a default value for a parameter to make it optional. Now you could omit that value when calling the function.
rotate = (layer, degrees = 10) -> layer.rotation = layer.rotation + degrees # 10 degrees rotate(layerA) # 50 degrees rotate(layerB, 50)
Below, you see how we can use the return value (or output) on getting the largest layer width. The value is then applied to layerC.
largestWidth = (firstLayer, secondLayer) -> if firstLayer.width > secondLayer.width return firstLayer.width else return secondLayer.width layerC = new Layer width: largestWidth(layerA, layerB)
Objects
Objects are a way to structure data and used all over the place in Framer, from layers to animations.
Think of an object as a way to organize values. There is a lookup key that contains a value, like a name and an address in a phone book. Like functions, they use whitespace.
people = koen: "123 Main Street" sara: "456 Wall Street" jorn: "789 Arts Street" print people.koen
There are many applications for objects, but the most common one in Framer is to provide options when creating a new Layer.
myLayer = new Layer x: 200 y: 200 backgroundColor: "red"
The value of a key can be anything, even another object. This requires nesting. In Framer, you’ll see this when defining animation properties. Notice the double indentation.
layer.animate x: 100 y: 200 backgroundColor: "red" options: curve: Spring(damping: 0.5) time: 0.5
Going back to creating your own simple object, there are two ways to get the value for a key. Using the key directly (called dot notation) or using the key as a string. They both do the exact same thing.
ages = koen: 33 jorn: 32 ben: 21 print ages.koenprint ages["ben"]
The string-based notation is useful when you want to generate an object with different states in Framer.
layerA = new Layer # Add states within a loop for i in [1..3] layerA.states["state#{i}"] = y: i * 200
You can also loop over objects. The main difference with arrays is that you have to use a for...of loop instead of for...in and that you get back both the key and value.
people = koen: 33 jorn: 32 ben: 21 for key, value of people print key, value # Or more logically named for name, age of people print name, age
Classes
Classes are objects that can be extended to add or change behavior. For example, our Components are all classes that extend Layer. We call them subclasses.
Subclasses inherit basic functionality, but add extra features, like the scrollable content in the ScrollComponent.
Classes can be constructed with the new keyword. This will call the special constructor function and return an instance of that class. Below, layerA is a variable that contains an instance of Layer.
layerA = new Layer
It’s easy to create your own subclass. If you have multiple buttons in your prototype, you can create a class that has its own constructor which specifies the size and background color of your button.
# Create Class class Button extends Layer constructor: (options) -> # Get default layer functionality super(options) # Set default properties @width = 300 @height = 100 @backgroundColor = "maroon" # Create button button = new Button
The @ symbol refers to the Button itself. Learn more about it here.
This button is not really flexible, though. We can’t set the size of a specific button, because the value is overriden in the constructor.
# This does not work button = new Button width: 250 # This will work button.width = 250
To make this work, we have to merge the default options with the options provided to the constructor. Here we use the lodash defaults function to merge the provided options with our own defaults.
class Button extends Layer constructor: (options) -> super _.defaults options, width: 300 height: 100 backgroundColor: "maroon" # Works! button = new Button width: 250
We can also add our own functions to the Button.
class Button extends Layer constructor: (options) -> super _.defaults options, width: 300 height: 100 # Deactivate by default @deactivate() activate: -> @backgroundColor = "red" deactivate: -> @backgroundColor = "maroon"
Now, these functions are a part of every button. So we can use them to add interactivity to our button, for example.
button.onTapStart -> @activate() button.onTapEnd -> @deactivate()
We can also add the event handlers to the button itself by placing them within the constructor. All buttons now inherit this interactivity.
class Button extends Layer constructor: (options) -> super _.defaults options, width: 300 height: 100 # Deactivate by default @deactivate() # Add events handlers @onTapStart -> @activate() @onTapEnd -> @deactivate() activate: -> @backgroundColor = "red" deactivate: -> @backgroundColor = "maroon"
Comparing Loops, Objects and Classes
There are often many ways to achieve the same thing in programming. This is both great, and sometimes tricky.
For instance, you can create two blue layers in a loop.
for i in [1..2] new Layer backgroundColor: "blue"
Or with a function.
createLayer = (backgroundColor) -> new Layer backgroundColor: backgroundColor createLayer("blue")createLayer("blue")
Or with a class.
class BlueLayer extends Layer constructor: (options) -> super @backgroundColor = "blue" new BlueLayernew BlueLayer
But here is no “right” way. It’s normal to go back through your code and rewrite small parts as you better learn what your needs are.
Scope
In programming, scope refers to the value of a variable within a block of code. Sometimes, you can’t access a value, depending on where you retrieve it.
You may run into scope bugs when using Events in a loop. Let’s take a look at what happens when we add a click event.
for i in [0...3] layer = new Layer backgroundColor: "blue" y: i * 250 layer.onClick -> layer.backgroundColor = "red"
The code above does not work as you might expect: when you click any layer, the third one turns red! What’s wrong? The onClick function uses the variable layer to change the background color.
However, this variable is updated each time at the start of the loop.
The background color only changes after you click, and at that moment the value of layer is what it was set to the last time the loop ran: the third layer. There are a couple solutions for this.
Using “this”
Instead of using the variable layer we can also find the layer that was clicked by using this.
The value of this depends on where it’s used. Within event handlers, it often refers to the layer.
for i in [0...3] layer = new Layer backgroundColor: "blue" y: i * 250 layer.onClick -> this.backgroundColor = "red"
You can also use @ as a shorthand for the this keyword.
layer.onClick -> @backgroundColor = "red"
Using “do”
Another solution is to “capture” the variable with do. For example, if you need to use it within event handlers of other layers.
button = new Layer for i in [1..3] layer = new Layer backgroundColor: "blue" y: i * 250 do (layer) -> button.onClick -> layer.backgroundColor = "red"
The button is used to change the color of all layers created in the loop. Without the do, only the last layer would change color.