Equations

These run the app. Each one is exactly as the code computes it.

Estimated one-rep max, with RPE

weight × (1 + (reps + RIR) ÷ 30)

RIR = 10 − RPE. Reps in reserve: how many more you had in you. RPE 8 → about 2 left.

Estimated one-rep max, no RPE logged

weight × (1 + reps ÷ 30)

The classic Epley equation. When no RPE is logged, RIR counts as 0 and the formula reduces to this.

The RPE trigger

top-set RPE ≤ trigger → earn it

Top-set RPE at or under the trigger earns progression. Default trigger is RPE 8, adjustable per program. Above the trigger, or no RPE logged, the target holds.

RPE-based progression

below max → +(10 − RPE) reps, min +2  ·  at max → +increment, back to min

Double progression, gated on RPE. Reps below your max → add 10 − RPE reps, never fewer than 2: RPE 8 earns +2, RPE 7 earns +3, RPE 6 earns +4. Half-step RPEs round to whole reps, half up: RPE 7.5 earns +3. At the top of your range → add the increment and reset to the range minimum - and if the rep jump itself would overshoot the top, the load goes up instead. The load jump itself scales with the headroom under your trigger: ×1 at the trigger, up to ×2 for a very easy top set.

Load increments

lb: round((w + v) ÷ v) × v  ·  %: nearest 5 lb to w × (1 + v ÷ 100)

Pounds: the new load lands on your increment grid: weight + value, rounded to the nearest multiple of value. Percent: weight × (1 + value ÷ 100), snapped to the 5 lb grid (2.5 kg in metric), never a decimal. Default increment: 5 lb.

%1RM target

snap_to_increment(basis × pct ÷ 100)

Basis = your training max, or your best same-rep-range estimated 1RM. pct defaults to 75%, clamped 1-100. The result snaps to your increment grid, not plates. Reps carry over from your latest top set, clamped to the range; with no history yet, it is set at your range-minimum reps.

Training max basis

entered TM wins; else best same-zone e1RM

A training max you type in beats everything. Without one, the app takes the best estimated 1RM from a top set logged in the same rep range.

Stage percent

pct = the week's stage % or your % of 1RM

On a %1RM program with Stages on, a week can carry its own % of training max. A week without one uses the program's % of 1RM setting.

Warm-up ladder snapping

round(x ÷ 5) × 5 / round(kg ÷ 2.5) × 2.5

Warm-up ladder rungs snap to the 5 lb grid (2.5 kg in metric), the same formula grid as percent increments, not a plate calculator. Working prescriptions keep the exact computed load and snap to your [increment grid](/docs/equations#load-increments) instead.

Linear progression

+increment every session

No RPE gate. Reps carry over from the latest top set, pulled into the range when they land outside it; only the load moves. Default: +5 lb a session. A top set below the range floor doesn't earn the jump - it's pulled back into range first ([Week-range rebase](/docs/equations#week-range-rebase)). The top set comes from the last session of that same program workout; for standalone work, from your latest session overall.

Time progression

latest + step × (10 − RPE), min 2 steps, clamped to range

Timed work progresses in seconds, scaled by RPE headroom like reps in [RPE-based progression](/docs/equations#rpe-based-progression), and always lands on whole seconds. Default step is 5 seconds, clamped to the time range. On deload weeks, unweighted timed work holds its seconds as-is - deloads reduce load only. Weighted timed work keeps its seconds and only the load deloads.

Deload week

load × d%, on Deload weeks

A week you set to the Deload stage; deloads are never scheduled automatically. On a Deload week, the normal prescription runs at the deload intensity: default 60%, clamped to 40-80%, snapped to your increment grid. Bodyweight rep work scales reps to the deload intensity instead, since there is no load to reduce; unweighted timed work holds its seconds as-is.

Week-range rebase

e1RM ÷ (1 + targetReps ÷ 30)

When you change an exercise's rep range, the app rebases the load with Epley in reverse: the weight your current estimated max predicts for the top of the new range. The same reverse-Epley math pulls a linear top set that landed below its range back to mid-range at the same effort.

Volume

weight × reps → add it up

Per set, summed. A set counts fully toward each primary muscle and 45% toward each secondary muscle in muscle-volume views. Set counts work differently: a set counts in full toward secondary muscles too, including in Muscles worked counts; the 45% applies to volume figures only. Distance-tracked work (sled pushes, carries) and non-volume work (stretches, mobility) count 0 - they aren't tonnage.

Dumbbell weight

enter per bell → stored = 2 × entered

Entry and display default to per-dumbbell. The app stores the combined total of both bells; volume and PRs use that stored total, so both bells are already counted and nothing is ever doubled. Exercises performed with a single dumbbell - goblet squats, pullovers, concentration curls, and their kin - default to One instead: the weight you enter is stored as-is, with no doubling. Increments follow the entry mode: in per-dumbbell mode the configured increment is the per-bell step, so the stored total moves by twice it; in total mode the increment applies to the total.

Similar exercises

3 × shared primary + shared secondary + 2 if same equipment + 2 if same push/pull + 1 if same category

How the app scores "similar": shared primary muscles weigh triple, shared secondary muscles single, matching equipment adds two, the same force (push, pull, or static) adds two, and the same exercise category adds one.

Top set

heaviest weight wins; ties → more reps

The set the engine reads each session. Warm-up sets sit out the top-set race.