Referi
Semi-automated scoring for padel courts: a wristband to score, a display on court, an app for the stats.
- Role
- Flutter developer on both apps: the companion app from its first stats screens to the stores, and most of the court display's game screens
- Client
- Referi
- Period
- 2025 – today
- Platforms
- iOS and Android (companion app); a Linux kiosk by the court (display)


The product
Referi keeps the score of a padel match so the players don't have to. Each player wears a wristband: they tap it on the court's gate to join a match, then press it to score a point, hold it to take one back, double-press to pause. A display at the side of the court shows the score as it happens, and calls out every game, set and change of sides.
Every point is recorded, so the match lives on in the companion app: results, trends, rankings and the history of each match, for every player who paired a wristband. I work on both apps: the one in the players' pockets and the one on the court's screen.
- 75%
- of the companion app's commits are mine (85 of 113)
- 49%
- of the court display's (69 of 142)
- 24k
- lines of Dart across the two apps, excluding generated code
- 3
- gestures on the wristband: all it takes to keep the score
Walkthrough
The app, in motion
Pick a recording, or jump straight to a chapter.

Recorded from the current code: the court display at 1920 × 1080, with its own sound effects laid under the video; the companion app at phone size, silent. A virtual court plays the back end.
What it does
From a press on the wrist to the stats in your pocket
01
Tap in, choose who serves
Between matches the display plays the club's videos and explains the three gestures. Each player taps their wristband on the court's gate and takes a place in one of the two teams, with their name and avatar; a wristband that doesn't belong is turned away. The first server double-presses, and the match starts.
02
A score that keeps itself
Every press becomes a point for the presser's team, and the display follows padel's rules: fifteen, thirty, forty, deuce and advantage, games, sets, the tie-break, the server and the change of sides. Each event has its animation and its sound, and a double press pauses on a full scoreboard.
03
Game, set and match
The last point triggers the calls for game, set and match, then the final score with each player's points and the winning pair, with a reminder that the full statistics are in the app.
04
Sign-up and a wristband of your own
The companion app signs players in with their phone number and asks for a nickname and a photo, from which Referi makes the avatar the display will show. Pairing finds the player's wristband over Bluetooth and ties it to the account.
05
Every match, in numbers
The last match set by set, matches played by week, month and quarter, points and breaks won and lost, the points of each recent match, and rankings in the club, the city and the whole network. The history shows who a player wins with and who beats them, match by match.
Under the hood
How it was built
A display driven by messages
The court's back end publishes over MQTT what the display must show (a state, such as the live score) and what it must play (an effect, such as a point or a change of sides). Effects queue up and each holds the next messages back until its animation and sound have run, or its time is up; an interrupt flag lets an urgent message cut in. Clean architecture with flutter_bloc and injectable; media_kit for the sponsors' videos.
A kiosk that runs all day
The display runs full screen on a small Linux PC by the court, with no mouse and no one to restart it. Some of my work there is invisible: finding why videos came up as a blue screen on the kiosk's graphics chip (hardware decoding, the renderer), and why score updates could lag behind the wristband press.
The companion app
Flutter with flutter_bloc, get_it and retrofit, in development, production and mock flavours. I added the mock one so the app runs, and is tested, without the back end. Phone sign-in with Firebase, push notifications, and Bluetooth scanning that finds Referi wristbands among everything else in range, across Android's and iOS's different ways of reporting them. Builds for both stores run on Bitbucket pipelines.
Recording a live system
A virtual court, two real apps
Referi runs on real courts with real players. None of that belongs in a portfolio, so both apps were recorded from their current code, running on their own, with a stand-in for the back end and invented players.
- 1
Both apps, built for the browser
The companion app runs at phone size, on the mock flavour it already had, with sign-in replaced by an in-memory fake. The court display, a Linux kiosk app, runs in a browser window at the TV's resolution.
- 2
A virtual court
In place of the MQTT broker the display gets a small court of its own: four invented players, padel's scoring rules, and the same state and effect messages the back end sends, through the same queue. The recording scripts tell it what happens on court: a tap on the gate, a press on a wristband.
- 3
Invented players and a club
Drawn avatars for the four players, a promo video of a club that does not exist, and a season of matches, rankings and notifications written for the demo, in English.
- 4
The display's sound
A browser recording has no sound, so the display logs each sound it plays, with the time. After each take the recorder lays the display's own sound files under the video at those times.
The logos, the interfaces, their pictures and the display's sound effects are the apps' own. The players, avatars, clubs, matches, statistics, notifications and the promo video are sample content made for this portfolio.

No demo to try here: Referi is a live product, so this page shows recordings on sample content.
Every screen
The full set of screenshots
The court display
StandbyBetween matches the display shows the club's videos. Tap to playHow to score, undo and pause with the wristband. Players tapping inEach wristband tapped on the gate fills a place in the two teams. Who servesThe player who serves first double-presses. Live scorePoints, games and the server, updated as the wristbands are pressed. Change of sidesCalled at the end of odd games, as the rules want. PauseA double press pauses the game; the display shows the full score. Deuce and advantageAdvantage, back to deuce, advantage again. Match wonGame, set and match, each with its own call. Final scoreEvery set, and each player's points. WinnersThe winning pair, before the court goes back to standby.
The companion app
OnboardingWhat Referi does, in three slides. Sign-inPhone number, terms and the consent for health data. Verification codeThe code sent by SMS (any six digits in the demo). NicknameThe name the court display will show. PairingThe phone looks for the wristband over Bluetooth. PairedThe wristband is now the player's key to every court. HomeNo matches yet. HomeThe avatar made from the player's photo, the month's numbers, the paired wristband. NotificationsResults arrive as soon as the match ends. PerformanceThe last match, set by set, and matches played over time. Advanced statsPoints and breaks won and lost, averaged by week, month or quarter. RankingGlobal, club and city rankings, with the week's movement. Match historyWho she wins with, who she loses to, and every match. Match detailLength, playing time and how the points went. ProfileAccount, notifications, terms, and deleting the account from the app.
Next case study
Herbarium →