BikeControl (SwiftControl)
Use Zwift Click, Zwift Play, Shimano Di2, or any Bluetooth controller with MyWhoosh, Rouvy, Zwift, and more. Free to try on iOS, Android, Windows, and macOS.
Player leaderboard — 1 point per person beaten.
Translation pending
Sports & fitnessJavaScript · PLpgSQLGitHub @Sam-BurtOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
The real Centre Parcs leaderboard — same design, same standard "1 point per
player beaten" scoring for every logged round, plus the ability to hand out
one-off bonus/penalty points — running on your own GitHub + Supabase +
Vercel accounts instead of a Claude Artifact. This gets you real accounts
(you sign in as admin from any device) and a real database, so it's yours
to keep and grow.
No coding experience needed for the steps below — just following along and
clicking the right buttons.Read the full README ↗The real Centre Parcs leaderboard — same design, same standard "1 point per player beaten" scoring for every logged round, plus the ability to hand out one-off bonus/penalty points — running on your own GitHub + Supabase + Vercel accounts instead of a Claude Artifact. This gets you real accounts (you sign in as admin from any device) and a real database, so it's yours to keep and grow.
No coding experience needed for the steps below — just following along and clicking the right buttons.
You said you already have accounts on all three, so skip straight to step 1.
supabase/schema.sql from this project, copy the whole file, paste
it into the SQL editor, and click Run. This creates the tables and
the security rules that only let you edit the board. (If you deployed
this project before, re-running this same file is always safe — it only
adds new bits, never touches existing data. If your board already had
players and results before events existed, running this file once
automatically creates your first event from what was already there —
current name, players and history — so nothing is lost; you don't need
to do anything else.)supabase/seed.sql, and run it too. You can always add
or delete players/results from the app itself afterwards.sb_publishable_... — same thing), and the service_role key
(newer dashboards call this the Secret key, starting sb_secret_...
— click "Reveal" and keep this one secret, don't put it anywhere but
Vercel's environment variables).https://your-site.vercel.app/reset-password to Redirect URLs
(swap in your real Vercel URL once you have it from step 3 below — you
can come back and add this after deploying).No git or command line needed:
beat-the-board, keep it
Private (recommended, since anyone with the repo could see your
Supabase URL — though not your password), and create it without a
README (you already have one).node_modules (there isn't one here) — drag-and-drop preserves folder
structure, so app/, components/, lib/, public/, and supabase/
will all land correctly as subfolders.beat-the-board
GitHub repo you just created.NEXT_PUBLIC_SUPABASE_URL — the Project URL from Supabase step 1.5NEXT_PUBLIC_SUPABASE_ANON_KEY — the anon public / Publishable key
from the same pageSUPABASE_SERVICE_ROLE_KEY — the service_role / Secret key from the
same page. This one is what lets you create real logins for other
players from the Players panel — don't add the NEXT_PUBLIC_ prefix
to it, or it would be exposed to every visitor's browser.NEXT_PUBLIC_VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY.beat-the-board-yourname.vercel.app — that's your new board.The site starts with no admin, so anyone who opens it just sees a read-only board (or an empty one, if you skipped the seed data).
your-site.vercel.app/admin/setup./login — sign in there, then go back to the home
page. You should now see the "Log a result" and "Players" panels, and
the pencil icon next to the event name.Bookmark /login on your phone so signing back in later is quick. Once
you're signed in, a tab bar appears at the bottom of the screen (Board /
Missions / Profile) — that's how everyone gets around. Signing out is a
button at the bottom of the Profile tab.
Open the Players panel (only visible while you're signed in as admin):
alfie — this is what they'll always type to sign
in, not a real email, and it's permanent — nobody can change it
themselves later) and a password (there's a "New" button to generate a
random one). After you hit Create account, their username and
password are shown once in a banner — write those down or read them
out, since they won't be shown again. Give that family member the
username/password and point them at your-site.vercel.app/login.Every signed-in player gets a tab bar fixed to the bottom of the screen — Board, Missions, Profile:
To send someone a mission: in the Players panel, tap Mission next to their name, type it, and hit Send mission. It appears on their Missions tab immediately.
For an actual phone alert ("ping!") when a mission lands, instead of them having to check the app:
npx web-push generate-vapid-keys
(Or ask whoever set this up for you to run it and send you the two
keys.)NEXT_PUBLIC_VAPID_PUBLIC_KEY
(the public key) and VAPID_PRIVATE_KEY (the private one — keep this
one secret, same as the Supabase service role key) for all environments,
then redeploy.The notification itself never shows the mission text — just "you've got a new secret mission" — so a locked phone on the coffee table doesn't spoil anything. The real text only ever shows up behind My Eyes Only, after signing in.
On iPhone specifically: Apple only allows push alerts for a site that's been added to the Home Screen and opened from there — a regular Safari tab can't receive them. The Profile tab explains this and walks through it (Share → Add to Home Screen) if it detects you're on an iPhone and haven't done that yet. Missions still show up on the Missions tab either way, with or without phone alerts turned on.
The board now runs in events — an event is the overall "game weekend" (what you called a "game/trip/event"; internally the database still calls these "trips", but everything you actually see in the app says "Event"), with its own name, badge, roster, date window and deadline. Every logged round and bonus/penalty point belongs to whichever event is current; only one event can be running at a time.
Starting an event: open the Event panel (admin only, above "Log a result"), give it a name, pick a badge from the small placeholder collection (swap in your own artwork any time — see below), optionally set a start/end date window, set a deadline (the moment that decides the winner), and tick who's playing from your player accounts. Hit Start event and the board, "Log a result" and the Players panel all scope to that roster.
Ending an event: once the deadline passes, the event finalizes itself automatically the next time you (the admin) have the app open — there's no server running in the background to do it on the dot, so this is a "catches up next time you look" design, which is fine for a family trip. You can also end it early any time with End event now in the Event panel. Either way, whoever's top of the board at that moment wins the trophy — unless it's an exact tie, in which case the event is marked "tied" and the Event panel shows a pick the winner prompt so you make the call by hand rather than the app guessing. The moment a winner is decided (automatically or by hand), whoever has the app open gets a full-screen celebration — badge, winner's name/icon and final score — the next time that happens on their device; each person only sees it once per event, but it fires fresh again next time an event finalizes.
Bonus/penalty points: in the Players panel, anyone currently on the event roster gets a ±Points button — award points on demand (e.g. "+3 for doing the washing up without being asked") or dock them (e.g. "-2 for getting caught on a secret mission"), with an optional note. These stack on top of the normal per-round scoring and show up in the History list alongside logged rounds, so it's always clear where someone's points came from.
Trophies & crowns: winning an event adds a trophy to that player's Trophies card on their Profile tab — a 3×3 (or bigger, once they've won enough to need it) grid of circular slots that fill in as they win. Tap a filled slot for a popup with that event's name, dates and final score. Anyone with at least one trophy also gets a small crown next to their name on the leaderboard, with a number next to it once they've won more than once.
Event badges: the 9 trophy badges under public/badges/ are simple
placeholders in the app's own colours. Replace badge-1.png …
badge-9.png with your own illustrated artwork whenever it's ready (same
file names, square, 512×512px works well) and re-deploy — nothing else
needs to change, and events that already picked a placeholder just show
the new artwork next time the badge loads.
The six icons players pick from (public/icons/icon-1.png … icon-6.png)
are simple placeholders. When your illustrated versions are ready, replace
those six files with your own artwork — same file names, ideally square,
512×512px works well (they're always shown small, but that keeps them
sharp on retina phone screens) — and re-deploy. Nothing
else in the code needs to change; players who already picked an icon just
see the new artwork next time they load the board.
If you ever want to run this on your own computer before pushing changes:
npm install
cp .env.local.example .env.local # fill in your Supabase URL + anon key
npm run dev
Then open http://localhost:3000.