I Built a No-Signup Calorie Calculator: 5 TDEE Lessons
Most calorie calculators ask for your stats, show a confident number, and hide how they got it. I built one that does the opposite: it names its equation, shows its activity factor range, rounds to 10 kcal, and puts maintenance first. Disclosure up front: I built ToolkitLoop, and this calculator is one of its free browser tools. The code and formulas below are the interesting part, not the promotion.
Try it here: https://toolkitloop.com/calorie-calculator
Lesson 1: Name the equation or the number means nothing
The default equation is Mifflin-St Jeor. The tool also offers revised Harris-Benedict and, when body fat percentage is known, Katch-McArdle. That menu exists because switching equations moves the answer, and a user who cannot see which equation ran cannot reproduce the result.
In code, the Mifflin-St Jeor branch is deliberately boring:
function bmrMifflinStJeor({ sex, weightKg, heightCm, age }) { const base = 10 * weightKg + 6.25 * heightCm - 5 * age; return sex === "male" ? base + 5 : base - 161; } Boring is the point. A calorie estimate should be a transparent formula with visible inputs, not a proprietary model. If a health-adjacent tool will not show its math, treat its output as marketing copy with a number attached.
Lesson 2: Activity factor is the biggest source of error
TDEE is BMR multiplied by an activity factor, here from 1.2 to 1.9:
function tdee(bmr, activityFactor) { return bmr * activityFactor; } One line, huge consequences. Moving from 1.4 to 1.6 on a 1,600 kcal BMR adds 320 kcal, more than most equation switches. And users pick this factor badly, usually from gym days alone, while the honest inputs include occupation, steps, standing time, and training duration and intensity.
That is why the tool has an Activity Level Assistant: it suggests a band, shows an adjacent comparison, and labels confidence as low or medium, and the user can override it. The lesson for any developer building an estimator: when one input dominates the output, spend your UX budget there, not on a prettier result card.
Lesson 3: Round aggressively and say so
The tool rounds results to 10 kcal and presents a starting range. Early versions of estimators like this often print something like 2,347 kcal, which implies a measurement device that does not exist. Rounding is a user-interface decision about honesty:
function roundTo10(kcal) { return Math.round(kcal / 10) * 10; } A rounded range invites testing: eat near the middle for two weeks, watch the trend, adjust. A fake-precise number invites arguing with the tool when the scale disagrees by 100 kcal, which it will, because equations are estimates and bodies are not spreadsheets.
Lesson 4: Caps are guardrails, not targets
Loss scenarios are capped at 20 percent or 500 kcal per day, whichever is smaller; gain is capped at 15 percent:
function lossScenario(maintenance) { const cut = Math.min(maintenance * 0.2, 500); return maintenance - cut; } Writing the cap as Math.min matters. A percentage-only cap lets a large maintenance number justify a huge deficit; a fixed-only cap lets a small maintenance number justify a reckless percentage. Taking the smaller of the two keeps both failure modes in check. The same pattern shows up in rate limiters and budgets: when two limits protect different cases, apply both and take the stricter one.
Lesson 5: State who the tool is NOT for
The calculator is explicit: it is an estimate, not medical or nutrition advice, and it is not for minors, pregnancy or breastfeeding, medical nutrition therapy, eating-disorder treatment, or specialised endurance or competitive nutrition. Its supported self-guided range starts at 1,200 kcal, described as a product range, not a universal clinical safety line.
That paragraph is the most important feature in the whole tool, and it costs nothing to implement. Many developer-built health tools fail here: they ship the formula, skip the scope, and let users apply an estimator to cases it was never designed for. If you build anything health-adjacent, write the exclusion list before you write the formula.
Macros: anchor protein, then fill the rest
Standard mode splits calories by percentage: protein 4 kcal per gram, carbohydrate 4 kcal per gram, fat 9 kcal per gram, and a custom split must total 100 percent. The optional active mode sets protein by body weight first, then allocates fat and the remaining carbohydrate. Anchoring one macro before splitting the rest avoids the classic bug where percentages add up to 110 or 90 and nobody notices until the grams look wrong.
Everything runs in the browser with no signup, and entered values stay on the device. For a tool that asks for body measurements, that architecture is not a bonus feature; it is the minimum respectful design.
The question I keep coming back to
Here is the hook I would actually argue about: should a calorie calculator ever show a single number, or should it always show a range with its equation and activity assumption attached? A single number is easier to act on. A range with its assumptions is easier to trust and easier to correct. I chose the range, and I think the single-number design is why people calculator-hop until they find the answer they wanted.
What would change your mind: a tighter equation, a better activity input, or just a number that stops pretending to be exact? Tell me which one you would build first, and why.
原文:https://www.a8q9.cn/en/article/i-built-a-no-signup-calorie-calculator-5-tdee-lessons-8ba13e.html