← Manas Vaze
December 2017 · originally published in Framer's Medium publication

Making Framer Prototypes Talk To Each Other

A step-by-step tutorial for easily prototyping interactive TV + remote prototypes in Framer.

Minimal still life of a leaf on a table
Original photo by Sarah Dorweiler

This piece was written for Framer Classic, the CoffeeScript-based tool, which has since been deprecated. The WebSockets approach still holds; the Framer specifics are of their time.

Framer has quickly become my main go-to tool for prototyping ideas, interactions and animations for my design work.

As a designer who stayed away from code, I felt that Framer does have a bit of a steep learning curve and I did drop off it a couple of times. But now I see the possibilities of what a designer can do once they are comfortable with it. It has also taught me different ways of approaching problems, thinking about the implementation as a part of the design process.

In this particular post, we are going to look at how to make two Framer prototypes talk to each other.

What's the need for prototypes to talk to each other?
If you are working on a product or company that has a set of apps and devices that form an ecosystem, it's very important to know the interaction model and possibilities occurring between these devices and apps.

Think Google or Amazon, with a range of devices and apps that usually work together and form an ecosystem. The continuity and seamless interaction between these devices forms the crux of the user experience.

the setup

To begin, let's have a look at all the elements that will be used in making the prototypes work and talk with each other. The setup consists of 3 main parts:

  1. The Smart TV
  2. The Remote Control
  3. Server

Apart from the basics in Framer, we will be making use of WebSockets: an advanced technology that makes it possible to open an interactive communication session between the user's browser and a server.

Diagram of the TV, remote and server setup

1. the smart tv

This prototype will behave as the TV. The primary job of this prototype is to listen to swipe gestures and handle the UI navigation accordingly.

Let's begin by creating some app icons that can appear on the TV home screen.

# Create app icons and build the TV UI in a container layer
container = new Layer
	width: Screen.width
	height: Screen.height
	backgroundColor: "EAEAEA"

container.center()

# An array to hold all the app icons of the TV
icons = []

# Create app icons of the TV in a loop and push them onto the array
for i in [0...5]
	icon = new Layer
		width: 200
		height: 200
		x: (280 * i) + 60
		y: 60
		borderRadius: 6
		backgroundColor: Utils.randomColor()
		parent: container
	icons.push(icon)

Use the devices dropdown to enable the TV device in the Framer preview window. Once you write the above code, your result should look something like this:

Smart TV prototype in Framer preview mode
Smart TV prototype, preview mode in Framer

Now, let's create the focus and hover interaction that we usually find in most smart TV UIs these days. For this, we are going to make use of a Framer module rather than write the complete logic by ourselves. Think of modules as a library of code that we can import into our prototypes to automate certain tasks, like handling the UI focus interaction in our case.

We'll use the Focus Engine module by blackpixel. Copy the FocusEngine.coffee file and paste it in the '/modules' folder of your project. Next, we need to add the following line of code in Framer to include this module.

# Command to include the FocusEngine module in our TV prototype
fe = require "FocusEngine"

Now that we have imported the module into our prototype, it needs to be fed with the app icon layers we created earlier to make them interactive.

# Initialize the focus engine with the app icons. All the layers that
# can be controlled with the remote need to be fed into the focus engine
fe.initialize(icons)

# Set the first icon to be on focus at the beginning
fe.placeFocus(icons[0])

Once the FocusEngine is initialised, you should be able to see the first layer on focus, like this:

First app icon highlighted by the focus engine

Next, we add the following code into our TV prototype. What this does is listen to swipe gestures and change the focus accordingly.

ws.onmessage = (event) ->
	if event.data == "left"
		fe.changeFocus("left")
	else if event.data == "right"
		fe.changeFocus("right")
	else if event.data == "up"
		fe.changeFocus("up")
	else if event.data == "down"
		fe.changeFocus("down")

Our TV prototype set-up is done.

2. the remote control

This prototype will be the remote control to the TV. Its main job is to enable a touch surface that will act as a remote control and pass the swipe gestures to the TV.

Create another Framer project and name it "remote-control". In this prototype we will be using the RemoteLayer module to create an Apple TV remote touch surface that can be used to send gestures to the smart TV prototype. This module handles the swipe gestures automatically for us.

Copy the RemoteLayer.coffee file and paste it in the '/modules' folder of your TV remote Framer project. Next, we need to add the following line of code in Framer to include this module.

# Command to include the remote control module in our remote prototype
RemoteLayer = require "RemoteLayer"

Next, let's create a RemoteLayer instance and define some events and actions for when a user swipes on it.

# Create a remote control layer in a container layer and define the
# action it should do on swipes (left, right, up and down)
container = new Layer
	size: Screen.size
	backgroundColor: "EAEAEA"

myRemote = new RemoteLayer
	parent: container
	swipeUpAction: ->
		ws.send("up")
	swipeDownAction: ->
		ws.send("down")
	swipeLeftAction: ->
		ws.send("left")
	swipeRightAction: ->
		ws.send("right")

In brief, the lines ws.send("up/down/left/right") are sending the messages to the WebSocket server, based on the type of swipe. Once you do the above, your remote control prototype should look something like this:

Apple TV style remote control prototype
The module we are using creates an Apple TV remote object for us

3. server

Awesome! Now that we have both the smart TV and remote control prototypes set up, we will look into connecting the two.

For this, we shall host a Node server on our local machine. You can download the npm package here and install it by following the instructions.

Next, open the terminal, navigate to the TV prototype folder and type the following command. This will create a package.json file that the Node server will use.

npm init --yes
Terminal showing npm init output

Next, we need to install express in the same folder, along with a couple of other dependencies. For WebSockets we'll install the ws module as well as bufferutil and utf-8-validate. Only ws is necessary, but the other two provide a performance boost.

npm install --save --save-exact express
npm install --save --save-exact ws bufferutil utf-8-validate
Terminal showing dependency installation

Next, create a new file in the same folder and name it server.js, as shown below.

server.js file inside the project folder
server.js file to be created inside the remote control project folder

Now, open this file in your favourite text editor, paste the following code and save the file.

'use strict';

const express = require('express');
const SocketServer = require('ws').Server;
const path = require('path');

const PORT = process.env.PORT || 3000;
const INDEX = path.join(__dirname, 'index.html');

const server = express()
  .use((req, res) => res.sendFile(INDEX))
  .listen(PORT, () => console.log(`Listening on ${ PORT }`));

const wss = new SocketServer({ server });

wss.on('connection', (ws) => {
  console.log('Client connected');
  ws.on('close', () => console.log('Client disconnected'));
  ws.on('message', function incoming(data) {
    console.log(wss.clients.size);
    console.log(data);
    wss.clients.forEach((client) => {
      client.send(data);
    });
  });
});

In brief, the code here is creating a new Node/Express server and defining the path and other parameters for it. We also declare that we are hosting this locally and that the server shall listen on port 3000. Now, let's verify by running the server:

node server.js
Terminal confirming the server is listening on port 3000
Confirmation of the server running. It should say "Listening on 3000"

Congratulations! You have just set up a Node server locally and it's running fine. :)

The last step is to make the TV prototype listen to the remote control prototype. For this, we need to add some JavaScript in the index.html file of both the TV and remote control prototypes. Please note that this code has to go inside the <body> tags of the index.html file.

<script>
  var HOST = "ws://localhost:3000";
  var ws = new WebSocket(HOST);
  ws.onmessage = function (event) {};
</script>
index.html open in a text editor with the WebSocket script added
Open the index.html file in your favourite text editor and paste the above JavaScript in it

This JavaScript is creating WebSocket objects, and the function ws.onmessage() will send across the message, or swipe gestures in our case.

Hit refresh on both the TV and remote prototypes and you are ready to go! Our set of prototypes are connected and can start working together.

The TV and remote prototypes responding to each other in real time
Snapshot of both the TV and remote prototypes talking to each other :)

conclusion

I hope you found this tutorial helpful in creating prototypes that can communicate with each other. This also opens up new ways to think about interaction between apps and devices. Excited to see what the community builds using Framer and WebSockets.

You can download the prototype files from here.

· · ·

Special thanks to all the people on the Framer Slack channel that have helped me so far, including Sergey, Steve, nvh, Muhammad Athar and many more. This article was originally published in Framer's Medium publication in December 2017.

get in touch
Say hello