4. Events

Align

The Align functions help you quickly position an object on the screen relative to its parent. Use these to place a Layer to the top, bottom, left, right or center of its parent. They can be used as layer properties, in states and animations.

# Create a layer an position it in the center

layerA =newLayer

x: Align.center

y: Align.center

# Create a state in the bottom right corner

layerA.states =

stateA:

x: Align.right

y: Align.bottom

stateB:

x: Align.left

y: Align.top

layerA.onTap -> layerA.stateCycle()

The Align functions calculate the correct value for x or y dynamically at the moment you actually want to position them. So if you have a state that puts a layer in the bottom right position, it will always do so, even if you resize the screen in between switching states.

You can also optionally use offsets:

layerA =newLayer

x: Align.center(-100)# 100 pixels left from the center

y: Align.top(100)# 100 pixels from the top

Please note that left and right only work for the x property, and top and bottom only for the y property. Center works for both. Align is a more flexible alternative to layer.center() that works well with Auto-Code direct editing.

align.bottom(offset)

Position the layer to the bottom of its parent. If there is no parent, it will use the Screen. Bottom only works for the y layer property. It can be used as a property, in states and in animations.

Arguments

offset — A number (optional).

layerA =newLayer

y: Align.bottom

layerB =newLayer

y: Align.bottom(-100)# 100 pixels from the bottom

align.center(offset)

Place the layer in the center, relative to its parent. If there is no parent, it will use the Screen. It can be used as a property, in states and in animations.

Arguments

offset — A number (optional).

layerA =newLayer

x: Align.center

y: Align.center

layerB =newLayer

x: Align.center(+100)

y: Align.center(-100)

align.left(offset)

Position the layer to the left of its parent. If there is no parent, it will use the Screen. Left only works for the x layer property. It can be used as a property, in states and in animations.

Arguments

offset — A number (optional).

layerA =newLayer

x: Align.left

layerB =newLayer

x: Align.left(100)# 100 pixels from the left

align.right(offset)

Place the layer to the right of its parent. If there is no parent, it will use the Screen. Right only works for the x layer property. It can be used as a property, in states and in animations.

Arguments

offset — A number (optional).

layerA =newLayer

x: Align.right

layerB =newLayer

x: Align.right(-100)# 100 pixels from the right

align.top(offset)

Position the layer to the top of its parent. If there is no parent, it will use the Screen. Top only works for the y layer property. It can be used as a property, in states and in animations.

Arguments

offset — A number (optional).

layerA =newLayer

y: Align.top

layerB =newLayer

y: Align.top(100)# 100 pixels from the top

Animation

Animation objects manage animations targeted on a layer. This is what is created by the layer’s animate function. The only difference is that animation objects don’t start immediately, you have to explicitly execute start().

The animation options allow you to define curves, timing, delays and more. Layers can run multiple animations at the same time. If animations affect the same layer properties, only the last one will run.

Properties

layer — A layer object, the targeted layer.

properties or state — An object with target values for the animated properties or a State object.

options — An object with all the animation options like curve, time and more. (Optional)

Example: Layer and properties

Here, we create a new Animation for layerA. Once we start the animation, it will move horizontally from 0 to 100. Note that we left out many optional arguments. By default, the animation will take 1 second, with an ease curve.

layerA =newLayer

# Animate the layer to the right

animationA =newAnimation layerA,

x:100

animationA.start()

Example: Layer and states

Animate a layer using a layer state by inserting the State object instead of layer properties.

layerA =newLayer

layerA.states.stateA =

x:100

# Animate the layer to the right

animationB =newAnimation layerA,

layerA.states.stateA

animationB.start()

Example: Multiple properties and time

Multiple properties can be animated at once. Here, we animate the x and opacity properties, with a duration of 5 seconds.

layerA =newLayer

# Animate multiple properties for 5 seconds

animationC =newAnimation layerA,

x:100

opacity:0.5

options:

time:5

animationC.start()

Example: Repeat and delay

When using repeat, the end values of properties will be reset to their starting position instantly. In the example below, there is a 2 second delay between every repeat.

layerA =newLayer

# Repeat an animation 5 times, delay for 2 seconds

animationD =newAnimation layerA,

x:100

options:

repeat:5

delay:2

animationD.start()

Animation Curves

Bezier.linear — Constant speed.

Bezier.ease — Ease curve.

Bezier.easeIn — Ease-in curve.

Bezier.easeOut — Ease-out curve.

Bezier.easeInOut — Ease-in-out curve.

Spring — A spring curve with damping.

Example: Bezier

layerA =newLayer

# Animate with a bezier curve

animationA =newAnimation layerA,

x:100

opacity:0.5

options:

curve: Bezier(0.25, 0.1, 0.25, 1)

Example: Spring

The default spring can be used along with the time property.

damping — Bounciness of the spring.

mass — Mass of the animating layer. (Optional)

velocity — Velocity at the start. (Optional)

layerA =newLayer

# Animate with a spring curve

animationA =newAnimation layerA,

x:100

options:

curve: Spring(damping:0.5)

time:0.5

Example: Classic Spring

The classic spring cannot be used with the time property.

tension — Strength of the spring.

friction — Weight of the spring.

velocity — Velocity at the start. (Optional)

tolerance — Minimal threshold before the animation ends. (Optional)

layerA =newLayer

# Animate with a spring curve

animationA =newAnimation layerA,

x:100

options:

curve: Spring(tension:250, friction:25)

Animatable Properties

Only numeric layer properties and color can be animated:

x, y, z

minX, midX, maxX

minY, midY, maxY

width, height

opacity

rotation, rotationX, rotationY, rotationZ

scale scaleX, scaleY, scaleZ

originX, originY, perspective

scrollX, scrollY

borderRadius, borderWidth

shadowX, shadowY, shadowBlur, shadowSpread

blur, brightness, saturate

hueRotate, contrast, invert, grayscale, sepia

Multiple Properties

You can start multiple animations targeting the same layer, as long as they don’t target the same properties. If you start two animations both targeting x for the same layer, the first one will be cancelled.

Performance

Most properties benefit from GPU accelerated drawing. You can animate many of them smoothly. But some properties need to involve the CPU to animate, and are therefore more expensive to render:

width

height

scrollX

scrollY

borderRadius

borderWidth

animation.start()

Start the animation.

layerA =newLayer

animationA =newAnimation layerA,

x:100

# Nothing will move until we start

animationA.start()

animation.stop()

Stop the animation.

layerA =newLayer

animationA =newAnimation layerA,

x:100

animationA.start()

# Stop the animation

animationA.stop()

animation.reverse()

Create a new animation with all reverse values.

layerA =newLayer

animationA =newAnimation layerA,

x:100

animationB = animationA.reverse()

# Alternate between the two animations

animationA.on Events.AnimationEnd, animationB.start

animationB.on Events.AnimationEnd, animationA.start

animationA.start()

animation.reset()

Reset the layer to its default state.

layerA =newLayer

animationA =newAnimation layerA,

x:100

animationA.start()

# On animation end reset the animation

animationA.on Events.AnimationEnd, ->

animationA.reset()

animation.restart()

Reset the layer to its default state and start the animation again.

layerA =newLayer

animationA =newAnimation layerA,

x:100

animationA.start()

# On animation end restart the animation

animationA.on Events.AnimationEnd, ->

animationA.restart()

animation.finish()

Stop the currently active animation and jump to its end state.

layerA =newLayer

animationA =newAnimation layerA,

x:100,

options:

time:3

animationA.start()

# Finish the animation after a 1 second delay

Utils.delay 1, ->

animationA.finish()

BackgroundLayer

A background layer is just a normal layer, but it scales with your window, so it always covers the entire canvas. If the background layer has a parent, the background will inherit the size of the parent.

layerA =newBackgroundLayer

backgroundColor:"white"

Colors can be defined by keywords, but also rgb and hex values.

# Hex value for white

layerA =newBackgroundLayer

backgroundColor:"#ffffff"

# RGB value for white

layerA =newBackgroundLayer

backgroundColor:"rgb(255,255,255)"

# RGBA value for white

layerA =newBackgroundLayer

backgroundColor:"rgba(255,255,255,1)"

Canvas

The Canvas object contains the size for the current entire document in pixels. It will change if you resize your document by resizing the window it is in.

Canvas.backgroundColor
<string>

Sets the background color of the canvas.

# Change the canvas background color

Canvas.backgroundColor ="#28affa"

Canvas.image
<string>

Sets the background image of the canvas. You can set it as a local path, or a link. The image will always fit to cover the canvas, and will never be stretched.

# Local images

Canvas.image ="images/background.png"

# Hosted images

Canvas.image ="http://framerjs.com/background.png"

Canvas.width
<number>

The width of the current entire document in pixels. (Read-only)

print Canvas.width

# Output: 640

Canvas.height
<number>

The height of the current entire document in pixels. (Read-only)

print Canvas.height

# Output: 480

Canvas.size
<object>

The width and height of the current entire document in pixels. (Read-only)

print Canvas.size

# Output: { width:640, height: 480 }

Canvas.frame
<object>

The x, y, width and height of the current entire document in pixels. (Read-only)

print Canvas.frame

# Output: { x:0, y:0, width:640, height: 480 }

Canvas.convertPointToScreen(point)

Converts a point from the Canvas to the Screen.

point =

x:20

y:40

pointInScreen = Canvas.convertPointToScreen(point)

Canvas.convertPointToLayer(point, layer)

Converts a point from the Canvas to a layer.

point =

x:20

y:40

layer =newLayer

pointInLayer = Canvas.convertPointToLayer(point, layer)

Color

The Color object can be used to define, detect, modify and mix colors. Colors can be defined using either a string value or an object. All colors are converted to a Color object with r, g, b, h, s, l and an a value.

bg =newBackgroundLayer

backgroundColor:"#28affa"

print bg.backgroundColor

# <Color "#28affa">

Supported color models: CSS Names, HEX, RGB, RGBA, HSL and HSLA.

# Multiple ways to define the same color:

blue =newColor("blue")

blue =newColor("#28AFFA")

blue =newColor("rgb(255, 0, 102)")

blue =newColor("rgba(255, 0, 102, 1)")

blue =newColor("hsl(201, 95, 57)")

blue =newColor("hsla(201, 95, 57, 1)")

You can also create new Color objects and pass in strings, or objects:

# Define a color with a HEX string

bg =newBackgroundLayer

backgroundColor:newColor("#fff")

# Define a color with an RGB object

layerA =newLayer

backgroundColor:newColor(r:255, g:255, b:255)

# Define a color with an HSL object

layerB =newLayer

backgroundColor:newColor(h:360, s:1, l:1, a:1)

Color Models

You can animate the background color, text color and shadow color of a layer. By default, color transitions use HUSL. With the colorModel property, you can specify in which model to animate. We support rgb, hsl and husl.

bg =newBackgroundLayer

backgroundColor:"blue"

# Animate in RGB

bg.animate

backgroundColor:"red"

options:

colorModel:"rgb"

color.lighten(amount)

Add white and return a lightened color.

Arguments

amount — A number, from 0 to 100. Set to 10 by default.

# Create a new color, lighten it

blue =newColor("#28affa").lighten(20)

layerA =newLayer

backgroundColor: blue

color.darken(amount)

Add black and return a darkened color.

Arguments

amount — A number, from 0 to 100. Set to 10 by default.

# Create a new color, darken it

blue =newColor("#28affa").darken(20)

layerA =newLayer

backgroundColor: blue

color.saturate(amount)

Increase the saturation of a color.

Arguments

amount — A number, from 0 to 100. Set to 10 by default.

# Create a new Color, saturate it

blue =newColor("#877DD7").saturate(100)

layerA =newLayer

backgroundColor: blue

color.desaturate(amount)

Decrease the saturation of a color.

Arguments

amount — A number, from 0 to 100. Set to 10 by default.

# Create a new Color, desaturate it

blue =newColor("#28affa").desaturate(25)

layerA =newLayer

backgroundColor: blue

color.grayscale()

Return a fully desaturated color.

# Create a new Color

yellow =newColor("yellow")

# Convert it to gray

gray = yellow.grayscale()

layerA =newLayer

backgroundColor: gray

color.gray(amount, alpha)

Generates a transparent white background.

Arguments

amount — A number representing the amount of white.

alpha — A number representing the alpha. (Optional)

layer =newLayer

layer.backgroundColor = Color.gray(0.5)

color.alpha(amount)

Increase the alpha value, also known as opacity, of the color.

Arguments

amount — A number, from 0 to 1. Set to 1 by default.

# Create a new Color, increase the opacity

blue =newColor("#28affa").alpha(.5)

layerA =newLayer

backgroundColor: blue

Color.mix(colorA, colorB, fraction, limit, model)

Blend two colors together, optionally based on user input. The fraction defines the distribution between the two colors, and is set to 0.5 by default.

Arguments

colorA — A color, the first one

colorB— A color, the second one

fraction — A number, from 0 to 1. (Optional)

limit — A boolean, set to false by default. (Optional)

model — A string, the color model used to mix. (Optional)

# Mix red with yellow

orange = Color.mix("red", "yellow", 0.5)

The limit defines if the color can transition beyond its range. This is applicable when transitioning between colors, using Utils.modulate. Below, the limit is set to true, so the transition cannot extend beyond the second color.

# Create new Layer

layerA =newLayer

backgroundColor:"red"

# Enable dragging

layerA.draggable.enabled =true

# On move, transition its color to yellow

layerA.on Events.Move, (offset)->

# Map the dragging distance to a number between 0 and 1

fraction = Utils.modulate(offset.x, [0, Screen.width], [0,1], true)

# Mix the colors, enable the limit, transition in HUSL

layerA.backgroundColor =

Color.mix("red", "yellow", fraction, true, "husl")

Color.random()

Returns a Color instance with a random color value set.

random = Color.random()

Color.isColor(value)

Checks if the value is a valid color object or color string. Returns true or false.

Arguments

value — An object or string, representing a color

print Color.isColor(newColor"red")# true

print Color.isColor("red")# true

Color.isColorObject(value)

Checks if the value is a valid color object. Returns true or false.

Arguments

value — An object, representing a color

print Color.isColorObject(newColor"red")# true

print Color.isColorObject("red")# false

Color.isColorString(value)

Checks if the value is a color string. Returns true or false.

Arguments

value — A string, representing a color

print Color.isColorString("red")# true

print Color.isColorString("#28affa")# true

Color.toHexString()

Returns the hexadecimal string representation of a color.

Arguments

value — An object or string, representing a color

blue =newColor("blue")

print blue.toHexString()# "#0000ff"

Color.toRgbString()

Returns the RGB string representation of a color.

Arguments

value — An object or string, representing a color

blue =newColor("blue")

print blue.toRgbString()# "rgb(0, 0, 255)"

Color.toHslString()

Returns the HSL string representation of a color.

Arguments

value — An object or string, representing a color

blue =newColor("blue")

print blue.toHslString()# "hsl(240, 100%, 50%)"

Defaults

The Framer.Defaults allows you to override the default properties for Layers and Animations when they are created. For example, all new layers get a light blue background color so you can see them. You can override that color here.

# Override the default background color for layers

Framer.Defaults.Layer.backgroundColor ="red"

# Override the default corner radius for layers

Framer.Defaults.Layer.borderRadius =10

layerA =newLayer

print layerA.backgroundColor

# Output: "red"

print layerA.borderRadius

# Output: 10

Here is an example to set the default animation curve. Note that those will also be used for layer.states switches unless you override them for a layer or state with the animationOptions property.

# Override the default animation options for all Animations

Framer.Defaults.Animation =

curve: Spring(damping:0.75)

# Override the default corner radius for layers

Framer.Defaults.Layer.borderRadius =10

layerA =newLayer

layerA.animate

x:100

# The animation will now use the spring curve

Device

The DeviceComponent emulates a device like an iPhone, iPad or Android. It allows you to scale the device, scale the content and adjust the orientation. After the device is set up, everything will render within its screen. Device previews match mirrored previews, meaning that if you're previewing on iPhone and then view it on an iPhone it will appear in fullscreen.

Scaling and orientation properties are also prefixed with Framer.Device:

Framer.Device.contentScale =0.5

Framer.Device.orientation =90

Underneath, the Device is just a collection of layers. That makes it easy to customize or add behaviour. You can find the entire source on Github. Here are some common examples:

Customize the device with a custom device image and sizes. If the device is a phone or tablet you can specify its type which will make sure the device image isn't visible when previewing on the device itself.

# Define and set custom device

Framer.Device.customize

deviceType: Framer.Device.Type.Tablet

screenWidth:720

screenHeight:1024

deviceImage:"http://f.cl.ly/items/001L0v3c1f120t0p2z24/custom.png"

deviceImageWidth:800

deviceImageHeight:1214

devicePixelRatio:1

Device.deviceType
<string>

The type of device to render. Below is an overview of all available options.

Dell XPS

Sony TV

Device.fullScreen
<boolean>

Set the device to render fullscreen, independent of the deviceType. Set to true or false.

# Render the device in fullscreen

Framer.Device.fullScreen =true

Device.deviceScale
<number / string>

The scale of the device. Supported scale values range from 0.5 to 1.

Framer.Device.deviceScale =0.5

Device.setDeviceScale(scale, animate)

The scale of the device and an optional animation (true or false). Supported scale values range from 0.5 to 1.

# Set device scale and animate

Framer.Device.setDeviceScale(0.5, true)

Device.contentScale
<number>

The scale of the content, including the custom device. Supported scale values range from 0.5 to 1.

# Set content scale

Framer.Device.contentScale =0.5

Device.setContentScale(scale, animate)

Sets the scale of the content, and an optional animation (true or false). Supported scale values range from 0.5 to 1.

# Set content scale and animate

Framer.Device.setContentScale(0.5, true)

Device.orientation
<number>

The orientation of the device. Supported orientation values are 0 and 90 (portrait and landscape orientations).

Framer.Device.orientation =90

Device.setOrientation(orientation, animate)

Sets the orientation of the device, and an optional animation (true or false). Supported orientation values are 0 and 90 (portrait and landscape orientations).

# Set orientation and animate

Framer.Device.setOrientation(90, true)

Device.orientationName
<string>

Set the device orientation by name. Valid options are "portrait" and "landscape". The portrait and landscape values are the same setting the device orientation to 0 and 90 respectively.

# Set orientation to either landscape or portrait

Framer.Device.orientationName ="landscape"

Framer.Device.orientationName ="portrait"

Device.rotateLeft()

Rotates the device to the left (clockwise).

Framer.Device.rotateLeft()

Device.rotateRight()

Rotates the device to the right (clockwise).

Framer.Device.rotateRight()

Draggable

Layers can be made horizontally and/or vertically draggable. They can be tossed around with momentum. To control where they end up, you can define a specific area that a layer can be dragged within. They can optionally be dragged beyond this area, but they will then bounce back by default.

layer.draggable.enabled
<boolean>

Enable dragging for the layer.

layerA =newLayer

layerA.draggable.enabled =true

layer.draggable.horizontal
<boolean>

Enable or disable horizontal movement.

layerA =newLayer

layerA.draggable.enabled =true

# Disable horizontal dragging

layerA.draggable.horizontal =false

layer.draggable.vertical
<boolean>

Enable or disable vertical movement.

layerA =newLayer

layerA.draggable.enabled =true

# Disable vertical dragging

layerA.draggable.vertical =false

layer.draggable.speedX
<number>

Modify the horizontal dragging speed. The value is in pixels per mouse moved pixels. The default value is 1. When set lower then 1 dragging will be slower than mouse movement and vice versa. You can set the value to 0 to disable horizontal dragging.

layerA =newLayer

layerA.draggable.enabled =true

# Make horizontal dragging slow

layerA.draggable.speedX =0.1

# Make horizontal dragging fast

layerA.draggable.speedX =10

layer.draggable.speedY
<number>

Modify the vertical dragging speed. The value is in pixels per mouse moved pixels. The default value is 1. When set lower then 1 dragging will be slower than mouse movement and vice versa. You can set the value to 0 to disable vertical dragging.

layerA =newLayer

layerA.draggable.enabled =true

# Make vertical dragging slow

layerA.draggable.speedY =0.1

# Make vertical dragging fast

layerA.draggable.speedY =10

layer.draggable.constraints
<object>

Constraints for the area this layer can be dragged within. If you also set the x and y properties as constraints, the layer will snap to that position on DragStart. The layer will animate to the new point on click.

layerA =newLayer

layerA.draggable.enabled =true

# Set dragging constraints

layerA.draggable.constraints =

x:0

y:0

width:200

height:200

layer.draggable.constraintsOffset
<object>

Get the offset position of a layer, compared to its dragging contraints. If you set the dragging constraints to { x: 100, y: 100 }, the layer will still be initially positioned at x: 0, y: 0. After dragging, the layer will be bound to its dragging contraints. This offset can be measured with constraintsOffset.

layerA =newLayer

layerA.draggable.enabled =true

# Set dragging constraints

layerA.draggable.constraints =

x:100

y:100

width:200

height:200

# Get the constraintsOffset

print layerA.draggable.constraintsOffset

# Returns { x:-100, y:-100 }

layer.draggable.isBeyondConstraints
<boolean>

See if the draggable layer is currently beyond its dragging constraints.
(Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Set dragging constraints

layerA.draggable.constraints =

x:100

y:100

width:400

height:400

# On move, see if the layer is beyond constraints or not

layerA.on Events.Move, ->

print layerA.draggable.isBeyondConstraints

layer.draggable.overdrag
<boolean>

Enable or disable dragging beyond the set constraints.

layerA =newLayer

layerA.draggable.enabled =true

layerA.draggable.constraints =

x:0

y:0

width:200

height:200

# Disable dragging beyond constraints

layerA.draggable.overdrag =false

layer.draggable.overdragScale
<number>

Set the dragging resistance when dragging beyond constraints. The scale is defined with a number between 0 and 1. The default value is 0.5.

layerA =newLayer

layerA.draggable.enabled =true

layerA.draggable.constraints =

x:0

y:0

width:200

height:200

# Increase resistance when dragging beyond constraints

layerA.draggable.overdragScale =0.25

layer.draggable.momentum
<boolean>

Enable or disable momentum/inertia simulation. Enabled by default.

layerA =newLayer

layerA.draggable.enabled =true

# Disable momentum

layerA.draggable.momentum =false

layer.draggable.momentumOptions
<object>

Options for momentum simulation on DragEnd.

layerA =newLayer

layerA.draggable.enabled =true

# Define friction and tolerance of momentum

layerA.draggable.momentumOptions =

friction:2.1

tolerance:0.1

layer.draggable.bounce
<boolean>

Spring animation when momentum runs beyond constraints.

layerA =newLayer

layerA.draggable.enabled =true

layerA.draggable.constraints =

x:0

y:0

width:200

height:200

# Snap back after dragging beyond constraints

layerA.draggable.bounce =false

layer.draggable.bounceOptions
<object>

Options for the spring animations when momentum runs beyond constraints.

layer.draggable.updatePosition(point)

Function to override the final value before setting it. Allows you to add your own behaviour to a draggable. This allows you to create draggable layers that snap between certain distances.

Arguments

point — An object with x and y properties.

layerA =newLayer

layerA.draggable.enabled =true

# Round numbers to a set amount

round =(number, nearest)->

Math.round(number / nearest)* nearest

# Drag in increments of 20px

layerA.draggable.updatePosition =(point)->

point.x = round(point.x, 20)

point.y = round(point.y, 20)

return point

layer.draggable.directionLock
<boolean>

Snap to horizontal/vertical direction after a certain threshold.

layerA =newLayer

layerA.draggable.enabled =true

# Allow dragging only in one direction at a time

layerA.draggable.directionLock =true

layer.draggable.directionLockThreshold
<object>

The thresholds for lock directions. The x and y values represent the distance you can drag in a certain direction before it starts locking.

layerA =newLayer

layerA.draggable.enabled =true

# Snap horizontally after dragging 50px

# Snap vertically instantly

layerA.draggable.directionLock =true

layerA.draggable.directionLockThreshold =

x:50

y:0

layer.draggable.pixelAlign
<boolean>

Snap to pixels while dragging to avoid subpixel-antialiasing.

layerA =newLayer

layerA.draggable.enabled =true

# Snap to pixel while dragging

layerA.draggable.pixelAlign =true

layer.draggable.isDragging
<boolean>

Whether the layer is currently being dragged (returns false when animating). (Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Check if the layer is being dragged

layerA.on Events.DragMove, ->

print layerA.draggable.isDragging

layer.draggable.isAnimating
<boolean>

Whether the layer is currently being animated by a momentum or bounce animation. (Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Check if the layer is animating

layerA.on Events.DragMove, ->

print layerA.draggable.isAnimating

layer.draggable.isMoving
<boolean>

Whether the layer is currently moving, either by dragging or by a momentum/bounce animation. (Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Check if the layer is moving

layerA.on Events.DragMove, ->

print layerA.draggable.isMoving

layer.draggable.offset
<object>

Get the x and y position of the draggable layer, relative to the Screen.
(Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Get the x and y position of the layer

layerA.on Events.DragMove, ->

print layerA.draggable.offset

layer.draggable.layerStartPoint
<object>

Get the x and y position of a draggable layer. (Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# On DragStart, get the current x and y position

layerA.on Events.DragStart, ->

print layerA.draggable.layerStartPoint

layer.draggable.cursorStartPoint
<object>

Get the x and y position of the cursor, relative to the Canvas.
(Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# On DragStart, get x and y position of the cursor

layerA.on Events.DragStart, ->

print layerA.draggable.cursorStartPoint

layer.draggable.layerCursorOffset
<object>

Get the x and y position of the cursor, relative to the draggable layer. If you click in the top left-corner, it returns { x: 0, y: 0 }. (Read-only)

layerA =newLayer

layerA.draggable.enabled =true

# Get the cursor position within the layer

layerA.on Events.DragStart, ->

print layerA.draggable.layerCursorOffset

layer.draggable.propagateEvents
<boolean>

Set the propagateEvents property of a draggable layer. Set to true by default. This is useful when working with draggable layers within ScrollComponents or PageComponents, or nested Components.

Let's say you'd like to have a draggable layer within the scroll.content layer. By default, moving the layer will also move the scroll.content. This is because both layers will listen to the dragging events.

To prevent any draggable children from passing events to its parent, set propagateEvents to false. This applies to all nested draggable layers.

scroll =newScrollComponent

width: Screen.width,

height: Screen.height

scroll.content.backgroundColor ="#28affa"

layerA =newLayer

parent: scroll.content,

backgroundColor:"#fff"

layerA.draggable.enabled =true

# Setting propagateEvents to false allows you to drag layerA

# without also scrolling within the ScrollComponent

layerA.draggable.propagateEvents =false

Events

Events are things that you can listen for. They can originate from the user, like a touch or click, or from an animation that ends. Most objects support event listening in Framer, but you will most often listen for events on layers.

When an event is called, the first argument is the event information. Depending on the event, this can contain mouse positions, mouse deltas etc. The second argument is always the layer that the event occurred to.

Change Events

The "change" event allows you to listen to properties as they're changing. Below is a full overview of properties you can listen for:

"change:x" — New x position.

"change:y" — New y position.

"change:point" — New x or y position.

"change:width" — New width value.

"change:height" — New height value.

"change:size" — New width or height values.

"change:frame" — New x, y, width or height values.

"change:scale" — New scale value.

"change:rotation" — New rotation value.

"change:borderRadius" — New borderRadius value.

"change:currentPage" — New currentPage layer.

"change:style" — New style declaration.

"change:html" — New html declaration.

"change:children" — Added or removed children.

"change:parent" — Added or removed parent.

For example, you can get the x position of a layer while it's animating. Note that it'll return the exact, sub-pixel values.

layerA =newLayer

layerA.animate

x:100

layerA.on "change:x", ->

print layerA.x

The "change" events can be used to link property changes to one another, with modulate. In the example below, we'll rotate the layer. The returned values are used to move the second layer horizontally.

layerA =newLayer

layerB =newLayer

x:100

# We rotate layerA from 0 to 180 degrees.

layerA.animate

rotation:180

# When the rotation value from layerA changes

layerA.on "change:rotation", ->

# Use the values to move layerB from 100 to 300

x = Utils.modulate(layerA.rotation, [0, 180], [100, 300], true)

layerB.x = x

Gesture Event Properties

Every gesture receives an event object with the following set of properties. The touchCenter, touchDistance, touchOffset, scale and rotation properties only return values when using multi-touch Events.

Positioning

event.point — Current x and y position

event.start — Start x and y position.

event.previous — Previous x and y position.

layerA =newLayer

layerA.pinchable.enabled =true

layerA.on Events.Pinch, (event)->

print event.point

Offset

event.offset — Current x and y offset.

event.offsetTime — Current duration since start.

event.offsetAngle — Current angle since start.

event.offsetDirection — Current direction since start.

layerA =newLayer

layerA.on Events.Pan, (event)->

print event.offset

Deltas

event.delta — Offset since last event.

event.deltaTime — Time since last event.

event.deltaAngle — Angle change since last event.

event.deltaDirection — Direction change since last event.

layerA =newLayer

layerA.on Events.Swipe, (event)->

print event.delta

Velocity & Force

event.velocity — Current speed in x and y values.

event.force — Current pressure sensitivity of a tap.

layerA =newLayer

layerA.on Events.Swipe, (event)->

print event.velocity

Input

event.fingers — Amount of fingers on screen.

event.touchCenter — Center point between two fingers.

event.touchDistance — Distance between two fingers.

event.touchOffset — Offset between two fingers.

layerA =newLayer

layerA.on Events.Rotate, (event)->

print event.fingers

Scale & Rotation

event.scale — Scale value from two fingers.

event.scaleDirection — Current scaling direction (up or down).

event.rotation — Rotation value from two fingers.

layerA =newLayer

layerA.pinchable.enabled =true

layerA.on Events.Pinch, (event)->

print event.scaleDirection

Events.touchEvent(event)

Extract the touch event from a given event on mobile.

layerA =newLayer

layerA.on Events.Click, (event, layer)->

myTouchEvent = Events.touchEvent(event)

Events.wrap(event)

Wrap a given DOM Element so we can keep track of the events and destroy them when needed. If you want to bind events to arbitrary dom element you should use this.

Events.wrap(window).addEventListener "resize", (event)->

print "Page is resizing"

Extras

Extras are optional parts of Framer that have specific tasks like preloading, touch emulation and hints. In general, they are enabled automatically based on where your prototype is shown. But extras are often overridable explicitly by you, if you require specific behaviour.

Hints

Hints are used to highlight layers that a user can interact with, such as taps, swipes, etc. They are mainly to help users discover what a project can do when they see it for the first time.

By default, hints are enabled both in Framer for Mac and when you share your prototypes with others. If you click anywhere outside of an interactive layer or outside of the device, purple rectangles will indicate the tappable or scrollable areas.

You can enable or disable hints for your entire projects like this:

Framer.Extras.Hints.disable()

Or enable them like this:

Framer.Extras.Hints.enable()

If you would like to show hints directly after a page loads, without any clicks you can do this:

Framer.Extras.Hints.enable()

Framer.Extras.Hints.showHints()

Some notes:

Draggable or scrollable areas will highlight if you tap them, but did not scroll.

Draggable or scrollable areas will only highlight if they can either scroll horizontal or vertically.

Layers with rounded corners will get a hint with rounded corners.

Rotated layers are currently unsupported.

Invisible layers will not show hints, unless they are set to invisible or their opacity is 0. They will show a hint if they are covered by another layer but still respond to taps.

Customization

You can override layers (or components based on layers) to customize the hint indicator (by default a purple rectangle). This is great when you want to disable the highlight on a specific layer, or have a specific visiual hint.

This is how you disable a hint on a specific layer:

layerA =newLayer

layerA.onTap -> print "layerA"

layerB =newLayerx:220

layerB.onTap -> print "layerB"

# Set an empty function on showHint

layerB.showHint =-> print "nope"

And you can customize the hint the same way:

layerA =newLayer

layerA.onTap -> print "layerA"

layerB =newLayerx:220

layerB.onTap -> print "layerB"

layerB.showHint =(hintFrame)->

# Create a hint layer, this will automatically be

# placed in the hints context on top of everything.

hint =newLayer

frame: hintFrame

backgroundColor:"red"

opacity:0.5

# Add a cool animation

hint.animate

scale:1.3

opacity:0

options:

time:0.5

# Remove the layer when done

hint.onAnimationEnd -> hint.destroy()

Preloader

When you open a project, our preloader makes sure your media is loaded before fully displaying. It analyzes the images and video you use and downloads them in the background, all while showing a circular progress indicator. When everything is fully loaded, it displays your project simultaneously.

A preloader vastly improves the user's experience because it avoids displaying your project in an incomplete state. When users interact with a prototype that is still loading, performance can suffer due to images being decompressed on the same thread that handles user interaction.

By default the preloader is only enabled outside of Framer, such as when you share a project online or via mirroring.

You can force enable the preloader like this:

Framer.Extras.Preloader.enable()

Or disable it like this:

Framer.Extras.Preloader.disable()

Customization

You can customize the preloader image with any image, such as your logo. To do so, use the setLogo() function:

Manually adding images

While the preloader often does a great job of discovering the main images used in your project, it may fail to locate specific images that were used at arbitrary points. The preloader also allows you to add these images manually using Framer.Extras.Preloader.addImage().

In the example below, the preloader cannot discover the image that layerB uses because it only gets created after a tap, and theoretically could be any url. So in this scenarios, we add the image manually at the top of the prototype.

Some notes:

Device images are not counted against the preloader and are shown instantly because they are likely cached.

There is a 30 second hard timeout on the preloader, after which your project gets shown even if not all images are loaded.

Cached images load faster the second time you visit a project.

Video preloading is based on the canplay event when enough buffer is available to play them.

Loading errors are counted as loaded, so that the project appears even if some images are missing.

The progress is based on image count and not loaded bytes, so if you have many small images and one big one, the last step may be significantly longer. Unfortunately, there is no great way to get progress based on size today.

FlowComponent

The FlowComponent helps you transition and navigate between multiple screens.
It’s built on two basic functions: showNext to transition to a new layer, and showPrevious to cycle back through previous layers. You can also use it to design overlays like modals, and fixed elements like a tab bar. The FlowComponent fires Transition events. Learn more about them here.

Properties

layer — A layer object, the targeted layer.

options — An object with all the animation options like curve, time and more. (Optional)

# Create layer

layerA =newLayer

size: Screen.size

# Create FlowComponent

flow =newFlowComponent

# Show the layer

flow.showNext(layerA, animate:true)

flow.showNext(layer, options)

Transition to a new layer. By default, it will animate to the layer, except if it’s the first layer added to the FlowComponent. If the width or height of the layer exceeds that of its parent, it will become scrollable. It also automatically detects whether to become vertically or horizontally scrollable.

flow.transition(layer, transition, options)

Create a custom transition. The transitions use states internally to cycle back and forward. There are three layers (current, next and background) with two states each (back and forward). If you don’t define a specific state, the FlowComponent assumes you don’t want to animate that layer.

The custom transition is a function that returns an object with states. Inside the function you have access to the arguments current FlowComponent, layerA, layerB and the overlay. If you don’t pass states for layerA, layerB or the overlay, it will leave the layer as is on a transition.

flow.current
<layer>

The layer (screen) that is currently visible.

# Create layer

layerA =newLayer

size: Screen.size

# Create FlowComponent, add layer

flow =newFlowComponent

flow.showNext(layerA)

# Get current screen

print flow.current

flow.scroll
<layer>

The automatically generated ScrollComponent layer. Any child layer that exceeds the width or height of the FlowComponent are automatically made scrollable. You can target the ScrollComponent with flow.scroll.

You can apply a gradient to a layer directly by using the layer.gradient property.

blue =newGradient

start:"#05F"

end:"#0DF"

layerA =newLayer

gradient: blue

All properties of the gradients object can be animated, too.

blue =newGradient

start:"#05F"

end:"#0DF"

purple =newGradient

start:"#30F"

end:"#B8F"

layerA =newLayer

gradient: blue

layerA.animate

gradient: purple

gradient.start
<string>

The start color. Set to black by default.

gradient =newGradient

start:"#05F"

gradient.end
<string>

The end color. Set to white by default.

gradient =newGradient

start:"#05F"

end:"#0DF"

gradient.angle
<number>

The angle of the gradient. Set to 0 by default.

gradient =newGradient

start:"#0DF"

end:"#05F"

angle:180

Layer

Layers are the basic containers of Framer, which can contain images, videos, or text. You can position layers with numeric values and dynamic values. Layers contain many properties that define their appearance, such as opacity, rotation and scale. Layers can also be nested to adjust their hierarchy.

To create a layer, use the new keyword. Every layer has a set of default properties: a blue background, and a default width and height of 100.

layerA =newLayer

You can set layer properties when creating them:

layerA =newLayer

x:100

y:100

width:250

height:250

opacity:0.5

backgroundColor:"white"

And you can also override them later:

layerA =newLayer

x:100

y:100

layerA.x =200

layer.id
<number>

A unique identification number for this layer. No other layer will have this number. The layer id is read only and cannot be changed.

layerA =newLayer

print layerA.id

# Output: 1

layer.name
<string>

The name of a layer. Layers aren't named by default. Imported layers will inherit the name you've defined within Sketch or Photoshop.

layerA =newLayer

layerA.name ="Button"

print layerA.name

# Output: "Button"

layer.x
<number>

The x property of a layer defines its x position relative to the top left corner.

layerA =newLayer

layerA.x =500

layer.y
<number>

The y property of a layer defines its y position relative to the top left corner.

layerA =newLayer

layerA.y =500

layer.z
<number>

The z property of a layer defines its position in space, also known as depth. The larger this value, the further away the object is from the point of view.

Remember that you will have to enable perspective on a parent layer before you can see this effect. Also note the z property is different from layer.index (z-index) which defines the order for layers when they all have the same z value.

layer.frame
<object>

Allows you to set or capture the x, y, width and height values of a layer.

layerA =newLayer

print layerA.frame

# Output: { x: 100, y: 100, width: 100, height: 100 }

layerA.frame =

x:10

y:200

width:10

height:10

print layerA.frame

# Output: { x: 10, y: 200, width: 10, height: 10 }

print layerA.x

# Output: 10

layer.props
<object>

Gets or sets all properties for this layer.

layerA =newLayer

# Get current layer properties

print layerA.props

# Output: { x: 100, y: 100, ...}

# Set properties

layerA.props =

rotation:90

opacity:0.5

layer.center()

Center this layer in its parent. If there is no parent, it will be centered relative to the screen.

layerA =newLayer

width:500

height:500

layerB =newLayer

parent: layerA

width:100

height:100

layerB.center()

print layerB.x, layerB.y

# Output: 200, 200

layer.centerX(offset)

Center this layer horizontally in its parent. If there is no parent it will be centered relative to the screen. The offset is a pixel offset from the center and optional.

Arguments

offset — A number that offsets the position.

layerA =newLayer

width:500

height:500

layerB =newLayer

parent: layerA

width:100

height:100

layerB.centerX()

print layerB.x, layerB.y

# Output: 200, 0

layerB.centerX(20)

print layerB.x, layerB.y

# Output: 220, 0

layer.centerY(offset)

Center this layer vertically in its parent. If there is no parent it will be centered relative to the screen. The offset is a pixel offset from the center and optional.

Arguments

offset — A number that offsets the position.

layerA =newLayer

width:500

height:500

layerB =newLayer

parent: layerA

width:100

height:100

layerB.centerY()

print layerB.x, layerB.y

# Output: 0, 200

layerB.centerY(20)

print layerB.x, layerB.y

# Output: 0, 220

layer.pixelAlign()

Round the x and y values of this layer to whole numbers. Allows you to snap layers on the pixel. This is useful when dynamically centering layers.

layerA =newLayer

x:100.18293

y:10.12873

layerA.pixelAlign()

print layerA.x, layerA.y

# Output: 100, 10

layer.screenFrame
<object>

Allows you to set or capture the absolute position of this layer on the screen, ignoring the inherited position from its parents.

layerA =newLayer

x:100

layerB =newLayer

parent: layerA

x:100

print layerB.screenFrame

# Output: { x: 200, y: 0, width: 100, height: 100 }

layerB.screenFrame =

x:400

y:0

width:100

height:100

print layerB.x

# Output: 300

layer.contentFrame()

The calculated frame for the total size of all the children combined.

layerA =newLayer

layerB =newLayer

parent: layerA

x:0

width:100

layerC =newLayer

parent: layerA

x:100

width:300

print layerA.contentFrame()

# Output: { x: 0, y: 0, width: 400, height: 100 }

layer.centerFrame()

The calculated frame, centered within its parent. If there is no parent, it will be centered relative to the screen.

layerA =newLayer

width:500

height:500

layerB =newLayer

parent: layerA

width:100

height:100

print layerB.centerFrame()

# Output: { x: 200, y: 200, width: 100, height: 100 }

layer.backgroundColor
<string>

Sets the background color for this layer. The color is expressed as a string in the CSS color format. Layers have a light blue background color by default.

layerA =newLayer

layerA.backgroundColor ="red"

layerA.backgroundColor ="#00ff00"

layerA.backgroundColor ="rgba(134, 12, 64, 0.3)"

layerA.backgroundColor ="transparent"

# Remove the background color

layerA.backgroundColor =""

layer.color
<string>

Sets the text color for this layer. The color is expressed as a string in the CSS color format. Layers have a white text color by default.

layerA =newLayer

layerA.color ="red"

layerA.color ="#00ff00"

layerA.color ="rgba(134, 12, 64, 0.3)"

layerA.color ="transparent"

# Remove the color

layerA.color =""

layer.gradient
<object>

Sets the gradient of this layer. By default, gradients made in Code have a start color of #FFF, an end color of #000 and an angle set to 0. Gradients can be used alongside the backgroundColor property, too.

layerA =newLayer

# Set a gradient

layerA.gradient =

start:"#05F"

end:"#0DF"

angle:0

layer.image
<string>

Sets the background-image url or path for this layer. You can set it as a local path or a full url. The image will always fit to cover the layer, and will never be stretched. You can remove an image by setting it to null or an empty string.

# Local images

layerA =newLayer

image:"images/logo.png"

# Hosted images

layerA.image ="http://framerjs.com/logo.png"

Setting an image will remove the default background color of a layer. Set the background color to another color than the default to show it behind the image.

# Show a color where the image is transparent

layerA =newLayer

image:"images/logo.png"

backgroundColor:"blue"

You can be notified of when an image is loaded and ready to display with the Events.ImageLoaded event. If there is an error loading an image (like not found) it will throw an Events.ImageLoadError event.

layerA =newLayer

# Listen to the loading event

layerA.on Events.ImageLoaded, ->

print "The image loaded"

layerA.on Events.ImageLoadError, ->

print "The image couldn't be loaded"

layerA.image ="images/logo.png"

layer.visible
<boolean>

Sets whether the layer should be visible or not.

layerA =newLayer

layerA.visible =false

layer.opacity
<number>

Sets the opacity for this layer. Opacity is defined with a number between 0 and 1 where 0 is invisible and 1 fully opaque.

layerA =newLayer

layerA.opacity =0.5

layer.clip
<boolean>

Sets whether the layer should clip its children. Clipping is disabled by default.

layerA =newLayer

width:100

height:100

layerB =newLayer

width:200

height:200

parent: layerA

layerA.clip =true

layer.ignoreEvents
<boolean>

Enable or disable any user events added to layers. When disabled, no user events on the layer will be emitted. The default value for this is true. Framer automatically disables it when you add an event listener.

layerA =newLayer

layerA.on Events.Click, ->

print "Click!"

# Now it won't respond to a click

layerA.ignoreEvents =true

# Now it will

layerA.ignoreEvents =false

layer.originX
<number>

Sets the x origin for scale, rotate and skew transformations. The origin is defined as a number, where 0 is the left edge of the layer and 1 the right edge. The default value is 0.5, the center of the layer.

layerA =newLayer

layerA.rotation =45

layerA.originX =0

layerA.originX =1

layer.originY
<number>

Sets the y origin for scale, rotate and skew transformations. The origin is defined as a number, where 0 is the top edge of the layer and 1 the bottom edge. The default value is 0.5, the center of the layer.

layerA =newLayer

layerA.rotation =45

layerA.originY =0

layerA.originY =1

layer.originZ
<number>

Sets the z origin for 3D transformations. The origin is defined in pixels. Positive values bring 3D layers closer to you, and negative values further way.

layerA =newLayer

originZ:-45

rotationY:90

layer.perspective
<number>

Sets the perspective for child layers. Perspective gives depth to 3d properties like rotationX, rotationY. The rotation is set from 1 to Infinity where 1 is a huge perspective. Setting perspective to 0 gives you an isometric effect. Perspective is disabled by default.

layerA =newLayer

# Set the perspective for all sub layers

layerA.perspective =100

layerB =newLayer

parent: layerA

rotationX:30

rotationY:30

layer.flat
<boolean>

Enable or disable 3D properties for all children of the layer.

# Enable flat on its children

layerA =newLayer

width:200

height:200

x:100

y:100

clip:false

flat:true

# Rotate horizontally

layerA.rotationX =45

# With flat enabled, adjusting z has no effect

layerB =newLayer

parent: layerA

z:25

layer.backfaceVisible
<boolean>

Defines whether a layer should be visible when not facing the screen. This is useful when an element is rotated, and you don't want to see its backside.

layerA =newLayer

layerA.backfaceVisible =false

layer.rotation
<number>

Sets the rotation, relative to its transform origin. The rotation is defined in degrees between 0 and 360. The default value is 0.

layerA =newLayer

layerA.rotation =45

layer.rotationX
<number>

Sets the x rotation, relative to its transform origin. The rotation is defined in degrees between 0 and 360. The default value is 0.

layerA =newLayer

layerA.rotationX =45

layer.rotationY
<number>

Sets the y rotation, relative to its transform origin. The rotation is defined in degrees between 0 and 360. The default value is 0.

layerA =newLayer

layerA.rotationY =45

layer.rotationZ
<number>

Sets the z rotation, relative to its transform origin. The rotation is defined in degrees between 0 and 360. Same as layer.rotation.

layerA =newLayer

layerA.rotationZ =45

layer.scale
<number>

Sets the scale, relative to its transform origin. The default scale is 1. Any number smaller then one will decrease the size and vice versa.

layerA =newLayer

layerA.scale =2

layer.scaleX
<number>

Sets the horizontal scale, relative to its transform origin. The default scale is 1. Any number smaller then one will decrease the size and vice versa.

layerA =newLayer

layerA.scaleX =2

layer.scaleY
<number>

Sets the vertical scale, relative to its transform origin. The default scale is 1. Any number smaller then one will decrease the size and vice versa.

layerA =newLayer

layerA.scaleY =2

layer.parent
<Layer object>

Sets the parent for this layer. You can set the parent to null if you want the layer to live at the root of your document. (Alias: superLayer)

layerA =newLayer

layerB =newLayer

layerB.parent = layerA

print layerB.parent

# Output: <Object:Layer layerA>

layer.children
<Array>

All the child layers of this layer. (Alias: subLayers)

layerA =newLayer

layerB =newLayer

parent: layerA

layerC =newLayer

parent: layerA

print layerA.children

# Output: [<Object:Layer layerB>, <Object:Layer layerC>]

layer.childrenWithName(name)

All child layers of this layer, filtered by name. (Alias: subLayersByName)

Arguments

name — A string of the layer name.

layerA =newLayer

layerB =newLayer

name:"navigation"

parent: layerA

layerC =newLayer

name:"button"

parent: layerA

print layerA.childrenWithName("button")

# Output: [<Object:Layer layerC>]

layer.siblings
<Array>

All sibling layers of this layer. (Alias: siblingLayers)

layerA =newLayer

layerB =newLayer

parent: layerA

layerC =newLayer

parent: layerA

print layerB.siblings

# Output: [<Layer layerC id:3 (0,0) 200x200>]

layer.siblingsWithName(name)

All sibling layers of this layer, filtered by name.

Arguments

name — A string of the layer name.

layerA =newLayer

layerB =newLayer

name:"navigation"

parent: layerA

layerC =newLayer

name:"button"

parent: layerA

print layerB.siblingsWithName("button")

# Output: [<Object:Layer name:button layerC>]

layer.descendants
<Array>

All descendant layers of this layer. These include layers that are nested multiple levels deep, so also the child layers of its own child layers.

layer.addChild(layer)

Add a layer as a child to this layer. This will set the parent of the added layer. (Alias: addSubLayer)

Arguments

layer — A layer object.

layerA =newLayer

layerB =newLayer

layerA.addChild(layerB)

print layerB.parent

# Output: <Object:Layer layerA>

layer.removeChild(layer)

Remove a layer from the children of this layer. (Alias: removeSubLayer)

Arguments

layer — A layer object.

layerA =newLayer

layerB =newLayer

parent: layerA

layerA.removeChild(layerB)

print layerB.parent

# Output: null

Layer.select(selector)

Select a layer with a specific name.

layer =newLayer

name:"a"

print Layer.select("a")

Layer.selectAll(selector)

Select all layers with a specific name.

layer =newLayer

name:"a"

layerB =newLayer

name:"a"

print Layer.selectAll("a")

layer.selectChild(selector)

Select a child layer with a specific name.

layer =newLayer

name:"a"

print layer.selectChild("a")

layer.selectAllChildren(selector)

Select all child layers with a specific name.

layer =newLayer

name:"a"

print layer.selectAllChildren("a")

layer.index
<number>

The order index for this layer. Sibling layers with a higher index (and the same z value) will drawn on top of this layer, and those with a lower index below.

The layer index increases by order of insertion. So if you add a layer as a child and the highest sibling index value is 5, the index of the inserted layer will be 6 (5 + 1). Or, the last inserted layer will always be on top.

layerA =newLayer

layerB =newLayer

# Draw layerB on top

layerA.index =2

layerB.index =1

layer.placeBefore(layer)

Places this layer before another layer. This changes the layer.index property for at least one of the layers. This method only works on layers that have the same parent, or no parent at all.

Arguments

layer — A layer object.

layerA =newLayer

layerB =newLayer

# Draw layerB on top

layerB.placeBefore(layerA)

layer.placeBehind(layer)

Places this layer behind another layer. This changes the layer.index property for at least one of the layers. This method only works on layers that have the same parent, or no parent at all.

Arguments

layer — A layer object.

layerA =newLayer

layerB =newLayer

# Draw layerB on top

layerA.placeBehind(layerB)

layer.bringToFront()

Places this layer in front of all other layers with the same parent.

layerA =newLayer

layerB =newLayer

layerC =newLayer

# Draw layerA on top

layerA.bringToFront()

layer.sendToBack()

Places this layer behind all other layers with the same parent.

layerA =newLayer

layerB =newLayer

layerC =newLayer

# Draw layerC last

layerC.sendToBack()

layer.html
<string>

Insert HTML content into this layer. The html can be anything, from text, to input and form elements to canvas or SVG content.

If you need to target any of the created elements, remember that they are only available after Framer rendered them. To reliably get a reference to a DOM element, use layer.querySelector or layer.querySelectorAll.

If the content that gets inserted needs user interaction, it's best to set layer.ignoreEvents to false. To retain the layer structure, the content is placed within an element that gets created when you set HTML for the first time.

layerA =newLayer

# Add simple text content

layerA.html ="Hello"

# Add inline styled text content

layerA.html ="I'm <span style='color:red'>Koen</span>"

# Add an input field

layerA.html ="<input type='text' value='Hello'>"

# Add a div with a canvas element and get a reference

layerA.html ="<div><canvas id='canvas'></canvas></div>"

canvasElement = layerA.querySelectorAll("#canvas")

layer.style
<object>

Set or get CC style properties for the layer.

Next to the standard CSS property names you can also camelCase naming. For example, layer.style["border-color"] is the same as layer.style.borderColor. For a full list see this overview.

layerA =newLayer

# Modify a single style property

layerA.style["outline"] ="1px solid red"

# Modify set of style properties

layerA.style =

"outline":"1px solid red",

"padding":"10px"

# Get a specific style property

print layerA.style["outline"]

# Output: "1px solid red"

layer.computedStyle()

Get all the current applied CSS style properties for the layer. Note that this is an expensive operation for the browser.
For a full reference on computed style, see this overview.

layerA =newLayer

layerA.backgroundColor ="red"

print layer.computedStyle()["background-color"]

# Output: "red"

layer.classList
<ClassList object>

A list of class attributed for the layer. Also contains methods to add, remove, toggle and check for classes.
For a full reference, see this overview.

layerA =newLayer

# Add the class .red

layerA.classList.add("red")

# Remove the class .red

layerA.classList.remove("red")

# Toggle the class .red

layerA.classList.toggle("red")

# See if the layer has class .red

print layerA.classList.contains("red")

# Output: true

layer.destroy()

This will remove a layer from the hierarchy and remove all its listeners. If the layer has children they will be destroyed too.

layerA =newLayer

layerA.destroy()

layer.copy()

This will copy a layer and all its children. The layers will have all the same properties as their copied counterparts (same position and looks). The event listeners will not be copied.

layerA =newLayer

layerB =newLayer

parent: layerA

layerC = layerA.copy()

layer.copySingle()

This will copy a layer without its children. Event listeners aren't copied.

layerA =newLayer

layerB =newLayer

parent: layerA

layerC = layerA.copySingle()

layer.blur
<number>

Adds a gaussian blur to the layer. Gaussian blur is defined in pixels. The default value is 0.

layerA =newLayer

layerA.blur =10

layer.backgroundBlur
<number>

Adds a background blur to the layer. Background Blur is defined in pixels. The default value is 0. Please note that this may not work in every browser, and can produce rendering artifacts. Learn more.

layerA =newLayer

layerA.backgroundBlur =10

layer.blending
<string>

Set the blending mode of the layer.

# Use soft light blending

layerA =newLayer

blending: Blending.softLight

Blending Options

Blending.normal — Normal (default) blending mode.

Blending.darken — Darken blending mode.

Blending.multiply — Multiply blending mode.

Blending.colorBurn — Color Burn blending mode.

Blending.lighten — Lighten blending mode.

Blending.screen — Screen blending mode.

Blending.colorDodge — Color Dodge blending mode.

Blending.overlay — Overlay blending mode.

Blending.softLight — Soft Light blending mode.

Blending.hardLight — Hard Light blending mode.

Blending.difference — Difference blending mode.

Blending.exclusion — Exclusion blending mode.

Blending.hue — Hue blending mode.

Blending.saturation — Saturation blending mode.

Blending.color — Color blending mode.

Blending.luminosity — Luminosity blending mode.

Alternatively, you can use a string notation.

# Use overlay blending

layerA =newLayer

blending:"overlay"

layer.brightness
<number>

Brightens or darkens a layer. Brightness is defined with a number. Setting brightness to 0 produces a completely black layer, while the value that produces a completely white layer depends on the color of your layer or image.

layerA =newLayer

layerA.brightness =10

layer.saturate
<number>

Saturates a layer. Saturation is defined with a number between 0 and 100 where 0 removes all saturation and 100 is default.

layerA =newLayer

layerA.saturate =50

layer.hueRotate
<number>

Sets the hue of a layer. The hue rotation is defined in degrees between 0 and 360. The default value is 0.

layerA =newLayer

layerA.hueRotate =180

layer.contrast
<number>

Sets the contrast of a layer. Contrast is defined with a number between 0 and 100 where 0 is removes all contrast. The default value is 100.

layerA =newLayer

layerA.contrast =50

layer.invert
<number>

Inverts the color of a layer. Invert is defined with a number between 0 and 100. The invert property inverts all colors and brightness values of a layer. Setting invert to 100 on a colored layer replaces all hues with their complementary colors. The default value is 0.

layerA =newLayer

layerA.invert =100

layer.grayscale
<number>

Grayscale converts all colors to gray. Grayscale is defined with a number between 0 and 100 where 100 turns all colors to a shade of gray. The default value is 0.

layerA =newLayer

layerA.grayscale =100

layer.sepia
<number>

Adds a sepia tone to your layer. Sepia is defined with a number between 0 to 100. The default value is 0.

layerA =newLayer

layerA.sepia =100

layer.shadows
<array>

Layers can have multiple shadows. You can inspect all included shadows by printing out the shadows property.

layerA =newLayer

shadow1:

y:10

blur:20

shadow2:

y:2

blur:4

print layerA.shadows

You can also use the shadows property to copy all shadows from one layer to another, without having to reference them one-by-one.

layerB =newLayer

layerB.shadows = layerA.shadows

You can set a specific shadow by using shadow with a number appended, like shadow1. These numeric properties range from 1—9, so the maximum amount of shadows you could add using them is 9.

layerA =newLayer

shadow1:

y:10

blur:20

color:"red"

layer.shadowX
<number>

Defines the shadow direction on the x-axis. A positive value will produce a shadow from the right edge of a layer, whereas a negative value will produce a shadow from the left edge. A visible shadow will only appear if the shadowColor property is also defined.

layerA =newLayer

layerA.shadowX =10

layer.shadowY
<number>

Defines the shadow direction on the y-axis. A positive value will produce a shadow from the bottom edge of a layer, whereas a negative value will produce a shadow from the top edge. A visible shadow will only appear if the shadowColor property is also defined.

layerA =newLayer

layerA.shadowY =10

layer.shadowBlur
<number>

Adds a Gaussian blur to the shadowX or shadowY property. shadowBlur is defined with a number. The default value is 0.

layerA =newLayer

layerA.shadowY =1

layerA.shadowBlur =4

layer.shadowSpread
<number>

Makes shadows larger in all directions. The shadow is expanded by the given value. Negative values cause the shadow to contract. If shadowX, shadowY and shadowBlur are all set to 0, this will appear as a border. A visible shadow will only appear if the shadowColor property is also defined.

layerA =newLayer

layerA.shadowY =1

layerA.shadowBlur =4

layerA.shadowSpread =2

layer.shadowColor
<string>

Sets the color of a layers shadow. The color is expressed as a string in the CSS color format.

layerA =newLayer

layerA.shadowY =1

layerA.shadowBlur =4

layerA.shadowColor ="rgba(0,0,0,0.2)"

layer.shadowType
<string>

Defines the type of shadow: inner or outer.

layerA =newLayer

layerA.shadowY =1

layerA.shadowBlur =4

layerA.shadowType ="inner"

layer.borderRadius
<number>

Rounds the corners of a layer in pixels. To create circles, set the property to a high value (50-100) or divide the layers width/height by two.

layerA =newLayer

layerA.borderRadius =3

# To create a circle:

layerA.borderRadius = layerA.width/2

layer.borderColor
<string>

Set the border color of this layer. The color is expressed as a string in the css color format.

layerA =newLayer

layerA.borderColor ="red"

layerA.borderWidth =2

layer.borderWidth
<number>

Set the width of the layer border in pixels.

layerA =newLayer

layerA.borderWidth =2

layerA.borderColor ="red"

layer.animate(properties or state, options)

Animate a layer by creating a new animation object with a set of layer properties or a state name. The optional animation options allow you to define how the layer animates using curves, timing and more. You can run multiple animations at a time as long as they don’t alter the same layer properties.

Arguments

properties or state — The layer properties or name of the state.

options — An object with all the animation options like curve, time and more. (Optional)

Example: Animate with properties

layerA =newLayer

# Animate the x position

layerA.animate

x:200

Example: Animate with properties and options

layerA =newLayer

# Animate the x position with options

layerA.animate

x:200

options:

curve: Spring(damping:0.5)

time:0.5

Example: Animate with states

layerA =newLayer

# Create a new state

layerA.states.stateA =

x:200

# State animation

layerA.animate "stateA"

Example: Animate with states and options

layerA =newLayer

# Create a new state

layerA.states.stateA =

x:200

# State animation with options

layerA.animate "stateA",

curve: Spring(damping:0.5)

time:0.5

layer.animationOptions
<object>

The animation options manage how and when the layer will be animated. Edit things like the curve and timing to change the appearance of an animation.

Once set, the animation options are set for every animation performed on the layer, unless they’re overruled. You can also set the animation options for individual layer states.

Properties

curve — A string, set to ease by default. (Optional)

curveOptions — An object with the options of the set curve. (Optional)

instant — A boolean, instantly jump to the end of an animation. (Optional)

layerA =newLayer

layerA.animationOptions =

curve: Bezier.ease

time:0.25

layer.animations()

Returns all the current running animations for this layer.

layerA =newLayer

layerA.animate

x:100

layerA.animate

y:100

print layerA.animations()

# Output: [<Object Animation>, <Object Animation>]

layer.isAnimating
<boolean>

A read-only property that checks if a layer is animating.

layerA =newLayer

layerA.animate

x:100

print layerA.isAnimating

# Result: True

layer.animateStop()

Immediately stop all animations running on this layer.

layerA =newLayer

# Stop an animation immediately

layerA.animate

x:100

layerA.animateStop()

layer.stateSwitch(name)

Instantly switch to a state without animating. (layer.stateSwitch() deprecated layer.states.switchInstant())

Arguments

name — A string, the name of the state.

layerA =newLayer

layerA.states.stateA =

x:100

layerA.stateSwitch("stateA")

layer.stateCycle(states, options)

Cycle through all the layer states. Once we reach the end of the cycle we start at the beginning again. You can provide an array of state names for the ordering, if you don’t it will order based on when a state was added.

layer.on(eventName, handler)

When an event is called the first argument is the event information. Depending on the specific event this can contain mouse positions, mouse deltas etc. The second argument is always the layer that the event occurred to.

MIDIComponent

A MIDI controller sends signals to your computer, similar to a keyboard or a mouse. Most commonly MIDI controllers have buttons, sliders and knobs that you can hook up to software. There is a wide variety of hardware MIDI controllers available on the market, many of them connect over USB. There are also MIDI controller apps, that connect over Bluetooth.

The MIDIComponent gives you the ability to work with MIDI controllers directly in Framer and in browsers that support the Web MIDI API.

Get Started

Connect a MIDI device

Open Framer and paste the following code

midi =newMIDIComponent

midi.onValueChange (value, info)->

print value, info

Now, when you change a button on the MIDI device you will see the values being printed, for example if you move a control from the start to end position:

» 0, {source:"111955983", channel:1, control:2}

» 1, {source:"111955983", channel:1, control:2}

» 2, {source:"111955983", channel:1, control:2}

…

» 125, {source:"111955983", channel:1, control:2}

» 126, {source:"111955983", channel:1, control:2}

» 127, {source:"111955983", channel:1, control:2}

By default, MIDIComponent will listen to MIDI signals from all controls and note buttons on all devices coming over any channel. You can use the properties you see printed above to filter the signal events. That way you can hook up control number 2 to a slider, for example:

midi =newMIDIComponent

control:2

slider =newSliderComponent

point: Align.center

max:127

midi.onValueChange (value)->

slider.value = value

The output values from MIDI are always between 0 and 127, but if you want to use the value to set a property that has a different range, you can use min and max to modulate the value for you. For example, the RGB components in a color range from 0 to 255, so you can use:

midi =newMIDIComponent

min:0

max:255

midi.onValueChange (value)->

Screen.backgroundColor =newColor

r: value, g:0, b:0

MIDIComponent.min
<number>

The value that will be send as the minimum value to the onValueChange handler. The default value is 0.

MIDIComponent.max
<number>

The value that will be send as the maximum value to the onValueChange handler. The default value is 127.

MIDIComponent.control
<number>

The number of the control, between 0 and 127. Filters out events not coming from this control.

To find the correct control number, you can use the extra information send to the handler of onValueChange.

MIDIComponent.channel
<number>

A number between 1 and 16 representing the channel. Filters out all events not coming from this channel.

To find the current channel of a control, you can use the extra information send to the handler of onValueChange.

MIDIComponent.source
<string>

The source to listen to. Filters out all events not coming from this source.

Each MIDI device has a unique source ID that is managed by the system. In general, the source ID should be stable, so that if you reconnect a device to the same computer, you should get the same ID. Note that the source ID will not be the same between different browsers and Framer.

To find the source ID, you can use the extra information send to the handler of onValueChange.

MIDIComponent.onValueChange(handler)

Handle MIDI signal events.

The handler gets two parameters, first the value of the signal and second an object with more information about the origin.

type (optional) — "note" if the signal is coming from a note, the value represents the velocity, 0 means the note is off.

Modules

Modules allow you to separate and organize parts of your prototype across different files. They're JavaScript or CoffeeScript files, which you can include (require) within your prototype. They help you organize your code, and choose what parts to focus on.

You can find them in the /modules folder of your prototype. Modules are based on JavaScript and Node.js standards. Everything that you've prefixed with exports in your module will be available in your prototype.
The require keyword imports your module.

If you want to add modules to an older project, we advice to create a new project in the latest Framer Studio, and copy over your files.

Get Started

Create a new project in Framer Studio

Navigate to the /modules folder and open the myModule.coffee file in a text-editor.

To include the module within your project, add the following:

# To include myModule.coffee in our prototype

module =require"myModule"

Make sure to save your file and refresh your prototype to see changes. Modules can contain anything. For example, you can create Layers within your modules, or define specific interactions within functions.

# Store variables

exports.myVar ="myVariable"

# Create functions

exports.myFunction =->

print "I'm running!"

# Create Arrays

exports.myArray =[1, 2, 3]

# Create Layers

exports.mylayerA =newLayer

backgroundColor:"#fff"

In the example above, a new layer is automatically created and included within our prototype. To also run the function, you can write:

# To include myModule.coffee

module =require"myModule"

# Run the function, printing "I'm running!"

module.myFunction()

Example: Interactions

Let's create a simple draggable interaction within a module. In our myModule.coffee file, we include the following function. It takes a layer, makes it draggable, and snaps it back to its original position on DragEnd.

# A draggable function without our module

exports.makeDraggable =(layer)->

layer.draggable.enabled =true

# Store current x and y position

startX = layer.x

startY = layer.y

# Animate back on DragEnd

layer.on Events.DragEnd, ->

this.animate

x: startX

y: startY

options:

curve: Spring(damping:0.5)

time:0.5

Now, within our prototype, we can call the makeDraggable function from our module to include the dragging interaction.

# Include module

module =require"myModule"

# Set background

bg =newBackgroundLayer

backgroundColor:"#28AFFA"

# Create a new layer

layerA =newLayer

backgroundColor:"#fff"

borderRadius:4

layerA.center()

# Add the dragging interaction to layerA

module.makeDraggable(layerA)

Example: npm

Framer modules work with npm, a package manager where thousands of JavaScript packages are published. Let’s import the Moment.js library. Make sure you already have npm installed.

# In your terminal

cd ~/my-project.framer

npm install moment

Create a new module in /modules, and name it npm.coffee. Beware that if you name the file the same as the npm module (like moment.coffee), you could run into a recursive import problem.

# File: modules/npm.coffee

exports.moment =require"moment"

After a refresh, you can import moment into your project.

# Import the moment module from your npm index

moment =require("npm").moment

# Or use this nice shortcut, which is the exact same

{moment} =require"npm"

And now you can use it in your project:

dayStarted =newLayer

html: moment().startOf("day").fromNow()

PageComponent

The PageComponent is based on the ScrollComponent, but designed for displaying paginated instead of continuous content. It supports content layers of different sizes, and can snap to layers based on location and scroll velocity.

page.originX
<number>

Defines how pages will be horizontally snapped to. The origin is defined as a number between 0 and 1, where 0 is the left-edge and 1 the right-edge. The default value is 0.5, the center.

page =newPageComponent

page.originX =0

page.originY
<number>

Defines how pages will be vertically snapped to. The origin is defined as a number between 0 and 1, where 0 is the top-edge and 1 the bottom-edge. The default value is 0.5, the center.

page =newPageComponent

page.originY =0

page.velocityThreshold
<number>

The velocityThreshold influences the role velocity plays in snapping to a different page. Besides the scrolling distance, the PageComponent also takes your scrolling speed (velocity) into account.

page =newPageComponent

page.velocityThreshold =0.2

To better understand the effects of adjusting the velocityThreshold, you can print out your velocity after scrolling. If you want switching between pages to be based mostly on distance, increase the velocityThreshold.

# Increase the velocityThreshold

page.velocityThreshold =5

# After switching between pages, print the velocity

page.on Events.ScrollEnd, ->

print Math.abs(page.velocity.x)

page.animationOptions
<object>

Set the animation options for the PageComponent. This defines the animation that occurs on ScrollEnd, when snapping to a page.

page =newPageComponent

page.animationOptions =

curve: Bezier.ease

time:0.25

page.currentPage
<Layer object>

Get the current page layer. (Read-only)

page =newPageComponent

# Get the current page layer

print page.currentPage

Note that you have to have pages within the page.content layer. You can also listen to the "change:currentPage" event to get the new currentPage, after it has been changed.

page =newPageComponent

# When the current page changes, print the new one

page.on "change:currentPage", ->

print page.currentPage

page.closestPage
<Layer object>

Get the closest page layer. (Read-only)

page =newPageComponent

# Get the current page layer

print page.closestPage

Note that you have to have pages within the page.content layer. You can also listen to the Scroll event to get the page closest page while scrolling.

# Create a new PageComponent and only allow horizontal scrolling.

page =newPageComponent

# Print the closest page while scrolling

page.on Events.Scroll, ->

print page.closestPage

page.nextPage(direction, currentPage)

Get the next page. Takes two arguments: direction and the currentPage. By default, the direction is set to "right" and the currentPage will be the first page.

page =newPageComponent

width: Screen.width

height: Screen.height

pageOne =newLayer

width: page.width

height: page.height

parent: page.content

backgroundColor:"#28affa"

pageTwo =newLayer

width: page.width

height: page.height

backgroundColor:"#90D7FF"

page.addPage(pageTwo, "right")

print page.nextPage()

We can also set the currentPage to any other page. For instance, we can look which layer is at the left of the second page.

# Get the page to the left of pageTwo

print page.nextPage("left", pageTwo)

# Returns pageOne

page.previousPage
<Layer object>

Get the previous page. Effectively the same as getting the page on the left using page.nextPage("left"). (Read-only)

page =newPageComponent

# Get the previous page

print page.previousPage

page.snapToPage(page, animate, animationOptions)

Snap to a specific page. Takes three arguments: a page.content layer, animate (true or false) and animation options. By default, animate is set to true and the animationCurve use a spring curve.

page =newPageComponent

width: Screen.width

height: Screen.height

pageOne =newLayer

width: page.width

height: page.height

parent: page.content

backgroundColor:"#28affa"

pageTwo =newLayer

width: page.width

height: page.height

backgroundColor:"#90D7FF"

page.addPage(pageTwo, "right")

# Automatically scroll to pageTwo

page.snapToPage(pageTwo)

In the example above, we can customize the scrolling animation by defining custom animationOptions as well.

# Define a slower easing curve

page.snapToPage(

pageTwo

true

animationOptions =time:2

)

page.snapToNextPage(direction, animate, animationOptions)

Snap to a specific the next page. Takes three arguments: direction, animate (true or false) and animation options. By default, the direction is set to "right" and animate is true.

page =newPageComponent

width: Screen.width

height: Screen.height

pageOne =newLayer

width: page.width

height: page.height

parent: page.content

backgroundColor:"#28affa"

pageTwo =newLayer

width: page.width

height: page.height

backgroundColor:"#90D7FF"

page.addPage(pageTwo, "right")

# Automatically scroll to pageTwo

page.snapToNextPage()

This allows you to snap to pages in any direction. For example, we can start on the first page by snapping to it without animating, and then animate back to the first page.

# Start at page two by default

page.snapToPage(pageTwo, false)

# Scroll back to the page at its left, which is pageOne

page.snapToNextPage("left", true)

page.snapToPreviousPage()

Snaps to the previous page. It keeps track of all previously visited pages, included the direction.

page =newPageComponent

# Snap to the previous page

page.snapToPreviousPage()

page.addPage(direction)

Add a new page to the page.content layer of the PageComponent. It takes two arguments: a layer (page) and a direction ("right" or "bottom").

page =newPageComponent

width: Screen.width

height: Screen.height

# The first page, placed directly within the page.content

pageOne =newLayer

width: page.width

height: page.height

parent: page.content

backgroundColor:"#28affa"

# Second page

pageTwo =newLayer

width: page.width

height: page.height

backgroundColor:"#90D7FF"

# Third page

pageThree =newLayer

width: page.width

height: page.height

backgroundColor:"#CAECFF"

# Add the second and third page to the right

page.addPage(pageTwo, "right")

page.addPage(pageThree, "right")

If you're looking to add pages to the left, you can initially add them to the right, and instantly switch to a different page, using snapToPage().

page =newPageComponent

width: Screen.width

height: Screen.height

pageOne =newLayer

width: page.width

height: page.height

parent: page.content

backgroundColor:"#28affa"

pageTwo =newLayer

width: page.width

height: page.height

backgroundColor:"#90D7FF"

# Add a page to the right

page.addPage(pageTwo, "right")

# Start at the second page by default

page.snapToPage(pageTwo, false)

page.horizontalPageIndex(page)

Get the index for a page component with horizontal pages. This is a number between 0 and the number of pages minus 1.

page =newPageComponent

width: Screen.width

height: Screen.height

pageA =newLayer

size: page.size

pageB =newLayer

size: page.size

page.addPage(pageA, "right")

page.addPage(pageB, "right")

print page.horizontalPageIndex(pageA)

# Prints: 0

print page.horizontalPageIndex(pageB)

# Prints: 1

page.verticalPageIndex(page)

Get the index for a page component with vertical pages. This is a number between 0 and the number of pages minus 1.

page =newPageComponent

width: Screen.width

height: Screen.height

pageA =newLayer

size: page.size

pageB =newLayer

size: page.size

page.addPage(pageA, "bottom")

page.addPage(pageB, "bottom")

print page.verticalPageIndex(pageA)

# Prints: 0

print page.verticalPageIndex(pageB)

# Prints: 1

Pinchable

Pinchable layers can be scaled and rotated with two fingers. By default, both of these properties are enabled. You can also define custom scale ranges, by defining minimum and maximum values.
To pinch layers within Framer Studio, hold the alt key while moving your cursor.

layer.pinchable.enabled
<boolean>

Enable pinching for the layer.

layerA =newLayer

layerA.pinchable.enabled =true

layer.pinchable.threshold
<number>

The minimal distance between two pointers before the gesture is recognized. Set to 0 by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Set the minimal distance to 10

layerA.pinchable.threshold =10

layer.pinchable.centerOrigin
<boolean>

Sets the transform origin of your pinchable layer to the center point between your fingers. Set to true by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Always scale from the center of the layer

layerA.pinchable.centerOrigin =false

layer.pinchable.scale
<boolean>

Enable or disable scaling on pinch. Set to true by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Disable scale on pinch

layerA.pinchable.scale =false

layer.pinchable.scaleIncrements
<number>

Scale the pinchable layer incrementally.

layerA =newLayer

layerA.pinchable.enabled =true

# Scale in increments of 0.5 (0.5, 1, 1.5, 2)

layerA.pinchable.scaleIncrements =0.5

layer.pinchable.minScale
<number>

Set the minimal scale value of the pinchable layer.

layerA =newLayer

layerA.pinchable.enabled =true

# Set the minimal scale to 0.5

layerA.pinchable.minScale =0.5

layer.pinchable.maxScale
<number>

Set the maximal scale value of the pinchable layer.

layerA =newLayer

layerA.pinchable.enabled =true

# Set the maximal scale to 2

layerA.pinchable.maxScale =2

layer.pinchable.scaleFactor
<number>

Set the scaling factor of the pinchable layer. Set to 1 by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Increase scaling speed by 2

layerA.pinchable.scaleFactor =2

layer.pinchable.rotate
<boolean>

Enable or disable rotation on pinch. Set to true by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Disable scale on pinch

layerA.pinchable.rotate =false

layer.pinchable.rotateIncrements
<number>

Rotate the pinchable layer incrementally.

layerA =newLayer

layerA.pinchable.enabled =true

# Rotate in increments of 15 degrees

layerA.pinchable.rotateIncrements =15

layer.pinchable.rotateFactor
<number>

Set the rotation factor of the pinchable layer. Set to 1 by default.

layerA =newLayer

layerA.pinchable.enabled =true

# Increase the rotation speed by 2

layerA.pinchable.rotateFactor =2

Print

Printing allows you to inspect variables on runtime. It works similarly to console.log, only when using print, the output is shown directly within your prototype. Note that you need to use print() in Javascript (but not in CoffeeScript). We will omit these in the rest of