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 . , ; " 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.

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 a while.

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 =newLayer

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 =newLayer

width: screenWidth

myLayerB =newLayer

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 =newLayer

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 =newLayer

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 =false

layerB.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 =newLayer

# Place a layer in the center

layerA =newLayer

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 =newLayer

layerA.draggable.enabled =true

marker =newLayer

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 =newLayer

size:50

backgroundColor:"blue"

layerB =newLayer

size:50

backgroundColor:"blue"

layerC =newLayer

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 make these as big as you like.

for index in[1..3]

layer =newLayer

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 =newLayer

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 =newLayer

layerB =newLayer

layerC =newLayer

# 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 =newLayerx:0

layerB =newLayerx:220

layerC =newLayerx: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 =newLayer

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 =newLayer

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 =newLayer

layerB =newLayer

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 separated 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 =newLayer

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 =newLayer

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.koen

print ages["ben"]

The string-based notation is useful when you want to generate an object with different states in Framer.

layerA =newLayer

# 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 =newLayer

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

classButtonextendsLayer

constructor:(options)->

# Get default layer functionality

super(options)

# Set default properties

@width=300

@height=100

@backgroundColor="maroon"

# Create button

button =newButton

The @ 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 work

button =newButton

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.

classButtonextendsLayer

constructor:(options)->

super _.defaults options,

width:300

height:100

backgroundColor:"maroon"

# Works!

button =newButton

width:250

We can also add our own functions to the Button.

classButtonextendsLayer

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.

classButtonextendsLayer

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]

newLayer

backgroundColor:"blue"

Or with a function.

createLayer =(backgroundColor)->

newLayer

backgroundColor: backgroundColor

createLayer("blue")

createLayer("blue")

Or with a class.

classBlueLayerextendsLayer

constructor:(options)->

super

@backgroundColor="blue"

newBlueLayer

newBlueLayer

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 =newLayer

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 =newLayer

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 =newLayer

for i in[1..3]

layer =newLayer

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.