§ Forge — hypertrophy tracker · Architecture — stack & data model
The fatigue model
The signature feature: a per-muscle fatigue estimate that drives the body
heatmap and the recovery story. Like progression, it's pure math in engine.js,
computed on read from set_logs (never stored).
The idea
Training a muscle deposits fatigue; rest clears it. Forge models this as a deposit-and-decay system over each muscle group. Two inputs decide how much a set deposits:
- Muscle contribution — from the exercise's
musclesmap. A prime mover gets 1.0; assistance muscles get ~0.3–0.8. (Barbell Bench: chest 1.0, front delts 0.5, triceps 0.5.) - Effort — derived from RPE.
effortFactor(rpe)maps RPE into[0.3, 1](RPE 10 → 1.0, RPE 7 → 0.5; missing RPE defaults to 0.75). Harder sets fatigue more.
The decay
Each past set's contribution is multiplied by an exponential decay based on how long ago it was logged:
decay = 0.5 ^ (hoursAgo / HALF_LIFE) // HALF_LIFE = 48h
So a set's fatigue halves every ~2 days. computeFatigue(sets, now, muscleKeys)
sums contribution × effort × decay across all recent sets per muscle, giving a
raw score. That raw score is squashed into a 0–100% reading with a saturating
curve so it never runs away:
pct = 100 × (1 − e^(−raw / FATIGUE_REF)) // FATIGUE_REF = 5
Finally fatigueTier(pct) buckets it into 5 discrete heat tiers
(cold · cool · warm · hot · molten) used for colouring.
What you see
- The front/back body map (the body map) colours each muscle by its tier, with a soft bloom on hot/molten muscles — cold steel that glows where you worked.
- A muscle status list: a heat bar + % per group.
- Starting a day that targets a still-hot muscle is the natural place for a recovery warning (the data is right there).
Weekly volume (a different question)
Fatigue answers "is it recovered?"; volume answers "am I training it
enough?". weeklyVolume(sets, now, muscleKeys, band) sums muscle contributions
over the trailing 7 days into effective sets and compares to a hypertrophy
band (default 10–20 effective sets/week), flagging each muscle under /
in / over. This is the landmark-style volume tracking serious lifters use,
and it surfaces the honest limit of a bar-and-bells gym: with no vertical pull,
back volume is harder to bank — and the numbers show it.
Why decay instead of "days since trained"
A simple "last trained 2 days ago" flag can't tell a hard 4-set session from a single easy set, and can't blend overlapping muscle contributions from different exercises. The continuous decay model accumulates all recent stimulus weighted by recency and effort, which is both more honest and what makes the heatmap move in a believable way.