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.+ 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 = 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 = 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 Layer
layerA.draggable.enabled = true
 
marker = new Layer
    x: Align.center
    y: Align.center
 
layerA.onDrag ->
    if layerA.> 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.> marker.and layerA.> 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 Layer
layerB = new Layer
layerC = new Layer
 
# Put all the layers in an array so we can loop them 
layers = [layerAlayerBlayerC]
 
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: 0
layerB = new Layer x: 220
layerC = new Layer x: 440
 
layers = [layerAlayerBlayerC]
 
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.

= (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(layerA10)

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(layerB50)

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(layerAlayerB)

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.koen
print 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 keyvalue of people
    print keyvalue
 
# Or more logically named 
for nameage of people
    print nameage

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 BlueLayer
new 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.