Gym Tracker is a phone-first web app that answers the question I used to ask myself before every set: what weight today? It reads my training history, the machine in front of me and how long I've been away, then gives a target for every set. It runs at gym.hadirfan.com for me and a few friends.
Why it exists
In mid-2026 I stopped training for three months to finish my final-year project and a competition. Coming back meant a new gym with machines I had never used, kg and lb stacks mixed together, and no safe idea of where to restart. A notes app can't tell you that a 60% comeback load on an unfamiliar cable machine should round down to its 5 kg steps. So I built something that could.

The calibration engine
At the core is a pure TypeScript engine with no database code in it, covered by more than 550 tests. It understands how each machine counts weight: pin stacks, barbells with the bar included, plate-loaded machines, per-hand dumbbells, and assisted machines, where less weight means harder. It converts between kg and lb, rounds down to each machine's real increment, and switches to rep progression when the next step would be too big a jump.
It also handles the messy parts of real training. A long break triggers a comeback deload that ramps back up over three weeks. The first session on a new machine becomes a calibration set, where one tap ("how many reps were left?") tunes the next weight. If a machine is missing or busy, a swap suggests equivalent exercises with a starting weight estimated from my own related lifts and capped so it's never heavier than the original. Plateaus are only flagged when the engine itself has stopped progressing a lift, so a one-off heavy set doesn't trigger false alarms.


Making it feel like a game
I wanted opening the app to feel like loading a game HUD, not filling in a form. Every working set earns XP, beating last session and hitting PRs earn more, and levels climb from Bronze to Diamond. Finishing a session plays a short "cleared" sequence: the XP counts up, a low-poly body map lights up the muscles that were trained, and a radar chart shows the week against the plan. There are seven colour themes, and a contrast test fails the build if any of them stops being readable.



Built for friends, not just me
My friends train differently: upper body only, cardio only, Arnold splits. New users answer eight quick questions and the app generates a full program in one of eight splits, sized to their goal, experience, time budget and the equipment at their gym. Walking a new gym once marks which machines exist, and that map is shared with everyone who trains there.

Under the hood
Next.js 16 with TypeScript and Tailwind on Vercel, and Supabase Postgres with row-level security on every table. An offline queue in IndexedDB means sets still save when the gym has no signal. Training-day reminders go out as Web Push from a scheduled database job. A performance pass cut the main screen from 16 sequential database round trips to 2, from about 670 ms to 130 ms.
Status
Live and invite-only. My own comeback starts on it in November 2026, with nutrition tracking for Malaysian food and friend challenges next.