In my last article, I talked about how to start working with Framer, create beautiful prototypes by importing layers from Sketch, and also showed how to create pretty loading with percentages.
After the article was published on habrahabr -
right here , I decided to continue my experiments with Framer, simply because I no longer see my designer everyday life without this fascinating thing.
The purpose of the new prototype was again
loading , but in a different format, created
without importing layers from anything. The prototype serves to illustrate the capabilities of Framer and to describe my experiments with the code.
')
So, this is what we will create in this tutorial:
Three screens of a simple prototype:
Login and password entry screen
Boot screen
Welcome screen
The result can be seen here:
http://share.framerjs.com/s6q2nzb8xf3f/
We will create all interface elements immediately in Framer (without importing layers from Sketch or Photoshop).
We will complicate the task by trying to create a prototype for a device that is not on the Viewer list in Framer. But, first, we look at what devices are still there:

As you can see, there is no Samsung Galaxy Tablet. We will use it then.
If accuracy is important for the prototype, then you need to find a picture of the Samsung Galaxy Tablet equal to the actual size of the tablet (2560 * 1600 px).
In this tutorial, natural sizes are not fundamental, as is what is depicted on the screen of the device.
I used
this picture here .
Its size (1500 * 1000 px).
Write the parameters:
Framer.DeviceView.Devices["custom"] = "deviceType": "tablet" "screenWidth": 1258 "screenHeight": 784 "deviceImage":"http://www.androidheadlines.com/wp-content/uploads/2014/09/81WUwHeaVKL._SL1500_.jpg" "deviceImageWidth": 1500 "deviceImageHeight": 1000 Framer.Device.deviceType = "custom"
The screen sizes are 1258 * 784 for us, as they completely cover what is shown on the screen of the device in the picture.
Create a background layer for the “Sign In” screen:
Framer.DeviceView.Devices["custom"] = "deviceType": "tablet" "screenWidth": 1258 "screenHeight": 784 "deviceImage":"http://www.androidheadlines.com/wp-content/uploads/2014/09/81WUwHeaVKL._SL1500_.jpg" "deviceImageWidth": 1500 "deviceImageHeight": 1000 Framer.Device.deviceType = "custom"
Now you can draw on this layer the fields for login, password and the “Sign in” button.
In order to be able to enter the password and login in the fields, you need to download the InputField.coffee module. I used a module created by Jordan Robert Dobson. Download it
here .
After downloading, go to the “modules,” folder, copy the InputField.coffee file and paste it into the “modules” folder of your project.

In Framer write:
Framer.DeviceView.Devices["custom"] = "deviceType": "tablet" "screenWidth": 1258 "screenHeight": 784 "deviceImage":"http://www.androidheadlines.com/wp-content/uploads/2014/09/81WUwHeaVKL._SL1500_.jpg" "deviceImageWidth": 1500 "deviceImageHeight": 1000 Framer.Device.deviceType = "custom"
Now, we can create input fields. Let's start with the password field, since this field will be located in the center of the screen:
Password = new InputField width: 640 height: 100 color: "#212121" backgroundColor: "#fff" borderWidth: 1 borderColor: "#60B9F4" borderRadius: 10 fontSize: 36 fontFamily: "Proxima Nova" indent: 48 placeHolder: "Type Password" placeHolderFocus: "********" Password.center()
In the parameters, we, in addition to the basic characteristics, also described what should be displayed in the field when we put the cursor there - in this case, just asterisks: placeHolderFocus: “********”
Next, write the login field parameters:
Login = new InputField width: 640 height: 100 color: "#212121" y: Password.y - 130 backgroundColor: "#fff" borderWidth: 1 borderColor: "#60B9F4" borderRadius: 10 fontSize: 36 fontFamily: "Proxima Nova" indent: 48 placeHolder: "Type Login" placeHolderFocus: "example@gmail.com" Login.centerX()
As you can see, we set this field to the position y = Password.y - 130, that is, 130 px higher than the Password field and leveled it along the X coordinate along the center.
Now we create a button that will be below the Password field on 160 px:
Button = new Layer width: 640 height: 100 borderWidth: 1 borderColor: "#60B9F4" borderRadius: 10 html: "SIGN IN" backgroundColor: "#60B9F4" y: Password.y + 160 Button.centerX() Button.style.color = "#fff" Button.style.fontSize = "48px" Button.style.fontFamily = "Proxima Nova" Button.style.lineHeight = "100px" Button.style.textAlign = "center"
We write the title of this screen. For example, the phrase “Welcome to our system!”.
In order not to further specify a specific state for the header, we can set its parent layer for it - superLayer. They will, for example, the Password field. Now, the title will change the state along with its parent layer - the Password field.
Text = new Layer backgroundColor: null width: 640 html: "Welcome to our system!" color: "#212121" superLayer: Password y: - 240 Text.centerX() Text.style.fontSize = "48px" Text.style.fontFamily = "Proxima Nova" Text.style.textAlign = "center"
Since we can already enter our login and password in the fields, it is time to click on the “Sign in” button. We make for her hover.
In hover state, the button and the inscription on it will change color and increase slightly in size. To make the color change smoothly, first set the transition and spring curve style to the button:
Button.style.transition = "background-color 1s ease" Button.states.animationOptions = curve: "spring(600,60,0)"
Now, you can record the onMouseOver event:
Button.onMouseOver -> Button.style.backgroundColor = "white" Button.style.color = "#60B9F4" Button.scale = 1.05
In order for the button to return to its original state when we move the mouse away from it, we need to create a reverse onMouseOut event:
Button.onMouseOut -> Button.style.backgroundColor = "#60B9F4" Button.style.color = "white" Button.scale = 1
The first screen is ready.

The next loading screen will appear after we click on the button.
First we need to remove the login and password screen. Let it move to the left when you press the button. Set states for screen elements.
signInBackground.states.add Pressed: x: -2000 Button.states.add Pressed: x: -2000 Login.states.add Pressed: x: -2000 Password.states.add Pressed: x: -2000
Now all elements have a new state - their position is shifted to the left by 2000 px from the original. As you can see, we do not set a separate state for the Text layer - since it will move along with its parent element - the signInBackground layer.
Create an event - click on the button:
Button.on Events.Click, -> Button.states.switch("Pressed", time: .4, curve: "easy out") Password.states.switch("Pressed", time: .4, curve: "easy") Login.states.switch("Pressed", time: .4, curve: "easy") signInBackground.states.switch("Pressed", time: 1, curve: "easy out")
Here we also wrote the time with which each element will change its state, and also set the curve of these changes.
We are starting to create a loading screen. We need 2 background layers. The first we make blue, the second white.
And for the second layer of the parent we will make the first layer.
The second layer is set overlay mode - screen (mixBlendMode: “screen”).
loadColor = new BackgroundLayer backgroundColor: "#60B9F4" backgroundLayer = new BackgroundLayer backgroundColor: "#fff" style: mixBlendMode : "screen" superLayer: loadColor
We draw 4 absolutely identical circles (0, 1, 2, 3, 4) with exactly the same position in the center of the screen. In order not to draw each one separately, simplify the task for yourself by creating an array.
circles = [] for i in [0..3] circle = new Layer backgroundColor: "black" superLayer: backgroundLayer borderRadius: 100 width: 50 height: 50 blur: 20 name: "circle #{i}" circle.center() circles.push(circle)
Make the backgroundLayer layer for them as a parent layer. Since this layer has a different blending mode (screen) and its parent layer is the loadColor layer of blue color, the circles became blue, although we asked them to backgroundColor: “black”.
For example, if we write instead of “black” - “red”, they will turn pink.
We also made the circles blurred (blur: 20) so that they flow seamlessly into one another.

But then the question arises how to make them flow one into another, but at the same time do not look blurry.
Everything is solved simply. We return above to the place where the backgroundLayer layer was described and add another line - we set a strong contrast:
backgroundLayer = new BackgroundLayer backgroundColor: "#fff" style: mixBlendMode : "screen" superLayer: loadColor contrast: 10000
Now, the circle looks like a circle, not a blur.

Make the circles move. To do this, create an animation.
They will be 2 - for the first and second round, and the circle 0 and 3 do not move.
load1 = new Animation layer: circles[1] properties: x: circles[0].x - 180 time: .7 curve: "easy" load2 = new Animation layer: circles[2] properties: x: circles[0].x - 90 time: .7 curve: "easy"
Here, the first circle (circles [1]) is moved away from the zero circle by 180 px in the x coordinate - x: circles [0] .x - 180. The second circle, respectively, by 90 px.
We have created a movement in one direction - to the left, now we will create the same movement to the right.
load11 = new Animation layer: circles[1] properties: x: circles[0].x + 180 time: .7 curve: "easy" load22 = new Animation layer: circles[2] properties: x: circles[0].x + 90 time: .7 curve: "easy"
We return to our event - click on the “Sign In” button and add our new animations there:
Button.on Events.Click, -> Button.states.switch("Pressed", time: .4, curve: "easy out") Password.states.switch("Pressed", time: .4, curve: "easy") Login.states.switch("Pressed", time: .4, curve: "easy") signInBackground.states.switch("Pressed", time: 1, curve: "easy out") load1.start() Utils.delay .1, -> load2.start() Utils.delay .1, -> load2.on Events.AnimationEnd, -> load11.start() Utils.delay .1, -> load22.start() Utils.delay .1, ->
As you can see, between each movement of the circles, we give a delay of 0.1 seconds (Utils.delay .1). The movement to the right side occurs after the movement to the left side ends. Therefore, we wrote load2.on Events.AnimationEnd, -> ... .., which means -
when load2 ends, load11 and load22 begin.
To make the animation last forever, we close the loop by appending below:
load22.on Events.AnimationEnd, -> load1.start() Utils.delay .1, -> load2.start() Utils.delay .1, ->
The second screen is ready.
We proceed to screen 3 with a greeting and color change.
Create an animation for circle 0, in which it will expand to full screen:
big = new Animation layer: circles[0] properties: borderRadius: 0 width: backgroundLayer.width height: backgroundLayer.height y:0 x: 0 blur: 0 curve: "spring(300, 30, 0)"
Now, we add the start of this animation below in the event of clicking on the button, making a delay of 2 before it:
Utils.delay 2, -> big.start()
Draw an invisible TextFinish layer, which is the word “Hello!”:
TextFinish = new Layer backgroundColor: null width: 640 y: 300 opacity: 0 html: "Hello!" color: "#fff" TextFinish.centerX() TextFinish.style.fontSize = "148px" TextFinish.style.fontFamily = "Proxima Nova" TextFinish.style.textAlign = "center" TextFinish.style.lineHeight = "154px"
Add to it 3 states (one in which it becomes visible, and 2 others, where the word Hello changes to Hello and White):
TextFinish.states.add activate: opacity:1 nactivate: html: "!" oactivate: html: "Ń–!" TextFinish.states.animationOptions = time: .6, curve: "easy out"
We add the change of states of the TextFinish layer to the event of clicking on the button. Now the whole event looks like this:
Button.on Events.Click, -> Button.states.switch("Pressed", time: .4, curve: "easy out") Password.states.switch("Pressed", time: .4, curve: "easy") Login.states.switch("Pressed", time: .4, curve: "easy") signInBackground.states.switch("Pressed", time: 1, curve: "easy out") load1.start() Utils.delay .1, -> load2.start() Utils.delay .1, -> load2.on Events.AnimationEnd, -> load11.start() Utils.delay .1, -> load22.start() Utils.delay .1, -> load22.on Events.AnimationEnd, -> load1.start() Utils.delay .1, -> load2.start() Utils.delay .1, -> Utils.delay 2, -> big.start() TextFinish.states.next()
It lacks only one, the last line - changing the background color. To add it, we add two states to the loadColor layer:
loadColor.states.add active: backgroundColor: "#f87b36" nactivate: backgroundColor: "#fa635f" loadColor.states.animationOptions = time: .6, curve: "easy"
And append to the event:
loadColor.states.next()
Done!
I hope that my story has shed light on what cool things every designer can create thanks to Framer. I am pleased to listen to your thoughts about Framer, and in general, how do you think - is it time for us to designers to start coding?
I’m finishing with this, but I will continue to write articles on useful materials on designer prototyping - programming.