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
. , ; " or
} 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.
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 (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.
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 a while.
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 Helloprint 10 + 1 # Prints 11
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.
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 = 400myLayerA =width: screenWidthmyLayerB =width: screenWidth
Both layers now use the variable
screenWidth as their width, and you can change both by only editing one number.
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 =width: 200height: 200opacity: 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 = layerBwidth / 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 defaultlayerA.x = layerAx + 100
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 =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 and I live in "# Hello my name is Koen and I live in Amsterdam
You can even add simple logic to templates.
age = 25print "I’m now and in ten years from now."# I’m 25 now and 35 in ten years from now.
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
layerA.visible = falselayerB.draggable.enabled = true
not keyword, you can reverse a boolean.
# Switches the visibility of a layerlayer.visible = not layervisible
You can combine booleans with the
or keywords. This means they either both have to be true or one of them has to be true.
print layerBvisible and layerCvisible # falseprint layerBvisible or layerCvisible # true
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 =# Place a layer in the centerlayerA =point: AligncenterbuttononClick ->if layerAvisiblelayerA.visible = falseelselayerA.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
layerA =layerA.draggable.enabled = truemarker =x: Aligncentery: AligncenterlayerAonDrag ->if layerAy > markerylayerA.backgroundColor = "red"
Because if-conditions are always booleans, you can also check for multiple conditions at once, by combining them with
layerAonDrag ->if layerAx > markerx and layerAy > markerylayerA.backgroundColor = "red"elselayerA.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 =size: 50backgroundColor: "blue"layerB =size: 50backgroundColor: "blue"layerC =size: 50backgroundColor: "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 make these as big as you like.
for index in 1..3layer =size: 50backgroundColor: "blue"
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
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..3layer =size: 50backgroundColor: "blue"y: i * 200
The code above will position the top of the layers layers at y positions
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 =layerB =layerC =# Put all the layers in an array so we can loop themlayers = layerAlayerBlayerCfor layer in layerslayer.size = 50layer.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 = x: 0layerB = x: 220layerC = x: 440layers = layerAlayerBlayerCfor layer in layerslayeronClick ->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 layerslayeronClick ->this.backgroundColor = "blue"
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.
= ->print "Hello!"print "How are you?"sayHellosayHellosayHello
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 =layerAonClick ->layerA.rotation = layerArotation + 10
You might notice that the function above has no name like the
sayHello function. But it also works with a name.
layerA == ->layerA.rotation = layerArotation + 10layerAonClickrotate
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.
=return x * 10print y10 # 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.
=return someNumber * 10print timesTen10 # 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 =layerB =x: Alignright=layer.rotation = layerrotation + 10# Now, we can pass in any layer! Neat.layerAonClick ->rotatelayerAlayerBonClick ->rotatelayerB
Multiple parameters are separated by commas. Another parameter we could add is the amount of rotation.
# Multiple parameters=layer.rotation = layerrotation + degreeslayerAonClick ->rotatelayerA10
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.
=layer.rotation = layerrotation + degrees# 10 degreesrotatelayerA# 50 degreesrotatelayerB50
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.
=if firstLayerwidth > secondLayerwidthreturn firstLayerwidthelsereturn secondLayerwidthlayerC =width: largestWidthlayerAlayerB
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 peoplekoen
There are many applications for objects, but the most common one in Framer is to provide options when creating a new Layer.
myLayer =x: 200y: 200backgroundColor: "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.
layeranimatex: 100y: 200backgroundColor: "red"options:curve: Springdamping: 0.5time: 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: 33jorn: 32ben: 21print ageskoenprint ages"ben"
The string-based notation is useful when you want to generate an object with different states in Framer.
layerA =# Add states within a loopfor i in 1..3layerAstates"state"=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: 33jorn: 32ben: 21for keyvalue of peopleprint keyvalue# Or more logically namedfor nameage of peopleprint nameage
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.
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:# Get default layer functionalitysuperoptions# Set default properties@width = 300@height = 100@backgroundColor = "maroon"# Create buttonbutton =
@ symbol refers to the Button itself. This button is not really flexible, though. We can’t set the size of a specific button, because the value is overridden in the constructor.
# This does not workbutton =width: 250# This will workbutton.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.
:super _defaults optionswidth: 300height: 100backgroundColor: "maroon"# Works!button =width: 250
We can also add our own functions to the Button.
:super _defaults optionswidth: 300height: 100# Deactivate by default@deactivate: ->@backgroundColor = "red": ->@backgroundColor = "maroon"
Now, these functions are a part of every button. So we can use them to add interactivity to our button, for example.
buttononTapStart ->@activatebuttononTapEnd ->@deactivate
We can also add the event handlers to the button itself by placing them within the constructor. All buttons now inherit this interactivity.
:super _defaults optionswidth: 300height: 100# Deactivate by default@deactivate# Add events handlers@onTapStart ->@activate@onTapEnd ->@deactivate: ->@backgroundColor = "red": ->@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..2backgroundColor: "blue"
Or with a function.
Or with a class.
:super@backgroundColor = "blue"
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.
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...3layer =backgroundColor: "blue"y: i * 250layeronClick ->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.
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...3layer =backgroundColor: "blue"y: i * 250layeronClick ->this.backgroundColor = "red"
You can also use
@ as a shorthand for the
layeronClick ->@backgroundColor = "red"
Another solution is to “capture” the variable with
do. For example, if you need to use it within event handlers of other layers.
button =for i in 1..3layer =backgroundColor: "blue"y: i * 250dobuttononClick ->layer.backgroundColor = "red"
button is used to change the color of all layers created in the loop.