# Referi

> Semi-automated scoring for padel courts: a wristband to score, a display on court, an app for the stats.

Case study by Paolo Gianfelici (Full-stack developer & UI/UX designer). https://paologianfelici.com/work/referi

- **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)
- **Stack:** Flutter, Dart, flutter_bloc, Bluetooth LE, MQTT, Firebase Auth, Cloud Messaging, media_kit, Linux kiosk
- **App Store:** https://apps.apple.com/it/app/referi-app/id6756484088
- **Google Play:** https://play.google.com/store/apps/details?id=terzabase.referi.app

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.

*Referi is on the App Store and Google Play, and on padel courts. The recordings on this page do not touch the service: both apps run from their current code as self-contained builds (the companion app on its own mock flavour, the display on a virtual court that stands in for the back end). The players, clubs, matches and avatars are invented, and nothing was sent anywhere.*

- 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

## From a press on the wrist to the stats in your pocket

### 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.

### 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.

### 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.

### 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.

### 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.

## 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.

- **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.
- **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.
- **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.
- **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.

## Recordings

- **On court: tap in, play** (63 s): The court display between matches, then four players tap their wristbands on the court gate, choose who serves, and score by pressing the wristband. The display follows every point. https://paologianfelici.com/media/referi/clips/court-start.mp4?v=da50c18400
- **On court: set point to the winners** (71 s): Later in the same match: a pause called from the wristband, deuce and advantage, the set and match points, and the display's closing screens. https://paologianfelici.com/media/referi/clips/court-finish.mp4?v=8d9d82d4bf
- **The app: sign-up and pairing the wristband** (55 s): A new player signs in with their phone number, picks a nickname and pairs the Referi wristband with the phone. https://paologianfelici.com/media/referi/clips/app-first-run.mp4?v=f20e0ce9b8
- **The app: after the match** (47 s): Giulia's matches, recorded by the wristbands: the last one, her trends, ranking, the full history and the details of each match. https://paologianfelici.com/media/referi/clips/app-stats.mp4?v=f739375a6c
