A small, dependency-free web tool for exploring "what if" body-composition scenarios from a DEXA report. Enter the four numbers your scan prints — total mass, fat mass, lean (soft tissue) mass and bone mineral content — then drag the sliders to lose fat, gain lean mass or hit a target body-fat percentage. A live chart compares Now against the Scenario as two 100%-stacked bars, and a results table shows every number so the arithmetic always checks.
- Total = Fat + Lean + Bone. Total is always derived from the three parts; it is never stored or edited independently.
- Bone is fixed. DEXA bone mineral content does not change on a training timescale, so it is shown locked.
- The Total slider changes fat. Moving Total adds or removes fat only; use the Lean slider to add or remove muscle.
- 3% floor. Fat can never be pushed below 3.0% of total mass. Essential fat is roughly 3–5% for men and 10–13% for women; the tool only enforces the universal 3% guard and does not ask for sex.
- Target body fat chips change fat only. The 8–30% chips set fat mass so the scenario lands on that percentage at the current lean; the men's and women's examples shown with each chip are approximate ranges, not diagnoses.
npm install
npm run dev # start Vite with HMR
npm test # run the vitest suite (add -- --run for a single pass)
npm run lint # oxlint
npm run build # type-check (tsc -b) and build to dist/Requires Node 22.13 or newer (the deploy workflow uses Node 24; vitest 5 and jest-dom 7 do not support Node 20). Runtime dependencies are react and react-dom only.
- In the repository's Settings → Pages, set Source to GitHub Actions. Do this first: the workflow's
actions/configure-pagesstep fails with "Get Pages site failed" if Pages is not yet enabled. - Push to
main. The included workflow (.github/workflows/deploy.yml) builds the site withBASE_PATH=/<repo>/and publishes it. If you pushed before enabling Pages, re-run the workflow from the Actions tab (it supportsworkflow_dispatch) or push again.
npm run deploypredeploy builds with BASE_PATH=/body-comp/; if your repository has a different name, edit the predeploy script in package.json to match.
When the site is served from the root of a domain, build with BASE_PATH=/ (or leave BASE_PATH unset).
Everything stays in your browser: your numbers are kept in localStorage on this device only and nothing is sent to a server. Share links ("Copy link") encode your numbers in the URL hash, so share them deliberately.
MIT © Sinan Yasar