Table of contents
Open Table of contents
The constraint
Most web apps assume a server somewhere: an API to call, assets split across files, a deploy step that uploads them. 1up Court Queue couldn’t assume any of that, because of where it gets used.
A badminton session has more players than courts, and someone has to track who’s on, who’s waiting, and who plays next. That someone is standing courtside with a phone, and sports halls are notorious for weak signal. A tool that needs a connection can stop working at the exact moment it’s needed most. So the build target became: one file, no server, works offline by default.
What breaks when you build this way
A single-file build removes a few things most web development takes for granted.
There’s no server-side anything — no API routes, no server-rendered pages, nothing running except what’s in the browser. There’s no code-splitting in the usual sense either. Normally a bundler hands out separate chunks on demand; here, every chunk the app will ever need has to be in the one file from the start, because there’s no second request to fetch anything else.
That means JavaScript and CSS both have to live inside a single HTML payload. The build tooling takes care of the mechanics of combining them, but it does shape what’s reasonable to reach for — a lot of third-party libraries assume they can lazy-load something later, and this build target doesn’t give them that option.
What it buys you
In exchange, the app asks nothing of its environment. Open the file and it runs — no install, no deploy pipeline, no hosting account, no DNS. At a venue with no signal and no Wi-Fi, that’s not a nice-to-have, it’s the difference between the app working and not.
It also changes what “shipping” means. There’s no release process beyond handing someone a file. For a tool built for one specific use — organising a session, courtside, on a phone — that simplicity is worth more than the flexibility a normal deploy would offer.
Two details that make it feel native
Being single-file doesn’t mean being careless about the phone it runs on. Two small things carry a lot of the feel:
- Safe-area insets. The app sets
viewport-fit=coverand uses safe-area insets in its CSS, so content sits clear of notches and rounded corners instead of hiding behind them. - A pre-paint theme script. A small script runs before the page paints, reading the saved theme and applying it immediately. Without it, a dark-mode user gets a flash of white before the page catches up.
Neither detail depends on the single-file build — they’re just the kind of polish that’s easy to skip and obvious when it’s missing.
Try it yourself
The full write-up is on the 1up Court Queue project page, including the stack and the rest of what it does on the court side.