Time to animate!
Let’s recreate the circle and give it a descriptive name:
orangeCircle = new Layer width: 300 height: 300 backgroundColor: "orange" borderRadius: 150
y properties were omitted because we will now use functions to position the circle.
orangeCircle = new Layer width: 300, height: 300 backgroundColor: "orange" borderRadius: 150 x: Align.center y: Align.center
Align.center function looks at the width (or height) of the screen and calculates which
y value is needed to place the layer in the center.
You can test this by changing the preview window to one of the device presets. Whatever the dimensions of the screen might be, the circle will always be smack in the middle.
We now add an animation in the simplest way possible.
orangeCircle in the Layer Panel to add an Animation.
Give it zero opacity (with the slider in the Properties Panel), and a scale of
6 (you’ll have to type the value in the Properties Panel).
orangeCircle.animate opacity: 0.00 scale: 6.00 options: time: 1 curve: Bezier.ease
Creating an animation is simple: after
animate you type the properties to which you want to animate.
opacity: 0– animate to zero opacity
scale: 6– make the circle six times as big
Here we’re animating
1 (the default, fully opaque) to
0 (completely transparent) and
6, all at the same time. You can add as many properties as you want and they will all animate simultaneously.
Framer also added the default animation
options. These values refer to the animation itself:
time: 1– the animation will take one second to complete
curve: Bezier.ease– this default curve makes an animation look more natural because it doesn’t start abruptly and slows down gradually at the end
Let’s add a few more properties:
orangeCircle.animate opacity: 0.00 scale: 6.00 options: time: 1 curve: Bezier.ease repeat: 5 delay: 1
You can also find these settings in the animation tab of the Properties Panel. Click the handle next to the animation to put it back in edit mode.
repeat: 5– repeat the animation five times (after the default first run)
delay: 1– with a delay of one second (between each repetition)
How to restart the animation? You can, of course, ⌘R reload the prototype, but wouldn’t it be better if we could trigger it with a tap?
Taps, swipes and other gestures are called events in Framer. You make a layer listen for an event, so it knows what to do when it’s tapped or dragged, etc.
You can add (most) events with the Event button, or by right-clicking the layer’s name in the Layer Panel.
orangeCircle in the Layer Panel to give it a
orangeCircle.onTap (event, layer) ->
In this event handler, you then write what should happen when this layer is tapped, this can be just one animation (or other action), or many. Be sure to indent, so that the lines are inside the event handler’s block.
What do we want to happen when the user taps it? We want to trigger our animation, so we place the
animate block inside the event block.
orangeCircle.onTap (event, layer) -> orangeCircle.animate opacity: 0.00 scale: 6.00 options: repeat: 1
Pro tip: To shift the indentation of multiple lines (e.g., the animation above) to the right: select the lines and type ⌘]. (To the left: ⌘[)
I got rid of the delay and changed the
repeat to just
1 so that it animates twice. I also removed the
curve properties because they contained the default values anyway.
We’ve attached an
onTap event to the layer. The above lines say the following:
In the event of a tap on orangeCircle, run this animation on orangeCircle.
(event, layer) parameters show that the event handler receives information about the ‘event’ itself, and the ‘layer’ that’s being tapped.
Since we want to animate the layer that’s tapped (and not any another layer), we can write
layer.animate instead of
orangeCircle.onTap (event, layer) -> layer.animate opacity: 0.00 scale: 6.00 options: repeat: 1
When you want to have more control over your animations, like being able to stop them, reverse them, or chain animations, you can use ‘animation objects.’
We’ll create one now. Type this under the code that created the layer:
# grow the circle circleGrow = new Animation orangeCircle, opacity: 0 scale: 6 options: curve: Spring
You create an
Animation object with the
new keyword, just like a layer object. And right after
Animation, you set which layer it should animate (here
orangeCircle), followed by a comma (
I added a spring
curve so that we’ll have a bouncy animation.
In our ‘event handler,’ we can now remove the earlier
layer.animate code and simply
start() our animation object.
# grow the circle circleGrow = new Animation orangeCircle, opacity: 0 scale: 6 options: curve: Spring orangeCircle.onTap (event, layer) -> circleGrow.start()
Note that text that starts with a hash, like
# grow the circle, is ignored by Framer. You can use hashes to leave comments for yourself or temporarily cancel out a few lines of code.
There’s a keyboard shortcut for commenting out text: ⌘/. You don’t have to drag and select the text for it; the cursor just needs to be on the line you want to comment out.
You’ll notice that you still have to reload the prototype to reset the animation. Animations only go one way, so we need a second animation to shrink the circle again.
Fortunately, there’s a function to quickly create the reverse of an existing animation object:
# shrink it again circleShrink = circleGrow.reverse()
We made a new animation,
circleShrink, by calling the
reverse() function on
circleGrow. This new animation does exactly the same thing as the original one, but backwards.
Next, we want to know when the growing ends so that we can trigger the shrinking. We’ll listen to the
onAnimationEnd event of the
circleGrow animation. The Event button (or right-clicking the layer name) only lets you add events to layers, but you can add the event to
orangeCircle and then change it to
# trigger shrinking after growing circleGrow.onAnimationEnd (event, layer) -> circleShrink.start()
These new lines say:
In the event of the ending of the circleGrow animation, start the circleShrink animation.
If you’re adding just one single function to an event you can also write it more concisely, like this:
# trigger shrinking after growing circleGrow.onAnimationEnd circleShrink.start
(Note that the parenthesis after
start() are omitted.)
Now, what do you think would happen if you added this extra line?