fit-lab: every recommendation shows its work
A free body, safety, goal, and movement assessment, built for India
Most fitness onboarding asks which body part you want to train, hands you a BMI label, and turns a few preferences into a confident-looking plan. fit-lab starts from the other end. It asks only for measurements that change the answer. It screens for reasons a generic plan could be unsafe. It checks whether your goal and your timeline agree. Then it prescribes a full movement foundation, with the evidence and the limits attached.


BMI is not the whole answer
fit-lab is a free, mobile-first fitness assessment for India. It combines height, weight, waist, neck, age, sex at birth, and, where it applies, hip circumference into a body-fat range and practical risk context, instead of pretending BMI is the whole story. Before it talks about goals, it runs a PAR-Q+-informed readiness screen and a SCOFF-informed food-risk screen. Then it checks whether the weight change and timeline you asked for are plausible.
- BMI as the whole assessment
- Let the user pick muscles
- A seeded slider counts as an answer
- Caveats hidden in generic fine print
- Use only measurements that change the read
- Prescribe complete movement coverage
- Require a real answer or interaction
- Put evidence and limits next to the claim
Solo, end to end
I designed and built it end to end: assessment logic, safety flow, body deformation driven by measurements, male and female body assets, anatomy coverage, exercise catalog, dosing, responsive interaction, visual system, source registry, validators, tests, and Cloudflare Pages deployment. It wasn’t a straight line from idea to polish. Some of the best decisions came from spotting that an implementation was wrong and replacing it.
The architecture is an evidence chain
The assessment is deterministic. Measurements and explicit answers become a typed profile. Screening decides whether to stop, caution, or proceed. Goal logic checks feasibility. The foundation engine picks the complete set of movement capacities for the training environment you have. The dose engine assigns sets, reps, RIR, and progression by goal and training age. Then validators refuse to ship any broken link between a recommendation, the anatomy, and its source.
| Layer | What it decides | How it stays honest |
|---|---|---|
| Body | Body-fat range, waist context, percentiles, and the visible figure | Measured inputs, sex-aware formulas, uncertainty bands, and mesh limit notes |
| Safety | Whether to stop, caution, or proceed | Every group closed explicitly; untouched means unanswered, never no |
| Goal | Whether a target and a timeline agree | Rate models use goal type and training age, not motivational copy |
| Foundation | Which movement capacities and variants are required | Automatic full-body coverage, anatomy validation, and verified external guides |
| Dose | Sets, reps, effort, progression, and weekly distribution | Deterministic rules with goal-specific tests and overlap caps |
I rebuilt the body model instead of tuning it


The first deformation system scaled whole horizontal slices of the mesh. Convenient math, dishonest picture. Change the waist and the arms and hands moved with it. Shoulder changes leaked into the skull. Weight made unrelated regions swell, because the algorithm knew height bands, not anatomy.
I replaced it with region-aware deformation. Waist, shoulder, weight, neck, and the other measurements act through per-region masks with controlled falloff, so a local measurement stays local. The rebuild also added honest limit notes. If a combination of measurements goes past what the base mesh can show cleanly, the product says so, instead of passing off a distorted render as measurement truth.
| Failure | Why patching was not enough | Replacement |
|---|---|---|
| Waist changed arms and hands | Horizontal slices had no idea which body part owned a vertex | Waist and torso masks with bounded falloff |
| Shoulder edits reached the skull | Vertices were grouped by height, not by body region | Shoulder, neck, and head regions separated explicitly |
| Extreme inputs looked precise | The renderer had no way to say what the asset could not represent | Profile validation plus visible limit notes |
| One base body stood in for everybody | Ratios cannot turn a male topology into a female body | Sex-aware mesh and profile loading |
The female mesh was a correctness fix
Female users were first rendered on a scaled male mesh with female ratios. That was wrong, and nothing flagged it. I sourced a genuine CC0 MakeHuman-derived female base and built sex-aware asset and profile loading, instead of disguising one body as another.
When the redesign broke, I rolled it back
A large redesign and a deformation rewrite got tangled mid-flight. The live preview was badly broken, and every rescue attempt mixed new visuals with body logic I couldn’t trust. Polishing the branch until it looked plausible would have been the wrong move. I froze the work as a git stash, rolled back to a known-good commit, and restarted the deformation work with smaller boundaries and explicit validators.
Rolling back was the fast path
Recovery is part of the craft. Keeping the failed direction for later and restoring a baseline I trusted was faster and safer than saving code whose behavior I could no longer explain.
I cut every question that did no work
The original flow was dense: character customization, a personality inventory, redundant sliders, and questions that didn’t change the result. I cut it to three moments: body, safety, and goal. Every field left has to move a formula, a threshold, a safety state, the mesh, or an exercise variant.


Cutting needed rules, not just fewer screens. A seeded slider value isn’t an answer until the person touches it. Choosing female adds the hip measurement, because the formula uses it; choosing male removes it. Changing sex clears the safety answers when the question set changes, so an old “none apply” can’t silently answer a pregnancy question that just appeared.
- Twenty-eight asks to use nine answers
- Character details mistaken for assessment data
- Prefilled controls treated as user intent
- Safety state survived a changed question set
- Body, safety, and goal only
- Every field changes a visible output
- Untouched values stay unanswered
- Safety answers that no longer apply are cleared
See the exercise, dose, research, and release detailsTechnique guides, dose logic, catalog research, tokens, accessibility, and publishing
Users don’t pick muscles anymore
The exercise system started as a muscle picker. That sounds like control, but it produces incomplete plans and lets preference pose as evidence. Someone can pick chest and arms and skip squat, hinge, pull, carry, aerobic base, balance, and mobility entirely. I replaced the picker with an automatic full-body foundation.
The foundation covers strength, aerobic base, balance, mobility, yoga, and calisthenics, with optional running, boxing, and outdoors emphasis. Your training environment picks the variants that work. It doesn’t decide whether a capacity matters. A custom anatomy-coverage validator fails the build if a recommended capacity can’t be shown in the 3D anatomy scene.


No verified guide, no exercise
No exercise ships with an invented tutorial, a dead link, or a generic channel homepage. Every recommendation needs an exact external technique-guide URL. The build checks that the URL is live, and for YouTube it verifies the video’s identity through oEmbed. If the guide can’t be verified, the exercise doesn’t ship.
| Evidence surface | Build rule | What the user can inspect |
|---|---|---|
| Technique guide | Exact URL, live response, and verified identity where applicable | The external guide attached to the prescribed exercise |
| Formula or threshold | Registered source and evidence kind | Why the number exists and where it came from |
| Exercise evidence | Catalog entry linked to the source registry | Guideline, meta-analysis, study, or editorial basis |
| Dataset | Source, transformation, and limitation recorded | Population context behind percentiles or ranges |
| 3D asset | License file and profile validation required | Mesh and anatomy provenance |
The muscle plan was wrong, and the tests passed
The first goal-specific engine gave beginners who chose build muscle four sets per muscle per week. That is close to a bare maintenance floor, not a useful hypertrophy plan. The output looked tidy and the code was deterministic. The advice was still wrong.
I retuned weekly volume by training age into evidence-backed hypertrophy ranges, and kept overlap caps so compound exercises don’t create absurd totals. Sets, reps, RIR, progression, and the weekly schedule are now generated together and tested as one system, not copied into cards one by one.
Green tests, wrong idea
The unit tests proved the old rule was applied consistently. They couldn’t prove four sets was the right rule. Fixing it meant going back to the literature, changing the product model, then changing the tests.
Research counts only when it ships
A late, systematic audit found a different kind of failure. Useful research on yoga, calisthenics, a strong sit-to-stand and mortality finding, and neck, arm, and lumbar capacities had been gathered and never connected to the shipped data. The notes existed. The product didn’t know them.
I audited the research against the exercise and capacity catalogs, added what was missing, and kept the same gate: no verified guide, no shipped exercise. The source-registry validator now catches orphaned claims and broken references, so research can’t look done just because it sits in a document.
The design-system switch hid a token collision
I adopted shadcn/ui and Radix primitives to build a proper light and dark system around the orange action accent. The switch surfaced a quiet failure: shadcn’s --muted and --radius names collided with existing fit-lab variables that used the same names for different things. Most secondary text went nearly invisible in light mode, and nothing failed to compile.
A before-and-after visual comparison caught it, not trust in a library’s defaults. I separated the legacy and shadcn token roles, then rechecked the assessment in both themes. The lesson wasn’t to avoid the library. It was to treat adopting tokens like an API migration, with namespace and contrast consequences.
Accessibility changed the implementation
The release sweep combined axe-core with a manual keyboard and screen-reader walk through every stage, both themes, and two viewport sizes. It found contrast pairs that failed WCAG AA, a generated accordion with no visible focus, and an ARIA state mismatch that crept in while I swapped hand-rolled toggles for Radix primitives.
You also don’t need WebGL to understand the body. The Three.js and React Three Fiber scene falls back to an accessible flat SVG when WebGL isn’t available, and labels describe the entered measurements instead of asking assistive technology to read a canvas. I don’t claim clinical or assistive-technology certification. The goal was a tested path that works and is honest about what the visual can and can’t tell you.


The first deploy hit a 403
The first Pages push was blocked with a 403. The environment’s default GitHub credential was read-only for the repository. I didn’t hack around it or paste a token into a script. I authenticated as the actual repository owner for push and Pages operations, and kept deployment in GitHub Actions as a static Vite build.
What’s under the hood
The app runs on React, TypeScript, Vite, and Tailwind. Three.js and React Three Fiber render the body and anatomy scene, with a flat SVG fallback. shadcn/ui and Radix provide the interaction primitives, Recharts draws the gauges, and Framer Motion runs the transitions. More than 270 tests cover the deterministic evidence, dose, goal, screening, capacity, and schedule engines.
Custom build validators check body-mesh assets, anatomy coverage, technique-guide links, and the source registry. GitHub Actions builds the static site and deploys it to Cloudflare Pages. The operations are simple on purpose. The complexity belongs in the product rules.
What v1 proves, and what it doesn’t
fit-lab is a working v1, not a finished clinical product. It shows that the assessment logic, evidence links, body assets, anatomy coverage, responsive flow, themes, and tested accessibility paths work as designed. It doesn’t diagnose, it doesn’t replace a clinician, and it can’t prove health outcomes. There is no usage analytics yet, so I don’t claim completion rates or behavior change.
What I’d fix next
The biggest gap is language. The product is India-first, but the verified technique guides are English-only, which shuts out people it was built for. The next version adds verified guides in major Indian languages, with the same identity and link checks. I’d also add privacy-respecting usage analytics, widen assistive-technology testing, and test the assessment with clinicians and with people using it over time.
The takeaway
fit-lab earned its credibility by removing choices the evidence couldn’t back and adding gates wherever the interface could bluff. The strongest decisions weren’t the 3D body or the orange theme. They were the rollback, the female mesh, the region-aware rebuild, the automatic full-body foundation, the corrected hypertrophy dose, and one rule: nothing ships unless you can see where it came from.