From figma to p5.js

Geert Roumen
10 min readSep 18, 2021

--

Prototyping interactive apps beyond UX flows

Visual overview of the article. On the left; the Figma logo (colourful F), with an isometric exploded view of the Figma (and thus SVG) file structure with a hearth in the middle. On the right the p5.js logo (red star) with code snippets underneath. (as explained in the article below).
This overview shows an isometric overview of the SVG structure of the file created in Figma, which is then being controlled by code in P5.

— If you don't like reading, and just want to start hacking; take this P5.js sketch, import your own Figma frames into it and edit the first line…

Sometimes you need more elaborate prototypes than the simple UX flows you can create in Figma. Creating animations and transitions in Figma is great, but when you need to deal with multiple states, variables, sound or connect your prototype to other services and devices you might need to start writing some code.

This article will describe how you could go from screen-based prototyping tools like Figma into more programming based prototyping tools like P5.js. This is not a manual on how to move from Figma to production code, but more a hacky approach from an interaction designer to prototype some experiences relatively fast. The benefits of using P5.js is that you can use all the features of the web, such as connecting to Arduino's, Bluetooth devices, Using sound, Communicating between devices but also simple things, like having a working slider that can influence something else on the screen, which we will explore in this example.

Tools like FramerX have been around, which try to combine code and design but sometimes it is easier to do a more quick-and-dirty prototype using this P5.js approach.

First, it might be good to understand what we are talking about. If Figma, SVG, P5 and javaScript are known concepts for you, feel free to skip this. The idea is that we will export an SVG file from Figma and use it in a P5.js sketch to make it interactive. You could potentially export SVG files with different software, such as Adobe xD, Sketch or Illustrator, but for the sake of simplicity, we keep it to Figma for now.

What is Figma?

Figma is a vector graphics editor and prototyping tool which is primarily web-based, with additional offline features enabled by desktop applications for macOS and Windows. The Figma Mirror companion apps for Android and iOS allow viewing Figma prototypes in real-time on mobile devices. The feature set of Figma focuses on use in user interface and user experience design, with an emphasis on real-time collaboration. — From wikipedia

What is SVG?

Scalable Vector Graphics (SVG) is an (XML)-based vector image format for two-dimensional graphics with support for interactivity and animation. The SVG specification is an open standard developed by the World Wide Web Consortium (W3C) since 1999. — From Wikipedia

What is P5.js?

p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else! p5.js is free and open-source because we believe software, and the tools to learn it, should be accessible to everyone. — From p5js.org

Why?

It’s good to ask the question why, especially since moving from Figma to P5.js will take time (and if working on commercial projects, money and resources could sometimes be spent better on testing and creating lower-fidelity prototypes. It is always good to consider doing that first, especially if it’s more about the holistic concept than the micro-interactions. However, if you want to know if certain interactions make sense, or if the concept is highly dependent on things that are currently not possible in Figma to prototypes like sound or the use of specific API’s then prototyping in P5.js might be the solution.

This technique was used to create these short videos where the concept was explained using P5.js sketches that contain Figma frames that are connected to physical hardware.

How?

For this article I will use an example screen from my thesis, the code for this example can be found here, to make changes and upload files, you will have to duplicate it. During my thesis, I had a frame in Figma that I would like to make more interactive, for the purpose of video prototyping and testing the concept. For this reason, it can sometimes make sense to first prototype and test as much in Figma, until you feel that this tool can’t be used for testing, or communicating the concept anymore since it is lacking interactive features.

Scale & proportions

For me, the best way was to create a workflow in P5.js that will display (almost) exactly the same as if I would be running Figma Mirror on the phone, by using this workflow I can prototype proportions and UI in Figma mirror first, and then move to P5.js whenever more complicated interactions get involved.

On the left side an interface with a slider that is moving, the value on the left top says "voltage" and is being influenced by the slider on the screen. On the right side, there is a Figma mirror screen.
On the left side, the P5.js sketch, on the right side is the Figma mirror sketch. If the fonts and rendering techniques are similar it should show similar results. (In this case, the exact font rendering of Roboto is slightly different P5.js sketch for this can be found here https://editor.p5js.org/lemio/sketches/XOgQWPYyL and the Figma file here: https://www.figma.com/community/file/1021106422783281837/Figma-to-P5-workflow

Interactivity

The reason that you want to move from Sketch to P5.js is to allow interactive elements to be edited by the code. For this it is best to export the screen from Figma as SVG and Include “id” attribute, don’t select outline text (unless all text is static) and don’t select Contents Only since you might need hidden elements at some point.

A closeup of the Figma interface where the "include ID attribute" is selected

How to include the Figma frame in P5.js

After you exported the Figma Frame (as described above) you now need to include the Figma frame in P5.js. For this, you need to create an account within P5.js (which allows you to upload files to the web editor) or run P5.js locally. Personally, I like the sharability of the P5.js web editor since I can easily send it to smartphones. To upload files into P5.js simply click the arrow above the file explorer and select upload file

An animated overview of how to upload files to the p5.js web editor
An animated overview of how to upload files to the p5.js web editor

Once uploaded the file should appear under the sketch files, now you can change the first line of code from our example in sketch.js to contain your Figma frame. When running the sketch, by pressing the play button, it should already show up on the preview window of P5.js

Errors

When you just insert your own Figma file into it, you will most likely get some errors, since you don't have the same elements defined (and named the same way) as in my example.
You will most likely get the error: TypeError: Cannot read property ‘mouseMoved’ of null this is since the sliderActiveArea is not defined yet.

TypeError: Cannot read property ‘documentElement’ of null at /figma.js:9:25
If you get this error; this probably means that you wrote the name of the SVG file wrong in the first line in sketch.js. Please check that the names are exactly the same including the .svg at the end.

Text alignment

Be aware that the aligning and other data that might help to make the text dynamic might be lost. It creates left top alignment, so if you want to centre text you need to play a bit with the SVG file to make sure it looks the way you want it to look. If the text is static or is aligned left top you don't have to worry about it.

How to control text and fonts

In Figma, you might use fonts that aren't available on the devices that you want to use the P5.js sketch on, if the text is interactive this means that you need to include the font in the P5.js sketch. If the text is not interactive you can rasterize (perhaps with a higher resolution than 16 px/em) or Outline the text to make sure you have exactly the same preview on the browser as in Figma.

If you use Google web fonts, like Roboto in this example, you can include them using this approach

To change the content of a Figma text element, use the ID that is assigned to it, get the element's first child and change its innerHTML. This is because Figma always creates a tspan within a text element in SVG. The code below is used to select the element that contains 2.5V below.

select("#voltageText tspan").html("Put your dynamic text here")

This is the SVG that Figma outputs:

<text id=”voltageText” 
fill=”#999999"
xml:space=”preserve”
style=”white-space: pre”
font-family=”Roboto”
font-size=”30"
font-weight=”500"
letter-spacing=”0em”>
<tspan x=”30" y=”60.7539">
2.5V
</tspan>
</text>

Make a slider work

In our example, we would like to have a slider that influences dynamic content somewhere else in the Figma Frame. To do this we need to do the following steps. As shown and explained in the example code.

  • Couple a function to all the mouse/finger interactions possible.
select("#sliderActiveArea").mouseMoved(controlSlider)
select("#sliderActiveArea").mousePressed(controlSlider)
select("#sliderActiveArea").touchMoved(controlSlider)
select("#sliderActiveArea").touchStarted(controlSlider)
  • Check if the mouse/finger is actually pressed/touching the screen (P5.js build in mouseIsPressed)
if (mouseIsPressed) {
//put code in here
}
  • Figure out where this is on the screen (P5.js build in: mouseX and mouseY)
const pt = svg.createSVGPoint();
//Get the x and y of the mouse/finger
pt.x = mouseX
pt.y = mouseY
  • Map this position to the position on the SVG/Figma frame (This was most tricky, but I found a nice explanation here)
svgP = pt.matrixTransform(svg.getScreenCTM().inverse());
  • Define the x position that the slider needs to go to. Since the x coordinate is the most left corner of the slider we move it half of its width more to the left. So the touchpoint will be in the centre.
var x = svgP.x — select(“#SliderHandle”).attribute(“width”) / 2;
select("#SliderHandle").attribute("x", x)
  • Get the edges of the active area, and map the value in relation to that.
//Get the full range of where the slider could go (slider_active_area), this is a transparent rectangle
var min_x = select("#sliderActiveArea").attribute("x");
var max_x = Number(select("#sliderActiveArea").attribute("x")) + Number(select("#sliderActiveArea").attribute("width"))
  • Map this value to another range (in our case voltage) and display this in the left top corner. (P5.js build in map(val,min,max,min,max))
select("#voltageText tspan").html(round(map(svgP.x, min_x, max_x, 0, 50)) / 10 + "V");

Make a button work

Just because it might be useful to see, to make a button work and in this case change the colour of an element.

In the setup add:

select(“#ChooseButton”).mousePressed(chooseButtonPressed)

Then to change the fill colour of the slider (now light grey, defined as a hexadecimal code

function chooseButtonPressed(){
select("#SliderHandle").attribute("fill", "#999999")
}

The sky is the limit, but you might need some more research to figure out how to do it. Mozilla has a great overview of all the attributes that SVG elements can have, to learn more about p5 and how to code interactive experiences for it the coding train is a great place to go. In general, if you want to make something work it is good to Google your idea with "JavaScript", "js" or "P5" since P5.js is just a javaScript library, you can often just copy and paste javascript code into P5.js

How is this working?

Figma logo with Figma text underneath -> Svg logo with SVG text underneath-> Js logo with figma.js text underneath-> P5.js logo with P5.js text underneath.

This sketch is working since there is a figma.js file that opens the SVG file and 'drops' it in the HTML frame of the P5.js sketch. Another option is to copy-paste the text of the SVG file into the P5.js sketch's HTML file called index.html. but by using this figma.js file I found it easier to make changes and just replace the Figma file.

Disable 'normal' behaviour

Besides just dropping the Figma SVG file into the HTML frame, this sketch also has some additional headers and styles to make it look like the Figma Mirror preview. Since you want it to feel like a native app and not a browser, you should disable what is considered normal behaviour (I did this for you if you duplicated the example), such as double-tapping to zoom and swiping to scroll.

The code below should be added to the header to disable tapping to zoom

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

The code below helps the page to be filling the screen and not scroll.

html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: fixed;
}

This code avoids text selection, which for this slider example is nice.

*{
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+/Edge */
user-select: none; /* Standard */
}

FullScreen Browser App

To really mimick the experience of the Figma mirror app, or trick the users into thinking that it is a real app, product or service, there are different paths to getting a webpage, shown full screen on a phone. There are various fullscreen apps, and you might also be able to use a fullscreen function within Chrome.

A good thing to know is that you can use the embed function of the P5.js web editor to run your sketch without it being in an iframe with P5 branding around it.

Using the embed link you have a 'pure' version of your p5 sketch, without any distractions or injected code

Let me know if this was of any help, what you build with it and what we could improve to make prototyping quicker, so we can make better products.

--

--