Introduction
tl;dr - if you’d like to play with the final result you can find the file on Figma community here. If you’d like to dig into how it works, read on…
This idea stemmed from a recent project where part of the experience involved simulating a fixed time period for group participants to complete an exercise. It made me wonder: could I create a fully functional countdown timer prototype using only Figma variables and component variants? Some of the key things I wanted to achieve:
- It had to look like a 7 segment digital display
- I wanted to be able to count down from any initial value (even quite long times)
- The timer controls should be able to pause and restart the timer
- (Bonus goal) It would be nice to add an extra minute on while the timer was running.
The 7 segment display
At the most basic level there’s a ‘number’ component which provides all the digits 0 to 9. Finding a good open-source 7-segment font was something of a challenge - and I ended up using DSEG. Using a component with variants for each digit actually makes the challenge harder - but nothing on Google Fonts was quite right.
The timer
The timer component has four instances of the number component wrapped up in a single block. Each digit is attached to the output of a variable - Minutes - Tens
Minutes - Units
Seconds - Tens
and Seconds - Units
, so as the timer counts down those values are reflected in the display.
In Figma variables there’s actually two sets of time variables - Minutes - Tens
etc. are the ones that are updated as the timer counts down. The other set of variables are used to reset the timer to a known starting point - so that once you hit stop and start again the timer will count down from the same value. The main time variables are then an alias of the reset values.
Making the timer run
Creating the logic of the timer was actually much trickier that expected (for reasons we’ll come on to) - but the basic concept is quite simple. There’s 4 variants of timer component:
- Two variants called “Tick” and “Tock” - every second we’re flipping back and forth between those two states, and executing some logic to figure out what the new time should be.
- A variant to represent the play state - “Playing” and “Paused”
The decrement logic
The logic for decrementing the time looks like this:
-
If all the time variables are zero, then the time has run out - so we can switch to the final “Finished” artboard to play the chime before resetting the timer.
-
If the time is something like 20:00 where
Minutes - Tens
hasn’t yet reached zero, but everything else is currently zero then decrement that number and set the other digits to 9, 5, and 9 respectively. -
If the time is something like 09:00 where there’s still
Minutes - Units
left but both seconds variables are zero (we don’t care aboutMinutes - Tens
in this test), then decrement that number and set the seconds to 5 and 9 respectively. -
If the number
Seconds - Units
is zero, but there’s stillSeconds - Tens
left (by this time we don’t care aboutMinutes - Tens
orMinutes - Units
) then decrement theSeconds - Tens
and setSeconds - Units
to 9. -
Finally, we’ll decrement
Seconds - Units
by 1 if there’s nothing else to do.
You’ll notice that in each step there’s a Changed
variable which is reset at the beginning of each cycle. I’d originally hoped that adding a “change to” within each logic step would allow me to bypass the other rules in the set - but Figma will evaluate all actions regardless. Figma also doesn’t currently allow for nested if / else logic, and we want to make sure that the final step (decrement the Seconds - Units
) only runs if nothing else has been changed this round - so adding a boolean to store the Changed
state is a cheeky hack around that.
The other bit of secret sauce is the Play State
variable. When I was trying to introduce the play / pause controls I’d originally planned to switch the variant of the Timer component over to the “Paused” variant to stop the timer, however one of the hazards of using “After delay” interactions in Figma is that once a delay timeout has been set, it’ll still execute those instructions regardless of whether the component variant has been changed in the meantime. Adding a “is the timer still running?” test to each decrement check allows you to wrest control of the timer back from those timeouts when one of the control buttons is pressed.
Wrapping it all up
The pause and stop buttons essentially do the same thing; the only difference being that stop resets the current minutes and seconds values back to the reset values.
The final polish is the finish chime - created by embedding a sound effect into a black screen video tucked into the “Finished” artboard.
Final thoughts
It’s a bit of fun - and it’s exciting to see some of the things you can achieve with a bit of creative deployment of Figma variables.
The perfectionist in me would also like to have achieved this prototype with a single artboard (by binding the state of the timer to a variable and then just modifying that variable to start it playing) however the binding of that play / paused state seems to prevent the “On delay” interactions from firing on the other property… maybe something for another day.