Making Framer prototypes can communicate what a final product will feel like early in the design process. I find working with Framer rewarding because it forces me to think through the logic and flow of a design in a very tangible way.
Building a prototype also helps me gain empathy for some of what engineers will go through when building the product. If it’s difficult to figure out the interactions in Framer, there is probably some sort of fundamental flaw or ambiguity in the design.
I make a lot of prototypes and they tend to be long flows with many different states. I have developed a pretty rapid system for converting a design into a robust prototype by anticipating issues that usually occur later in the process. I decided to write my process down as a way of how you can handle a prototype workflow with Framer. I claim, over the course of time, it makes the process really fast.
Step 1: Static Design
As an example we are going to make a swipe-able stack of cards that you’ve seen in apps like Moments and Tinder. The cards can be favorited or dismissed. Any card can be opened to a list view of content.
The static design process should be the really familiar part. Think through the states the experience can take and map them out in Sketch. Once you feel you’ve got a good grasp of the spectrum of possibilities you will be ready to move forward.
Side note: Framer now supports importing from 1x resolution. Design in 1x and it’ll make your life easier when creating the spec for engineers later on.
Step 2: Write Plain Text Logic
This is the magic step. The one that saves me the most time and prevents me from going back and forth figuring stuff out in a non-productive way later on.
In plain text, write out everything the prototype should do.
Try to write out all actions the person using the prototype will take and the results they will see. A lot of flows tend to have a somewhat linear timeline, so write out the ideal state of what will happen. You will deal with the edge cases later.
This plain text logic will end up creating pseudo-code. It will also inform how you will build the Sketch file you are going to import into Framer in the next step. Building a really coherent import file will save you a lot of time.
Here’s what the plain text logic looks like for our example:
- Tap icon to open app to main view
- Cards load in
- Swiping card left marks complete
- Swiping card right marks favorite
- Tap open button on any card to expand
- List view appears for active card
- Tap exit to close list view
- On last card, show completion animation
- Tap reload button to reload cards
Now go back through this flow and write out every time something is a user interaction or a resulting interface action:
- Tap icon (user action) to open app to main view (zoom animation) - Cards load in (loading animation) - Swiping card left (user action) marks complete (checkmark animation) and loads remaining cards to new positions (animation) - Swiping card right (user action) marks favorite (star animation) and loads remaining cards to new positions (animation) - Tap open button (user action) on any card to expand (card to full screen animation) - List view appears for active card (list items scale and exit button appears) - Tap exit button (user action) to close list view (list items and exit button scale away, full screen scales to card) - On last card swipe (user action), show completion animation (scale in completion animation) - Tap reload button (user action) to reload cards (loading animation)
It’s important to both recognize everything that is a visual change to the view as well as what triggers it. The user actions will be your action events and the interface actions will be the resulting animations. Try to figure them all out now so you can identify and build reusable ones when possible. If you can nail down what you want here, everything else should be a breeze.
Step 3: Compile Your Framer Import Sketch File
In this step, we take the original Sketch file with the states of the experience and convert it to a new file we will use to import into Framer.
I tend to layer the states of the experience based on how they appear in the visual hierarchy. This helps me avoid using placeBefore or placeBehind as much as possible in the final code which I find makes debugging slower and more confusing. I place most layers in the spot they will reside in when active in the view and then move them out of the view when I set up the Framer project.
I try to be concise and accurate in my naming scheme, generally using the same names from my plain text logic, removing spaces and writing them as camelCase instead. I choose names which are obvious but specific so I don’t have to refer back and forth to the Sketch document. The names should always describe the purpose of the element. For example, you might only have one button, that reloads the view, but name it ‘reloadButton’ instead of ‘button’. This makes it easier to avoid confusion later on if you decide to add other buttons.
Be sure to remove any layers from the Sketch file which aren’t going to appear in the prototype. This makes hunting for specific groups easier and increases the chance your prototype will be really performant. Sometimes I flatten all elements that don’t need to be manipulated at the very end of a project for even better performance, but I generally avoid doing it earlier in the process for maximum flexibility.
Step 4: Import and Reuse
Okay, now the fun part. Import the Sketch file into Framer at the proper device resolution. Set up any layers which have special interaction properties, i.e. draggable, scrollable, etc. Set the initial positions of the layers which aren’t in the view, set up any scaling, etc. Basically you want to get the project into its initial state you’d like it to start in.
Here’s a truncated example of how I lay this out (check out the prototype for more):
# define initial positions app.appView.scale = 0 app.appView.originX = 0.361
# define draggables and scrollables app.card1.draggable = true app.card2.draggable = false app.card3.draggable = false
scroll = ScrollComponent.wrap(app.cells) scroll.scrollHorizontal = false
# define springs cardLift = “spring(160,40,10)” cardPull = “spring(200,26,10)”
# define animations cardExitLeft = (layer) -> layer.animate properties: x: -750 curve: cardPull
# define conditionals currentCard = 1
Now take the first user action from the pseudo-code and write the real Framer code. Work your way down the list. There will be a bit of back and forth in this step as you experiment and see how things look and feel. Don’t be afraid to adjust and re-save layers in your Sketch file. If you’ve done this right, it will be easy to track the changes in Framer.
I often refer back to the Sketch file for position and size of the elements.Often I’ll be making a prototype in 2X resolution from the Sketch file, so I try not to forget to double the values.
Step 5: Adjust Until You Reach Desired State
Just tweak the thing. If you have some reusable springs and animations, it should be really easy to change stuff around. Try different feels. Edit the Sketch file and reimport as necessary. You might discover something new that inspires you to make changes.
The greatest pleasure I get from prototyping is this step. I feel Framer and Sketch play so well together at this point and I love going back and forth between them to get the prototype to feel exactly as it should.
I usually record my prototypes ideal flow with an app called Screenflick. I like it because it lets me control both the screen resolution when recording as well as the output resolution when exporting. It lets me control which of my user interactions the viewer sees. I also find the prototypes stay more performant than when I use Quicktime to do the recording.
For many presentations, I put the prototype on device and record the interactions with a camera. I tend to use Frames or Frameless. I like Frames ability to store the prototypes locally on the device without an internet connection. That comes in useful when randomly showing off the prototypes throughout the day.
A Few More Tips
If I have video layers, I generally set up a ‘holder’ layer group for where the video will go in the prototype which is a dummy static layer that should look like the video. This helps for two reasons, I can refer to the Sketch file for positioning and size, and when I inject the real video file into hierarchy, I can simply place it right above the holder layer to manipulate it.
Set Up Snippets
Over the course of time you end up developing a style with Framer that works well for you. The best thing you can do to be faster is record those tricks as snippets so you have them readily available. Before you know it, you will be making prototypes in no time at all because you will barely be writing any code, just pulling stuff together and tweaking from logic that works for you and your system.
Here’s my favorite snippet, it lets me slow down the animations so I can fine tune them:
// Slow down animations Framer.Loop.delta = 1 / 240
I hope these thoughts help you think about how you can be more deliberate in the decisions of your workflow to avoid churn later on in the process. Every time you write a Framer prototype, it’ll be half as hard next time. So stick with it, it’s worth it.
If you ever want to talk more about Framer or Sketch or related stuff feel free to get in touch via Facebook or Twitter. Also check out the Framer JS group on Facebook, there is always a ton of great Framer conversation going on there. Thanks for reading!
Download the prototype and Sketch files on GitHub.