Get Started

Starting with Framer couldn’t be easier. Auto-Code is a revolutionary new way to design with code, without actually writing it.

Auto-Code helps you position Layers, set up States and Animate them with Events. You can add them to your project with the insert menu. Here’s a short introduction video to get you started.

Auto-Code and Sketch Import work great together. Design your visual assets in Sketch, import to Framer start adding interactions. It’s a seamless design workflow.

Layers

If you’ve ever used a visual design tool, you’ll already be familiar with the concept of a Layer. Without content, it’s simply a rectangle. But it can contain an image, a video, audio, text, and much more.
Properties

Layers have many types of properties. Ones that define its position, appearance, and even interactivity. Every layer has a set of default properties. It has a width and height of 200 by 200, and a transparant grey background.

All of these default properties can be overridden. For example, you can define a blue background, and make give your layer a solid white background color.

# Background layer 
bg = new BackgroundLayer
    backgroundColor: "#28affa"
 
# Create a layer 
layerA = new Layer
    x: 0
    y: 0
    width: 200
    height: 200
    backgroundColor: "#fff"

A layer has a ton of visual properties. You can transform it, scale it, hide it and more. After having created a layer, you can still override its properties.

# Override properties 
layerB.borderRadius = 4
layerB.rotation = 45
layerB.opacity = 0.5
layerB.scale = 0.5

A great way to explore all layer properties is by using AutoCode. In front of every layer you create, an edit icon appears. Click this to bring up the properties panel. Here, you can directly manipulate your layers. For a list of all layer properties, check out our Docs.

Positioning

A layer can be positioned with its x and y properties. These values define the distance from the top-left corner of the canvas.

# Position layerA 
layerA.x = 200
layerA.y = 200

Layers can also be positioned using dynamic properties. Say you want to position one layer relative to another. Instead of manually calculating the center point of this layer, you can simply use the midX and midY properties. You can find all positioning properties (min, mid, max) in our Docs.

layerA = new Layer
    x: 200
    y: 200
 
layerB = new Layer
    opacity: 0.5
 
# Align to the center of layerA 
layerB.x = layerA.midX
layerB.y = layerA.midY

You can center a layer within its parent by using the Align property. Layers can also be exclusively centered horizontally or vertically. See below for all available Align properties.

  • Align.left (x)
  • Align.right (x)
  • Align.top (y)
  • Align.bottom (y)
  • Align.center (x and y)
# Parent layer 
layerA = new Layer
    width: 400
    height: 400
 
# Align to the bottom-right corner 
layerB = new Layer
    parent: layerA
    x: Align.right
    y: Align.bottom
Hierarchy

Layers can be grouped. A layer placed within another layer is called a child layer. The container layer is called the parent layer. Layers inherit properties from their parent layers, like their opacity or position.

# Two ways to define hierarchy 
layerB.parent = layerA
layerA.addChild(layerB)

If you want to place a layer in front of another layer, you can use the placeBefore method. Vice versa, you can use placeBehind.

layerA = new Layer
layerB = new Layer
 
# Place layerB on top 
layerB.placeBefore(layerA)
Layer Types

Layers can be almost anything. Think backgrounds, images, videos, text and more. To add an image, for example, you simply reference an image located in /images within your project folder.

# Image 
layerA = new Layer
    image: "images/sea.png"
 
# Video 
layerA = new Layer
    video: "fish.mp4"
 
# Text 
layerA = new Layer
    html: "Hello!"

Animate

Almost every layer property can be animated. Multiple properties can be animated at once. You can then continue to define the curve, time, delay and many more custom animation options.
Get Started

Let's start by animating the opacity of a layer. You can start animations by using the animate keyword, and then defining a set of properties.

layerA.animate
    properties:
        opacity: 0.5
Options

You can completely customize the feel of your animation, by changing options like time, curve and delay. Below is a list of the available options:

  • time (in seconds)
  • curve (ease, spring, bezier)
  • delay (in seconds)
  • repeat (amount of times)
  • colorModel (rgb, hsl, husl)

Durations in Framer are defined in seconds. Note that the time property has no effect when using spring curves. Add animation options at the same indentation level as the properties keyword:

# Animate with an easing curve 
layerA.animate
    properties:
        rotation: 180
        borderRadius: 200
    curve: "ease"
    time: 1
Easing Curves

Animations optionally take a curve that describe the type of animation. You can use pre-defined curves like linear or ease-in. The ease curve is the default in Framer. See all built-in easing curves below, or check out this website to learn more about easing curves.

  • ease
  • ease-in
  • ease-out
  • ease-in-out
# Animate with an easing curve 
layerA.animate
    properties:
        scale: 0.75
    curve: "ease"
    delay: 0
    time: 1
Spring Curves

To make animations that feel truly native, you’ll want to work with spring curves. A spring curve consists of 3 elements:

  • tension (bounciness)
  • friction (weight)
  • velocity (wind-up)
# Animate with a spring curve 
layerA.animate
    properties:
        scale: 0.75
    curve: "spring(400,20,0)"

States

States allow you to define the different appearance options of a layer. A layer can have multiple states, each with a different set of properties. States can then be cycled through, with or without animation.
Adding States

Think of states as a different way to manage multiple animations. You start by adding the states, and then animate or cycle betweem them later.

In the example below, the default state of layerA contains the opacity property, plus all default layer properties. Next, a new state for layerA is defined, titled "fade", with an opacity set to 0.

# The default state 
layerA = new Layer
    opacity: 1
 
# A new state titled "fade" 
layerA.states.add
    fade:
        opacity: 0

For layerA to inherit the properties of the "fade" state, it needs to switch from the default state to the "fade" state.

# Switch states with animation 
layerA.states.switch("fade")
 
# Switch states without animation 
layerA.states.switchInstant("fade")
Toggling States

States can also be toggled between, using next() instead of switch(). Just like with layer animations, you can also customize the animation options of states.

# Add states 
layerA.states.add
    second:
        rotation: 0
 
# State animation options 
layerA.states.animationOptions =
    curve: "ease"
 
# Toggle states 
layerA.onTap ->
    layerA.states.next()
Editing States

You can remove and override previously defined states. To override states, simply add a new state with the same name.

# Remove second state 
layerA.states.remove("second")
 
# Override third states 
layerA.states.add
    third:
        blur: 10

Events

Events are things that can happen to layers, often triggered by user interaction. With events, you can animate layers based on these interactions. From simple taps and swipes to advanced multi-touch gestures.

Framer includes a ton of events. The most common ones you may be familiar with, like onTap, onScroll and like. Events can also be caused by animations, state switches, page changes and the like. And if you want to design more complex interactions, you can use the multi-touch gestures, like onEdgeSwipe and onPinch.

layerA.onTap ->
    ...
layerA.onScroll ->
    ...
layerA.onSwipe ->
    ...
layerA.onAnimationEnd ->
    ...

One of the most common use cases of events is toggling between a set of states on tap (which is click or touch).

# Toggle states on tap 
settings.onTap ->
    settings.states.next()
Example: Animation Chaining

Events can be used to chain animations. For example, you can start a new animation after another one ends by listening to the AnimationEnd event.

# Animation Events 
layerA.onAnimationStart ->
    ...
layerA.onAnimationEnd ->
    ...

Below is a simple example of a chained animation. Every animation gets an AnimationEnd event, so they can be chained infinitely.

layerA.animate
    properties:
        x: 80
    curve: "ease"
 
layerA.onAnimationEnd ->
    layerA.animate
        properties:
            x: 0
        curve: "ease"

Draggable

Draggable layers include physics and many customizable properties that open up new creative possibilities. By accounting for things like the speed and the direction, you can take greater control over dragging interactions.
Get Started

Let’s start by creating a draggable layer. Simply set draggable.enabled to true. Now, you can pick it up, place it elsewhere, and even toss it around.

You can also restrict the dragging direction, by disabling dragging horizontally or vertically. Both are enabled by default. You can also specify the speed. This can provide you with accelerated or reduced dragging.

# Make the layer draggable 
layerA.draggable.enabled = true
 
# Prevent vertical dragging 
layerA.draggable.horizontal = true
layerA.draggable.vertical = false
 
# Alternative way by setting the speed 
layerA.draggable.speedX = 1
layerA.draggable.speedY = 0
Constraints

In most cases, you’ll want to limit the range a layer can be dragged within. For example, think of the pull-to-refresh gesture, in which you can only drag a certain distance. In Framer, this can be achieved with constraints.

Constraints have x, y, width and height properties. Think of it as another layer, that contains your draggable layer.

# Make the layer draggable 
layerA.draggable.enabled = true
 
# Set the constraints frame 
layerA.draggable.constraints =
    x: 0
    y: 0
    width: 160
    height: 80
Overdrag, Bounce and Momentum

It’s likely you’re already familiar with these terms, even if you don’t know them by name. Let’s have a look at each of them.

A draggable layer can be dragged beyond its constraints, although it will snap back. This is called overdrag. Think of Safari on iOS, where you can drag websites beyond the top and bottom of the pages.

When a layer is moving in a direction, it can also bounce beyond its constraints. This is called bounce. It’s sort of like a rubber-band effect.

Finally, setting momentum to false disables the default physics of your draggable layer. You can still move it, but you can’t toss it around anymore. The momentum and bounce properties can also be customised. Have a look at this example of a custom draggable layer with constraints.

# Disable overdrag 
layerA.draggable.overdrag = false
 
# Disable bounce 
layerA.draggable.bounce = false
 
# Disable momentum 
layerA.draggable.momentum = false
Events

The three fundamental dragging events that you can listen to are: DragStart, DragMove and DragEnd. The Move event is fired whenever the draggable layer is moving. Unlike the DragMove event, this includes the momentum and bounce animations.

# Start dragging 
layerA.onDragStart ->
    layerA.animate
        properties:
            scale: 1.1
 
# After dragging 
layerA.onDragEnd ->
    layerA.animate
        properties:
            scale: 1
Drag Animation

There are two specific events that occur when momentum and bounce are enabled: DragAnimationDidStart and DragAnimationDidEnd. They occur after DragEnd, while the layer is animating.

# After DragEnd, the DragAnimation starts 
layerA.onDragAnimationStart ->
    layerA.animate
        properties:
            scale: 0.8
 
# Starts with the momentum and bounce 
layerA.onDragAnimationEnd ->
    layerA.animate
        properties:
            scale: 1

Pinchable

Pinchable layers can be scaled and rotated with two fingers. This multi-touch gesture is often seen in maps and photo apps, to zoom and navigate content.

In Framer for Mac, you can hold the alt key while moving your cursor to bring up a second cursor. This allows you to emulate multi-touch gestures. Just like with draggable layers, you can enable pinching by setting pinchable.enabled to true.

layerA = new Layer
layerA.pinchable.enabled = true

Pinchable layers contain scale and rotate properties, both enabled by default. By disabling the scale, you can only rotate a pinchable layer, and vice versa.

# Disable scale on pinch 
layerA.pinchable.scale = false
 
# Disable rotation on pinch 
layerA.pinchable.rotate = false
Pinch Events

The three basic pinchable events are: onPinch, onPinchStart and onPinchEnd. Let's have a look at the last one. Pinching adjusts the actual scale and rotation properties of a layer. So after a pinch, we can animate these properties back to their default values.

# Enable pinching 
layerA.pinchable.enabled = true
 
# Animate back to original position 
layerA.onPinchEnd ->
    layerA.animate
        properties:
            scale: 1
            rotation: 0
        curve: "spring(300,20,0)"
Panning

If you enable both dragging and pinching, the layer also becomes pannable. Panning is the same as dragging, except it’s a multi-touch gesture. You can detect a pan with the onPan event.

# Enable panning 
layerA.draggable.enabled = true
layerA.pinchable.enabled = true
 
# Animate back to original position 
layerA.onDragEnd ->
    layerA.animate
        properties:
            scale: 1
            rotation: 0
        curve: "spring(300,20,0)"

Components

Think of a component as a bundle of layers, with pre-defined interactions. Like the SliderComponent, which allows you to add sliders without having to create all the elements from scratch. They're completely customizable, but work out of the box.

Framer includes the following Components. Read more on the Scroll, Page and Slider Components in the sections below.

  • ScrollComponent
  • PageComponent
  • SliderComponent
  • MIDIComponent

Scroll

You’re probably familiar with the smooth scrolling on iOS. Getting this to feel just right involves a lot of physics. The ScrollComponent in Framer takes care of this for you, while remaining completely customizable.

A ScrollComponent is built with two layers. First, the ScrollComponent itself, which serves as a masking layer.

Second, the content layer, which has draggable enabled and pre-defined constraints. The size of the content layer is calculated for you, based on the size of its children.

# Create a ScrollComponent 
scroll = new ScrollComponent
    size: 120
 
# Create the content layers 
layerA = new Layer
    parent: scroll.content
 
layerB = new Layer
    parent: scroll.content

Similar to draggable layers, you can also restrict the scrolling direction.

scroll.scrollHorizontal = true
scroll.scrollVertical = false
Wrapping

A great way to bring your static designs to life with Framer is by using the Import feature. To add scrolling behavior to imported layers, you can wrap them in a ScrollComponent, using ScrollComponent.wrap().
Check out the Scrollable Template to see an example.

# Sketch Import 
sketch = Framer.Importer.load("imported/scrollable@1x")
 
# Wrap the imported content layers 
scroll = ScrollComponent.wrap(sketch.content)
Content Inset

To add some extra spacing to your content, you can use the contentInset property. This is useful to place content within a scrollable area. Think of a header on top a list. You can’t scroll beyond the header, but you can scroll the feed. An example of this can be seen in Twitter for iOS.

# Create a ScrollComponent 
scroll = new ScrollComponent
    width: 120
    height: 120
    scrollHorizontal: false
 
# Define the contentInset 
scroll.contentInset =
    top: 40
    bottom: 40
    right: 0
    left: 0
Events

The three fundamental scrolling events are: ScrollStart, Scroll (or ScrollMove) and ScrollEnd. Within the Scroll event, the positions of the scrollable layer can be retrieved. For example, animations can be started based on the vertical scrolling distance with scroll.scrollY.

# Create a ScrollComponent 
scroll = new ScrollComponent
    scrollHorizontal: false
 
# Listen to the Scroll event 
scroll.onScroll ->
    if scroll.scrollY < -10
 
        layerA.animate
            properties:
                scale: 1
Scroll Animation

Just like with draggable layers, there are two specific events that occur when momentum and bounce are enabled: ScrollAnimationDidStart and ScrollAnimationDidEnd. They occur after ScrollEnd.

# After Scroll, the ScrollAnimation starts 
scroll.onScrollAnimationDidStart ->
    layer.animate
        properties:
            width: 100
 
# After the scroll animation 
scroll.onScrollAnimationDidEnd ->
    layer.animate
        properties:
            width: 120

Page

With the PageComponent, piecing together multiple static screens into a single, interactive prototype is a breeze. It handles all of the calculations, allowing you to focus on the experience.

The PageComponent allows you to easily swipe between layers, in any direction. It’s based on the ScrollComponent.

# Create a PageComponent 
page = new PageComponent
 
# Create page layers 
layerA = new Layer
    parent: page.content
 
layerB = new Layer
    x: 110
    parent: page.content
Adding Pages

New pages can be added by using page.addPage(). This takes a layer, and places it on the right side. Pages can also be added on the bottom.

# Create a PageComponent 
page = new PageComponent
 
# Create a set of layers 
layerA = new Layer
layerB = new Layer
 
# Add layerA to the right 
# Add layerB to the bottom 
page.addPage(layerA)
page.addPage(layerB"bottom")

You can automatically generate a set amount of pages using a for-loop. Below, we create 10 new layers, and place each within the page.content. Finally, we set the x property by multiplying the index variable by 105.
This places each layer to the right, with 5 pixels of spacing.

# Create a PageComponent 
page = new PageComponent
    scrollVertical: false
 
# Create 10 layers 
for index in [0...10]
    layer = new Layer
        parent: page.content
        size: 200
        x: 210 * index
Wrapping

To add pagination behavior to imported layers, you can wrap them in a PageComponent, using PageComponent.wrap(). Have a look at the Artboards Template to see this in use.

# Sketch Import 
sketch = Framer.Importer.load("imported/pages@1x")
 
# Wrap the imported content layers 
page = PageComponent.wrap(sketch.content)
Ordering and Sorting

Detecting a page-switch can be done with the change:currentPage event. This is really useful when designing things like page indicators.

# Listen to any page switch 
page.on "change:currentPage"->
    page.previousPage.animate
        properties:
            opacity: 0.2
            scale: 0.8
        time: 0.2
 
    page.currentPage.animate
        properties:
            opacity: 1
            scale: 1
        time: 0.2

You don’t always want to start at the first page. You can also automatically snap to a page layer, with or without an animation.

# Snap to the layer pageThree 
page.snapToPage(pageThree)
 
# Snap with a custom animation curve 
page.snapToPage(pageTwotruecurve: "spring(200,25,0)")
Page Index

You can keep track of the index of your pages, measured either horizontally or vertically. The index is the page number, minus 1. This means the index will always start at 0 instead of 1. To highlight many of the mentioned properties and methods, have a look at this Page Indicator example.

page.on "change:currentPage"->
    for layer in indicators
        layer.animate
            properties:
                opacity: 0.5
 
    current = page.currentPage
    = page.horizontalPageIndex(current)
 
    indicators[i].animate
        properties:
            opacity: 1

Slider

Sliders can be used to show progress, change the volume, adjust photos, define a price range and more. With the SliderComponent, you can build adaptable designs without having to start from scratch.

The SliderComponent consists of 3 layers: the slider itself, the fill and the knob. The slider is track of the slider. The knob is used to change the value of the slider. The fill represents the current value. You can change the appearance of these layers, just like any other layer.

The SliderComponent has a few unique properties:

  • min (minimum value)
  • max (maximum value)
  • value (starting value)
  • knobSize (width and height of the knob)
# Create Slider 
slider = new SliderComponent
    min: 0
    max: 100
    value: 50
    knobSize: 40
 
# Customize fill color 
slider.fill.backgroundColor = "#fff"

The slider itself is simply a Framer layer, meaning you can change all of its visual properties. Same thing goes for the fill and knob layers.

# Customize slider 
slider.backgroundColor = "#DDD"
 
# Customize fill 
slider.fill.backgroundColor = "#00AAFF"
 
# Customize knob 
slider.knob.shadowY = 2
Value Changes

With the onValueChange function, you can detect value changes, and retrieve the current value as it’s being changed.

# Create Slider 
slider = new SliderComponent
    min: 0
    max: 100
    value: 50
 
# Get the current value 
slider.onValueChange ->
    print slider.value