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 to train, hands you a BMI label, and returns a confident-looking plan. fit-lab attaches the evidence and the limits to every answer.
BMI is not the whole answer.
fit-lab is a free, mobile-first assessment for India. Measurements become a body-fat range and risk context, and before goals it runs a PAR-Q+-informed readiness screen and a SCOFF-informed food-risk screen.
- 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 it, directed the build, and tested it.
The architecture is an evidence chain.
The assessment is deterministic, and validators refuse to ship any broken link between a recommendation, the anatomy, and its source.
What each layer decides, and how it stays honest.
| 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 figure responds as the readings go in. The rail shows only values you have touched.
The first deformation system scaled horizontal slices of the mesh, so it knew height bands, not anatomy. Weight made unrelated regions swell.
I replaced it with region-aware deformation: per-region masks with controlled falloff, so a local measurement stays local.
| 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, and nothing flagged it. I sourced a CC0 MakeHuman-derived female base and built sex-aware asset and profile loading.
When the redesign broke, I rolled it back.
A large redesign and a deformation rewrite got tangled and broke the live preview. I rolled back to a known-good commit and restarted with smaller boundaries and explicit validators.
I cut every question that did no work.
The original flow had character customization and a personality inventory. Every field left has to move a formula, a threshold, a safety state, the mesh, or an exercise variant.
Choosing female adds the hip measurement, because the formula uses 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 details
Users don’t pick muscles anymore.
The exercise system started as a muscle picker, which let someone skip squat, hinge, pull, carry, aerobic base, balance, and mobility entirely. I replaced it with an automatic full-body foundation.
It covers strength, aerobic base, balance, mobility, yoga, and calisthenics, with optional running, boxing, and outdoors emphasis. The build fails if a recommended capacity can’t be shown in the 3D anatomy scene.
No verified guide, no exercise.
Every exercise needs an exact external technique-guide URL. The build checks that it is live and verifies YouTube videos through oEmbed.
| 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, close to a bare maintenance floor. The code was deterministic. The advice was still wrong.
I retuned weekly volume by training age into evidence-backed hypertrophy ranges, with overlap caps so compound exercises don’t create absurd totals.
Research counts only when it ships.
A late audit found research on yoga, calisthenics, a strong sit-to-stand and mortality finding, and neck, arm, and lumbar capacities that never reached the shipped data.
I added what was missing. The source-registry validator now catches orphaned claims and broken references.
The design-system switch hid a token collision.
When I adopted shadcn/ui, its --muted and --radius names collided with fit-lab variables that meant different things. Most secondary text went nearly invisible in light mode, and nothing failed to compile.
A before-and-after visual comparison caught it, and I separated the token roles. Adopting tokens is an API migration, with namespace and contrast consequences.
Accessibility changed the implementation.
A release sweep with axe-core and a manual keyboard and screen-reader walk across both themes found contrast pairs failing WCAG AA, an accordion with no visible focus, and an ARIA state mismatch from the Radix swap.
Without WebGL, the 3D scene falls back to an accessible flat SVG, and labels describe the measurements instead of asking assistive technology to read a canvas. I don’t claim clinical or assistive-technology certification.
The first deploy hit a 403.
The default GitHub credential was read-only. Instead of pasting a token into a script, I authenticated as the repository owner and deployed through GitHub Actions as a static Vite build.
What’s under the hood.
The app runs on React, TypeScript, Vite, and Tailwind, with Three.js and React Three Fiber for the 3D scene, shadcn/ui and Radix for interaction, Recharts for gauges, and Framer Motion for transitions.
What v1 proves, and what’s next.
fit-lab is a working v1, not a finished clinical product. It doesn’t diagnose or replace a clinician, and it can’t prove health outcomes. There are no usage analytics yet, so I don’t claim completion rates or behavior change.
The biggest gap is language: the product is India-first, but the verified technique guides are English-only. Next come guides in major Indian languages with the same checks, privacy-respecting usage analytics, wider assistive-technology testing, and testing with clinicians and people using it over time.
fit-lab earned its credibility by removing choices the evidence couldn’t back and adding gates wherever the interface could bluff.









