How to make Framer prototypes talk to each other
Take your prototypes to the next level with this tutorial for Framer Classic and Framer X
Editor’s note: We’ve made some big changes to Framer, and this article refers to deprecated tools. Learn more about what Framer is today →
Imagine having a great idea for a chat application that you’d like to explore further. You come up with fantastic, interactive features and start writing down cool ideas on post-its. Eventually, you get to the point where you desperately want to start fleshing out some basic wireframes. And suddenly the wireframes turn into high-def mockups. All of it looks amazing. Since you have some experience with Framer, you start building an interactive prototype that really gives a feeling of your potential product. All interaction patterns are flawless and it has lots of smart UI animations and nice visual touches.
You have a working flow of the “Group Conversation” feature that you hold so dearly. You can type messages and send them to conversations. You get some mocked responses and it all seems ready to be built into an actual app that runs on your phone. But you feel that something is missing. The following thought pops into your head:
It would be so valuable if I could put this prototype in the hands of people and have them chat with each other. That could generate important & valuable feedback on the user experience.
In this series, I want to show designers who build awesome prototypes with Framer that they can empower prototypes by thinking a bit outside the box with little effort. This time, I will demonstrate how you can approach communication between Framer prototypes using a Chat prototype as an example. We will implement broadcasting of chat messages to all Framer prototypes that are listening. And believe me, it’s super easy to build. This article will include examples for both Framer Classic and Framer X.
Approaching our problem
If we want to build a prototype of a chat application, we need a way to communicate with other users. Let’s define users as people that use an instance of your prototype. If someone writes a message to a group conversation, it needs to be broadcasted to all other users. The big problem is that Framer prototypes can’t just magically discover other nearby prototypes and send messages to them. What we need is a single intermediary point that all prototypes are connected to.
The best way to describe this intermediary entity would be a “server.” We need to make sure that all prototypes connect to a “chat server” in order to send and receive messages.
We’ll write a super simple chat server with just a few lines of code, using Node. Node is a JavaScript runtime which in short enables us to write server code using JavaScript, which is perfect for this use case. If you don’t have it already, download and install Node here.
Let’s begin!
Create a folder somewhere on your computer and name it something appropriate. It will contain a few files in order to run our chat server. Open up a terminal window and navigate to the folder you just created.
Run the following 2 commands:
npm init -y
npm install ws -s
It will simply create a package.json file which will have some basic information about our project and install a package called “ws” that will help us set up a WebSocket server. More on what that means in a moment.
Now, time for some coding! Create a new file called server.js. This will in fact be the only file that you need to care about. And it won’t be much code either.
30 lines of code, not much more than that! Let’s walk through it all line by line.
- First, we import the necessary modules that we need to run this chat server.
- On line 6 we create an http server that will be used by our WebSocket server on line 9. You may be wondering what WebSockets are. WebSockets give us persistent connections between the client and the server, apart from regular HTTP requests that end with a response from the server. WebSockets enable us to sit and wait for messages and receive them with little to no latency, which is super good for our chat feature.
- Line 12 to 28 registers some listeners for events that occur on the WebSocket server. That’s where the magic happens. Messages come in and are distributed to other users/prototypes that have an open WebSocket connection.
- And lastly, we fire up our server and log some useful information in the console. Simple as that!
Executing the following command in the terminal will start our chat server:
node server.js
You should now see “Chat server now running on http://localhost:8081” being printed out in the terminal. We have just written a small server that broadcasts incoming messages to all other users, just like a “Group Conversation” feature would do.
All we have to do now is write some code in our Framer prototypes to use this server for chat communication. I have examples for both Framer Classic and Framer X, which I thought could be helpful for some of you.
Framer X
Follow this example if you use Framer X. Get started by creating a new Code Component, and paste the code below.
Okay, this might look a bit complicated, but I can assure you that it is not! Let’s go through it line by line and break down what we are doing here.
- First off, we import React as we usually do in Framer X.
- On line 3 to 14, we are just defining some types. We declare an interface called Payload that describes the data structure delivered by the chat server.
- Now to our component. We declare our Chat component and make sure that we extend the React.Component class.
- Line 18 to 21 might look a bit unfamiliar. We’re instancing a connection to our WebSocket-based chat server.
Important: Make sure to replace “localhost” on line 18 with the IP address of the computer that runs the chat server. This is important because when people run your prototype on their phones, the connection attempt will fail because “localhost” will point to their phones instead of your computer. - On line 19 we declare a state for our chat that eventually will hold all messages received by the server. If you don’t know what states are in React, read more about them here.
- Next, in the componentWillMount function, we’re setting up some event handlers on our WebSocket connection. The ws.onmessage will trigger when we get a message from the server, so we’re calling a _renderMessage function that we define later in the code.
What’s worth mentioning here is that as soon we send our message to the server, we won’t receive it in the ws.onmessage. Why? Well, if you remember the code we wrote for the server, we explicitly made sure to not send the message back to where it came from. This makes sense because we can just create a new TextLayer with that same chat message before sending it to the server & everyone else.
componentWillUnmount will make sure to close our connection to the chat server when the Chat component un-mounts. - _renderMessage is the function that renders the messages to the screen. It simply updates the state with the new message that will propagate down to the render function that will immediately re-render the messages.
- To send messages, you can use the _sendMessage-function. It is not hooked up to any UI in this example, but you can use it yourself by binding it to some button or whatever.
Framer Classic
Follow this example if you use Framer Classic. Switch over to the Code tab and paste the code below.
- We start off by instancing a connection to our WebSocket-based chat server.
Important: Make sure to replace “localhost” on line 2 with the IP address of the computer that runs the chat server. This is important because when people run your prototype on their phones, the connection attempt will fail because “localhost” will point to their phones instead of your computer. - We’re creating an array that will hold all messages on line 4.
- After that, we set up some functions on the WebSocket instance that will trigger depending on what happens. ws.onopen will trigger when our connection to the server is established. ws.onclose will trigger when we disconnect. And lastly, ws.onmessage will trigger when we get a message from the server. This is where we create a new TextLayer with the chat message as text, resulting in a new TextLayer every time a new chat message pops in. We also push the new message payload into our message array so we can offset each new message with a margin multiplied by the amount of messages received (see line 26).
- On line 41 we basically just create a button that we can press to simulate a message being sent to the server. You should probably add an input field so you can type some text instead and send that to the server.
What’s worth mentioning here is that as soon as we send our message to the server, we won’t receive it in the ws.onmessage. Why? Well, if you remember the code we wrote for the server, we explicitly made sure to not send the message back to where it came from. This makes sense because we can just create a new TextLayer with that same chat message before sending it to the server and everyone else.
That’s it! We just wrote a chat server that broadcasts incoming messages to other connected clients. We also wrote some code for our prototypes that receives and renders the payloads sent. You can of course modify the payloads and add usernames and user image urls along with the messages so the prototype is a bit more fancy.
You should now be able to boot up prototypes on phones or computers (as long as they are connected to the same WiFi as your computer that runs the Chat Server) and have Group conversations. As I mentioned in the guides above, it’s important that you replace “localhost” with the computer’s local IP address, otherwise this won’t work.
We’re of course not limited to just use this chat server for chat prototypes. You can use it for anything that requires fast, reliable communication between prototypes. And also, as Node servers run on your computer (instead of your browser), you could integrate connections to a database and other fancy backend-related services. Be creative!
Please, if you find bugs or concepts that I didn’t explain thoroughly enough, drop me a mention on Twitter and I’ll help out immediately. Thanks for reading this through and I hope to see you again in the next article in this series. ‘Til then — happy hacking!