This tool allows you to quickly build your weightlifting programs, ensure you have proper weekly volume per muscle group, and balance it with the time you spend in a gym. You can build multi-week programs, plan your mesocycles, deload weeks, testing 1RM weeks, and see the weekly undulation of volume and intensity of each exercise on a graph.
Set the program name, create weeks and days, type the list of exercises for each day, putting each exercise on a new line, along with the number of sets and reps after slash (
/
) character, like this:
Squat /3x3-5
Romanian Deadlift /3x8
Autocomplete will help you with the exercise names. You can also create custom exercises if they're missing in the library.
On the right you'll see Weekly Stats, where you can see the number of sets per week per muscle group, whether you're in the recommended range (indicated by color), strength/hypertrophy split, and if you hover a mouse over the numbers - you'll see what exercises contribute to that number, and how much.
The exercise syntax supports RPEs , percentage of 1RM, rest timers, various progressive overload types, etc. Read more about the features in the docs!
When you're done, you can convert this program to Liftosaur program, and run what you planned in the gym, using the Liftosaur app!
To use this program:
Install Liftosaur app
Copy the link to this program by clicking on below
Import the link in the app, on the Choose Program screen.
03:55
999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
///***Muscle Group IDs***/
/// 01 => Chest
/// 02 => Triceps
/// 03 => Back
/// 04 => Biceps
/// 05 => Calves
/// 06 => Quads & Glutes
/// 07 => Hamstrings
/// 08 => Side Delts
/// 09 => Abs
/// Full tag is created by combining digits from:
/// Day (1-2 digits) & Muscle Group ID (2-digits) & Index (2 digits, 0-based)
/// to create 5-6 digit long unique tag.
///
/// Ex:
/// 3 Quads exercises on day 4 would have tags:
/// 40600, 40601, 40602
/// 4 => 4th day of week
/// 06 => Quads Muscle Group ID
/// 00, 01, 02 => Index of exercise for muscle group in that day
{"exportedProgram":{"customExercises":{},"program":{"id":"rngzffcj","name":"RP Hypertrophy 4-Day Upper-Lower","url":"","author":"","shortDescription":"","description":"","nextDay":1,"weeks":[],"isMultiweek":false,"days":[{"id":"fovgggqd","name":"Day 1","exercises":[]}],"exercises":[],"tags":[],"deletedDays":[],"deletedWeeks":[],"deletedExercises":[],"clonedAt":1730500899235,"planner":{"name":"RP Hypertrophy 4-Day Upper-Lower","weeks":[{"name":"Start","days":[{"name":"Day 1 - Upper A","exerciseText":"///***Muscle Group IDs***/\n/// 01 => Chest\n/// 02 => Triceps\n/// 03 => Back\n/// 04 => Biceps\n/// 05 => Calves\n/// 06 => Quads & Glutes\n/// 07 => Hamstrings\n/// 08 => Side Delts\n/// 09 => Abs\n\n/// Full tag is created by combining digits from:\n/// Day (1-2 digits) & Muscle Group ID (2-digits) & Index (2 digits, 0-based)\n/// to create 5-6 digit long unique tag.\n///\n/// Ex:\n/// 3 Quads exercises on day 4 would have tags:\n/// 40600, 40601, 40602\n/// 4 => 4th day of week\n/// 06 => Quads Muscle Group ID\n/// 00, 01, 02 => Index of exercise for muscle group in that day\n\n///*****PROGRAM LOGIC*****///\ntLogic: Squat[1-3] / used: none / 10+x5 / 86.53% / warmup: 1x12 50%, 1x8 75%, 1x4 110% / update: custom() {~\n /// Minimum reps for any set to be in the hypertrophy range (based on RP\n /// guidelines of about 5-30 reps between 3-0 RIR for hypertrophy as of\n /// early 2024)\n var.MIN_HYP_REPS = 5\n\n /// Bilateral exercise (both sides at the same time)\n var.TYPE_BILATERAL = 1\n /// Unilateral exercise (left/right side done as separate sets)\n var.TYPE_UNILATERAL = 2\n\n /// Minimum increment value that will be treated as a fixed weight rather than percentage\n var.FIXED_WEIGHT_INCR_MIN = 0.25\n\n /// Disable progression and match or beat system, just repeat targets\n var.PROG_TYPE_NONE = 0\n /// Linear - Add weight each week keeping a fixed single rep target after\n /// week 1, unless at the minimum for hypertrophy, in that case add 1 rep.\n var.PROG_TYPE_WEIGHT = 1\n /// Double - Add reps until hitting the top of the target rep range, then\n /// add weight and reset rep targets to the original range\n var.PROG_TYPE_REPS = 2\n\n /// Number of expected accumulation weeks to estimate RPE/RIR progression\n var.ACCUM_WEEKS = 4\n /// Week number to determine when progression vs deload logic applies (should\n /// be last week number defined in program)\n var.DELOAD_WEEK = 3\n\n /// Target RPE for week 1 of the program\n var.RPE_START = 7\n /// Target RPE for final accumulation week\n var.RPE_END = 10\n /// How much RPE should increase each week to reach RPE_END by final accumulation week\n var.RPE_INCR = (var.RPE_END-var.RPE_START)/(var.ACCUM_WEEKS-1)\n /// RPE value for deload and triggers recovery session logic to update all sets in that session\n var.RPE_RECOVERY = 3\n\n /// Prepare workout and handle set progression\n if (setIndex == 0) {\n /// Always start mesocycle with defined number of sets and values\n if (week == 1) {\n numberOfSets = state.startNumSets*state.type\n /// Make all sets AMRAP during week 1 since we're targetting a rep range & RIR, keeping all other values the same\n sets(1, state.type, state.targetMinReps, state.targetMaxReps, 1, completedWeights[1], 0, var.RPE_START, 0)\n sets(state.type+1, numberOfSets, var.MIN_HYP_REPS, var.MIN_HYP_REPS, 1, completedWeights[1], 0, var.RPE_START, 0)\n }\n /// Only do set progression during accumulation weeks\n else if (week < var.DELOAD_WEEK) {\n var.numSets = state.numSets\n if (state.progressType != var.PROG_TYPE_NONE) {\n var.numSets = (state.numSets + state.setsModifier)*state.type /// Double for unilateral exercises\n }\n var.numSets = var.numSets > 0 ? var.numSets : state.type\n numberOfSets = var.numSets\n \n var.rpe = 0\n var.amrap = 0\n /// Check if sets were added since last time\n if (numberOfSets/state.type > state.numSets) {\n /// Offset RPE by 1 increment since sets have increased and we don't want to progress sets & proximity\n /// to failure at the same time per critiques of RP methodolgy from sources like Eric Helms and MASS\n var.rpe = state.targetRpe - var.RPE_INCR\n var.rpe = var.rpe >= var.RPE_START ? var.rpe : var.RPE_START\n var.amrap = 1\n \n /// Undo previous weight progression when adding sets and doing linear progression so multiple variables\n /// are not progressing at once. Only reverse if we increased by a single increment over last time.\n if (state.progressType == var.PROG_TYPE_WEIGHT) {\n /// Handle reversing fixed increments\n if (state.increment >= var.FIXED_WEIGHT_INCR_MIN) {\n if (state.lastIncrement == state.increment) {\n weights -= state.lastIncrement\n }\n }\n /// Handle reversing percentage based increments\n else if (state.increment > 0) {\n var.lastWeight = completedWeights[1] - state.lastIncrement\n var.lastWeightIncremented = roundWeight(var.lastWeight + (var.lastWeight*state.increment))\n if (var.lastWeightIncremented == completedWeights[1]) {\n weights -= state.lastIncrement\n }\n }\n }\n\n /// Configure sets added today as RPE target & AMRAP and keeping weight of previous last set\n /// sets(fromIndex, toIndex, minReps, maxReps, isAmrap, weight, timer, rpe, shouldLogRpe)\n sets((state.numSets*state.type)+1, numberOfSets, var.MIN_HYP_REPS, var.MIN_HYP_REPS, 1, completedWeights[state.numSets], 0, var.rpe, 0) \n }\n /// First set is a rep range (not just single rep increase from double progression) so show the RPE targets\n /// and make it prompt for completed reps\n else if (minReps[1] < reps[1]-1) {\n var.rpe = state.targetRpe\n var.amrap = 1\n }\n\n /// Configure pre-existing sets in case we are targetting an RPE today instead of just match/beat previous session.\n /// Useful as a signal that I shouldn't just hit rep targets today and instead try to focus on hitting RPE/RIR\n for (var.set in reps) {\n if (var.set <= state.numSets) {\n sets(var.set, var.set, minReps[var.set], reps[var.set], var.amrap, completedWeights[var.set], 0, var.rpe, 0)\n }\n }\n }\n /// Deload week\n else {\n var.deloadSets = floor(state.numSets * state.deloadSetsRatio)\n /// Ensure we have an even number of deload sets for unilateral exercises (erring on side of doing less)\n if (var.deloadSets % state.type != 0) {\n var.deloadSets = var.deloadSets - 1\n }\n /// Ensure deloadSets is not negative\n if (var.deloadSets <= 0) {\n var.deloadSets = state.type\n }\n numberOfSets = var.deloadSets\n }\n }\n /// Check if recovery session is being done/started by having marked a set as low\n /// RPE, and if so, we want to use that same low weight and RPE for the rest of the\n /// session\n else if (RPE[setIndex] > 0 && RPE[setIndex] <= var.RPE_RECOVERY && week < var.DELOAD_WEEK) {\n RPE = RPE[setIndex]\n weights = completedWeights[setIndex]\n }\n~} / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 0, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) {~\n///***PARAMETERS***///\n /// increment: weight to progress by each week. Treated as fixed lb/kg value if at least FIXED_WEIGHT_INCR_MIN or higher, otherwise, decimal percentage. Always include lb/kg label even when setting a percentage.\n /// progressType: 0 = none, 1 = linear progression (add weight each time targets are hit), 2 = double progression (add reps until hitting top of rep range, then weight)\n /// targetMinReps: minimum target reps for week 1 set 1 (following sets can drop below this)\n /// targetMaxReps: max target reps for week 1 set 1\n /// startNumSets: how many sets to start with in week 1 (should be an even number for unilateral exercises)\n /// type: movement type. 1 = bilateral, 2 = unilateral\n /// deloadWeightRatio: percent to change weight by for deload week (decimal 0 to 1)\n /// deloadRepsRatio: percent to change reps by for deload week (decimal 0 to 1)\n /// deloadSetsRatio: percent to change number of sets by for deload week (decimal 0 to 1)\n /// rating: set progression rating. Evalute recovery from previous session & performance today to add/subtract sets to exercises (typically -2 to 2)\n /// rateGroup: target group of tagged exercises to apply rating. Typically 3-4 digits: first 1-2 are day in week, last 2 are muscle group ID.\n /// ratingIndex: index of exercise in group to apply rating to (combined with rateGroup to create full tag, then gets incremented after applying rating)\n /// numRatingExercises: how many exercises are in that muscle group target where rating applies (i.e. how many exercises in the program have that tag)\n /// lastIncrement: how much weight was changed after completing the last working session\n /// numSets: last completed number of sets in previous working session, basis for how many sets to do again next time\n /// setsModifier: number of sets to add/remove relative to last done number of sets. Usually updated via rating to modify number of sets shown for future sessions.\n /// mesoWeek: current week in mesocycle\n /// targetRpe: underlying estimated RPE/RIR target for current working week based on meso length and start/end RPE targets (mainly displayed when new sets are added or rep ranges are used)\n\n///***CONSTANTS***///\n /// Minimum reps for any set to be in the hypertrophy range (based on RP\n /// guidelines of about 5-30 reps between 3-0 RIR for hypertrophy as of\n /// early 2024)\n var.MIN_HYP_REPS = 5\n \n /// Disable progression and match or beat system, just repeat targets\n var.PROG_TYPE_NONE = 0\n /// Linear - Add weight each week keeping a fixed single rep target after\n /// week 1, unless at/under the minimum for hypertrophy, in that case add\n /// reps.\n var.PROG_TYPE_WEIGHT = 1\n /// Double - Add reps until hitting the top of the target rep range, then\n /// add weight and reset rep targets to the original range\n var.PROG_TYPE_REPS = 2\n\n /// Bilateral exercise (both sides at the same time)\n var.TYPE_BILATERAL = 1\n /// Unilateral exercise (left/right side done as separate sets)\n var.TYPE_UNILATERAL = 2\n\n /// Maximum weight increment value that will be treated as a percentage rather than fixed weight\n var.FIXED_WEIGHT_INCR_MIN = 0.25\n\n /// Number of expected accumulation weeks to control RPE/RIR progression. Can\n /// be different than number of weeks defined in the program to allow smaller\n /// programs where weeks are manually repeated or larger programs to allow\n /// autoregulating mesocycle length while still having weeks auto-progress.\n var.ACCUM_WEEKS = 4\n /// Week number to determine when progression vs deload logic applies (should\n /// be same as number of weeks defined in program since deload should be the\n /// final week)\n var.DELOAD_WEEK = 3\n\n /// Target RPE for week 1 of the program\n var.RPE_START = 7\n /// Target RPE for final accumulation week\n var.RPE_END = 10\n /// How much RPE should increase each week to reach RPE_END by final accumulation week\n var.RPE_INCR = (var.RPE_END-var.RPE_START)/(var.ACCUM_WEEKS-1)\n /// RPE that indicates a recovery or deload session/set\n var.RPE_RECOVERY = 3\n\n /// Defines the threshold where we consider weights to be used during deload\n /// still \"heavy\" and thus should do logic to update each deload set weight\n ///\n /// Typically we just want to use the same weight for all deload sets if the\n /// weight is reduced substantially for deload, but if deload weight is still\n /// pretty heavy, and working weights bewteen sets were different during\n /// accumulation, we probably also want to use different weights in each deload\n /// set.\n var.DELOAD_WEIGHT_RATIO_HEAVY = 0.8\n\n///***Useful Variables***///\n /// Ensure type is valid\n state.type = state.type == var.TYPE_BILATERAL || state.type == var.TYPE_UNILATERAL ? \n state.type : var.TYPE_BILATERAL\n\n /// Ensure we have a non-negative starting number of sets\n if (state.startNumSets < 0) {\n state.startNumSets = state.type\n }\n\n /// Ensure the progress type is valid, default is weight progression\n state.progressType = state.progressType == var.PROG_TYPE_NONE\n || state.progressType == var.PROG_TYPE_WEIGHT || state.progressType == var.PROG_TYPE_REPS ?\n state.progressType : var.PROG_TYPE_WEIGHT\n\n /// Indicates if current day was for recovery\n var.recoveryDay = numberOfSets <= 0 || (RPE[numberOfSets] > 0 && RPE[numberOfSets] <= var.RPE_RECOVERY)\n\n /// Indicates if current day was a real working day that may produce progression\n var.progressDay = !var.recoveryDay && state.progressType != var.PROG_TYPE_NONE\n && completedReps[1] > 0\n\n /// If it's program week 1, and this isn't the first time we're doing the program,\n /// we may have skipped deload so ensure variables are set to restart progression\n if (week == 1) {\n state.mesoWeek = 1\n state.lastIncrement = 0lb\n state.ratingIndex = 0\n if (var.progressDay) {\n state.startNumSets = numberOfSets/state.type\n }\n state.numSets = state.startNumSets\n state.setsModifier = 0\n state.targetRpe = var.RPE_START\n }\n\n///***Now we do progression and setup future workouts/meso***///\n\n /// Still in acumulation weeks\n if (week < var.DELOAD_WEEK) {\n /// Ensure target RPE for this session is set correctly based on if sets were added\n /// compared to last time\n state.targetRpe = numberOfSets/state.type <= state.numSets ? state.targetRpe : state.targetRpe - var.RPE_INCR\n\n var.sumLastReps = 0 /// sum of minimum rep targets for same num sets as last time (i.e last session performance or target range)\n var.sumCompletedReps = 0 /// sum of completed reps today for same num sets as last time\n var.newSetsAboveMin = 1 /// signifies all new sets added today completed reps above minimum reps\n for (var.set in completedReps) {\n /// Compare sets from previous session to todays performance to determine if we\n /// at least matched performance/volume in those initial pre-existing sets\n if (var.set <= state.numSets) {\n var.sumLastReps = var.sumLastReps + minReps[var.set]\n var.sumCompletedReps = var.sumCompletedReps + completedReps[var.set]\n }\n /// Check that newly added sets were above the minium reps\n else if (completedReps[var.set] < minReps[var.set]) {\n var.newSetsAboveMin = 0\n }\n }\n\n /// Signifies if rep targets were hit in this session.\n ///\n /// We compare sums to allow missing the rep target on one set but then make up for\n /// it in another set so long as it balances out (i.e. set 1 did 2 LESS reps than\n /// target, but then set 2 did 2+ MORE reps than target which balances it out and we\n /// still should progress as volume should be about the same)\n var.hitReps = completedReps[1] >= state.targetMinReps\n && var.sumCompletedReps >= var.sumLastReps && var.newSetsAboveMin\n\n /// Potentially change weight by more than 1 increment in a few situations where\n /// we will set this value to indicate the reason and number of extra increments.\n /// <= -1 => weight was too heavy, so decreased by 1 or more increments\n /// == 0 => weight was inappropriate, but we manually corrected by last set today\n /// == 1 => weight was appropriate, normal progression logic applies\n /// >= 2 => weight was too light, so increased by multiple increments\n var.incrementModifier = 1\n \n /// Indicates if the first set progressed by weight or reps so later sets can\n /// follow. Will be modified in main progression logic loop below\n var.firstSetProgType = state.progressType\n \n /// Only record/update program if this was not a recovery session/set\n if (!var.recoveryDay) {\n /// Loop through sets and do main progression logic\n for (var.set in completedReps) {\n var.weight = completedWeights[var.set]\n var.reps = reps[var.set]\n var.minReps = minReps[var.set]\n /// Save values from today before incrementing for setting up deload later\n var.todaysWeight = completedWeights[var.set]\n var.todaysReps = var.reps\n\n /// Do unique logic for set 1\n if (var.set == 1) { \n if (var.progressDay) {\n /// We didn't hit targets in week 1, weight is too heavy for the desired rep\n /// range for this mesocycle so we need to decrease it\n if (week == 1 && completedReps[var.set] < state.targetMinReps) {\n /// Check if we manually lowered weights in later sets so we can re-use that\n if (completedWeights[numberOfSets] < completedWeights[var.set]) {\n var.weight = completedWeights[numberOfSets]\n var.incrementModifier = 0\n }\n else {\n var.incrementModifier = completedReps[var.set] - state.targetMinReps\n /// Fixed weight increments\n if (state.increment >= var.FIXED_WEIGHT_INCR_MIN) {\n var.weight = completedWeights[var.set] + (var.incrementModifier*state.increment)\n }\n /// Percentage based increments\n else {\n var.weight = completedWeights[var.set] + (completedWeights[var.set]*state.increment)*var.incrementModifier\n }\n }\n }\n else if (var.hitReps) {\n var.reps = completedReps[var.set]\n var.minReps = var.reps\n var.todaysReps = var.reps\n \n /// Options for indicating weight was too light and should be adjusted heavier:\n /// 1. Do more reps than the target rep range max\n /// 2. Manually mark as 1+ lower RPE than this week's target\n if (var.reps > state.targetMaxReps || (RPE[var.set] > 0 && RPE[var.set] <= state.targetRpe-1)) {\n /// Check if we manually adjusted weight in later sets during this workout and\n /// just use the weight from the last set as the new weight for all sets\n if (completedWeights[numberOfSets] > completedWeights[var.set]) {\n var.weight = completedWeights[numberOfSets]\n var.incrementModifier = 0\n }\n /// Otherwise, modify the number of increments we add for next time\n else {\n var.diff = var.reps > state.targetMaxReps ?\n var.reps - state.targetMaxReps : state.targetRpe - RPE[var.set]\n var.incrementModifier = var.diff + 1 /// Add 1 to ensure change larger than 1 increment\n }\n }\n \n /// Linear progression\n if (state.progressType == var.PROG_TYPE_WEIGHT) {\n /// Only increase weight if we aren't at the minimum reps for hypertrophy\n if (var.reps > var.MIN_HYP_REPS) {\n /// Fixed weight increments\n if (state.increment >= var.FIXED_WEIGHT_INCR_MIN) {\n var.weight = var.weight + state.increment*var.incrementModifier\n }\n /// Percentage based increments\n else {\n var.weight = var.weight + (var.weight*state.increment)*var.incrementModifier\n }\n var.firstSetProgType = var.PROG_TYPE_WEIGHT\n }\n /// Otherwise increase reps instead so we have some room to drop reps in\n /// following sets without dropping weight since this is still the 1st set\n else {\n var.reps = var.reps + 1\n var.firstSetProgType = var.PROG_TYPE_REPS\n }\n }\n /// Double progression\n else if (var.reps >= state.targetMaxReps) {\n /// Fixed weight increments\n if (state.increment >= var.FIXED_WEIGHT_INCR_MIN) {\n var.weight = var.weight + state.increment*var.incrementModifier\n }\n /// Percentage based increments\n else {\n var.weight = var.weight + (var.weight*state.increment)*var.incrementModifier\n }\n var.minReps = state.targetMinReps\n var.reps = state.targetMaxReps\n var.firstSetProgType = var.PROG_TYPE_WEIGHT\n }\n else {\n var.reps = var.reps + 1\n var.firstSetProgType = var.PROG_TYPE_REPS\n }\n }\n \n /// Ensure weight is positive, Liftosaur doesn't seem to like negative values\n var.weight = var.weight >= 0lb ? var.weight : 0lb\n \n state.lastIncrement = roundWeight(var.weight) - completedWeights[var.set]\n if (state.lastIncrement < 0) {\n state.lastIncrement = 0lb\n }\n }\n \n /// Default is all sets will use same weight from set 1 and must be bewteen\n /// the minimum hypertrophy range reps up to the target rep range max\n weights = roundWeight(var.weight)\n minReps = var.MIN_HYP_REPS\n reps = state.targetMaxReps\n \n /// Set match or beat targets if weight was appropriate for target reps\n if (var.incrementModifier == 1) {\n minReps[var.set] = var.minReps\n reps[var.set] = var.reps \n }\n /// Otherwise, we've made a larger adjustment to the weight so set 1 uses the target\n /// rep range minimum as the bottom bound\n else {\n minReps[var.set] = state.targetMinReps\n /// Unilateral exercises use a separate set for each side so set 2 is also\n /// the \"first\" set for one side and should be set similarly\n if (state.type == var.TYPE_UNILATERAL && numberOfSets >= 2) {\n minReps[2] = state.targetMinReps\n }\n }\n }\n /// Repeat simpler logic for rest of the sets\n else {\n /// Only calculate changes for secondary sets if we had a normal increment based\n /// on set 1's performance\n if (var.progressDay) {\n if (var.hitReps) {\n var.reps = completedReps[var.set]\n var.minReps = var.reps\n var.todaysReps = var.reps\n \n if (state.progressType == var.PROG_TYPE_WEIGHT\n || var.reps >= state.targetMaxReps || var.firstSetProgType == var.PROG_TYPE_WEIGHT) {\n /// Fixed weight increments\n if (state.increment >= var.FIXED_WEIGHT_INCR_MIN) {\n var.weight = var.weight + state.increment\n }\n /// Percentage based increments\n else {\n var.weight = var.weight + (var.weight*state.increment)\n }\n \n /// If progressing by reps ensure the rep range target is set since weight has changed\n if (state.progressType == var.PROG_TYPE_REPS) {\n /// Unilateral exercise should use target rep range for 2nd set as well, otherwise hypertrophy range\n var.minReps = var.set == 2 && state.type == var.TYPE_UNILATERAL ? state.targetMinReps : var.MIN_HYP_REPS\n var.reps = state.targetMaxReps\n }\n }\n else {\n var.reps = var.reps + 1\n } \n }\n }\n \n var.weight = var.weight >= 0lb ? var.weight : 0lb\n \n /// Override default values set earlier so we can match/beat performance\n if (var.incrementModifier == 1) {\n if (completedWeights[var.set] != completedWeights[1]) {\n weights[var.set] = roundWeight(var.weight)\n }\n minReps[var.set] = var.minReps\n reps[var.set] = var.reps\n }\n \n /// Only set potentially different weight for a deload set if we are still\n /// using heavy weight for deload week. Otherwise, we'll just keep using the\n /// same weight from set 1 for all deload to avoid having to change weights.\n var.todaysWeight = state.deloadWeightRatio >= var.DELOAD_WEIGHT_RATIO_HEAVY ?\n completedWeights[var.set] : completedWeights[1]\n }\n\n /// Update deload week based on todays performance in case we deload early. We\n /// update the value for all days rather than just this day of the week since\n /// some exercises may change days during deloads\n weights[var.DELOAD_WEEK:*:*:*] = roundWeight(var.todaysWeight * state.deloadWeightRatio)\n minReps[var.DELOAD_WEEK:*:*:var.set] = floor(var.todaysReps * state.deloadRepsRatio)\n reps[var.DELOAD_WEEK:*:*:var.set] = floor(var.todaysReps * state.deloadRepsRatio)\n }\n }\n\n /// Ensure sets modifier is 0 so we don't add sets. Must be done before processing the\n /// rating since you may be rating this same exercise.\n state.setsModifier = 0\n \n if (state.progressType != var.PROG_TYPE_NONE) {\n if (var.progressDay) {\n state.numSets = numberOfSets/state.type\n }\n /// Do set progression if rating and target exercise values are set\n if (state.rating != 0 && state.rateGroup != 0 && state.numRatingExercises != 0) {\n /// Combine group + index to create full unique tag\n var.tag = state.rateGroup*100 + state.ratingIndex\n state[var.tag].setsModifier = state.rating\n state.ratingIndex = (state.ratingIndex + 1) % state.numRatingExercises\n }\n }\n\n /// RPE target for next session\n var.nextRpe = var.progressDay ? state.targetRpe + var.RPE_INCR : state.targetRpe\n var.nextRpe = var.nextRpe <= var.RPE_END ? var.nextRpe : var.RPE_END\n var.nextRpe = var.nextRpe >= var.RPE_START ? var.nextRpe : var.RPE_START\n state.targetRpe = var.nextRpe\n \n /// Calculate weight to start week 1 of next meso based on weight achieved today\n /// since we could deload early or do recovery weeks or whatnot and restart a meso\n /// at any time.\n /// Logic here just ensures the weight we pick keeps us in the target rep range\n /// for week 1 of the meso based on the last non-recovery weight and RIR/RPE we\n /// did.\n if (var.progressDay && var.hitReps == 1) { \n /// RIR value where we want to start the meso\n var.startRir = 10 - floor(var.RPE_START)\n /// Based on RPE of set 1 today we can convert to how many reps-in-reserve\n var.rir = 10 - ceil(RPE[1] > 0 ? RPE[1] : state.targetRpe)\n /// Calculate an estimate for maximum number of reps possible at todays weight.\n /// Add 1 rep to assume we adapt and get a little stronger after this session.\n /// i.e. Estimate how many reps would be 0 RIR or failure with todays weight\n var.estMaxRepsAfterRecovering = completedReps[1] + var.rir + 1\n \n /// Determine estimate for how many reps would correspond to the starting RIR\n /// i.e. how many reps would be the target given the RIR we want to start at\n var.startRepEstimate = var.estMaxRepsAfterRecovering - var.startRir\n\n /// Next, based on how many starting reps we estimated, determine how many\n /// increments to modify the weight to keep us within our target rep range\n /// for week 1 set 1.\n var.numIncrements = 0\n \n /// If estimated reps for a starting RIR set with todays weight would be higher\n /// than the target rep range we can increase weight by 1 increment for every rep\n /// above the target max since we assume that every increment drops about 1 rep\n /// worth of strength\n if (var.startRepEstimate >= state.targetMaxReps) {\n /// + 1 to ensure we land more inside in the target range and not exactly\n /// at the max reps\n var.numIncrements = (var.startRepEstimate - state.targetMaxReps) + 1\n }\n /// Otherwise, if starting RIR would be below the minimum reps we need to decrease the\n /// weight to ensure we get more reps next time to put us in the target rep range\n /// (numIncrements will be negative)\n else if (var.startRepEstimate <= state.targetMinReps) {\n /// - 1 to ensure we land more inside in the target range and not exactly\n /// at the min reps\n var.numIncrements = (var.startRepEstimate - state.targetMinReps) - 1\n }\n\n /// Set starting weight for next meso\n var.weight = roundWeight(completedWeights[1] + var.numIncrements*state.increment)\n weights[1:*:*:*] = var.weight >= 0lb ? var.weight : 0lb\n }\n\n state.mesoWeek += 1\n }\n /// Deload week is done, so reset start of meso targets\n else {\n state.mesoWeek = 1\n state.lastIncrement = 0lb\n state.ratingIndex = 0\n state.numSets = state.startNumSets\n state.setsModifier = 0\n state.targetRpe = var.RPE_START\n }\n\n /// Always ensure default state of keeping sets the same for related target exercise(s)\n state.rating = 0\n RPE[var.DELOAD_WEEK:*:*:*] = var.RPE_RECOVERY\n\n~}\n\nBench Press[1,1-3] / ...tLogic: Squat / 135lb / id: tags(10100) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 0, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nIncline Chest Fly[2,1-3] / ...tLogic: Squat / 25lb / warmup: none / id: tags(10101) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 301, ratingIndex+: 0, numRatingExercises: 2, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nTriceps Extension, Cable[3,1-3] / ...tLogic: Squat / 30lb / warmup: none / id: tags(10200) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 302, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nSeated Row, Leverage Machine[4,1-3] / ...tLogic: Squat / 100lb / id: tags(10300) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 10, targetMaxReps: 15, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 0, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nLat Pulldown[5,1-3] / ...tLogic: Squat / 100lb / warmup: none / id: tags(10301) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 10, targetMaxReps: 15, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 303, ratingIndex+: 0, numRatingExercises: 2, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nBicep Curl, Cable[6,1-3] / ...tLogic: Squat / 25lb / warmup: none / id: tags(10400) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 15, targetMaxReps: 20, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 304, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }","id":"jupyaavj"},{"name":"Day 2 - Lower A","exerciseText":"Calf Press on Leg Press[1,1-3] / ...tLogic: Squat / 200lb / warmup: 1x10 50%, 1x5 75% / id: tags(20500) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 8, targetMaxReps: 12, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 405, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nSquat[2,1-3] / ...tLogic: Squat / 200lb / id: tags(20600) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 406, ratingIndex+: 0, numRatingExercises: 2, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nSeated Leg Curl[3,1-3] / ...tLogic: Squat / 75lb / warmup: none / id: tags(20700) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 15, targetMaxReps: 20, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 407, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nLateral Raise, Cable[4,1-3] / ...tLogic: Squat / 15lb / warmup: none / id: tags(20800) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 408, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nCrunch, Cable[5,1-3] / ...tLogic: Squat / 40lb / warmup: none / id: tags(20900) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 8, targetMaxReps: 12, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 1, deloadSetsRatio: 1, rating+: 0, rateGroup+: 409, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }","id":"vbbohyeg"},{"name":"Day 3 - Upper B","exerciseText":"Pull Up[1,1-3] / ...tLogic: Squat / 180lb / id: tags(30300) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 0, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nBent Over Row[2,1-3] / ...tLogic: Squat / 100lb / warmup: none / id: tags(30301) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 103, ratingIndex+: 0, numRatingExercises: 2, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nPreacher Curl, EZ Bar[3,1-3] / ...tLogic: Squat / 50lb / warmup: none / id: tags(30400) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 104, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nIncline Bench Press, Smith Machine[4,1-3] / ...tLogic: Squat / 135lb / id: tags(30100) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 10, targetMaxReps: 15, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 0, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nChest Fly, Cable[5,1-3] / ...tLogic: Squat / 25lb / warmup: none / id: tags(30101) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 15, targetMaxReps: 20, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 101, ratingIndex+: 0, numRatingExercises: 2, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nTriceps Pushdown[6,1-3] / ...tLogic: Squat / 30lb / warmup: none / id: tags(30200) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 15, targetMaxReps: 20, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 102, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }","id":"jezqspnq"},{"name":"Day 4 - Lower B","exerciseText":"Romanian Deadlift, Barbell[1,1-3] / ...tLogic: Squat / 150lb / id: tags(40700) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 5, targetMaxReps: 10, startNumSets: 1, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 207, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 1, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nBulgarian Split Squat[2,1-3] / ...tLogic: Squat / 25lb / warmup: 1x8 0lb / id: tags(40600) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating: 0, rateGroup: 0, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nLeg Extension[3,1-3] / ...tLogic: Squat / 70lb / warmup: none / id: tags(40601) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 15, targetMaxReps: 20, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 206, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nStanding Calf Raise, Leverage Machine[4,1-3] / ...tLogic: Squat / 150lb / warmup: none / id: tags(40500) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 1, targetMinReps: 15, targetMaxReps: 20, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 205, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nLateral Raise[5,1-3] / ...tLogic: Squat / 15lb / warmup: none / id: tags(40800) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 15, targetMaxReps: 20, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 208, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }\n\nHanging Leg Raise[6,1-3] / ...tLogic: Squat / 0lb / warmup: none / id: tags(40900) / update: custom() { ...tLogic: Squat } / progress: custom(increment: 5lb, progressType: 2, targetMinReps: 10, targetMaxReps: 15, startNumSets: 2, type: 1, deloadWeightRatio: 0.6, deloadRepsRatio: 0.5, deloadSetsRatio: 0.5, rating+: 0, rateGroup+: 209, ratingIndex: 0, numRatingExercises: 1, lastIncrement: 0lb, numSets: 2, setsModifier: 0, mesoWeek: 1, targetRpe: 7) { ...tLogic: Squat }","id":"kpapcuzk"}],"id":"kwyxwosn"},{"name":"Accumulation","days":[{"name":"Day 1 - Upper A","exerciseText":"","id":"qzvpxinf"},{"name":"Day 2 - Lower A","exerciseText":"","id":"iajicjae"},{"name":"Day 3 - Upper B","exerciseText":"","id":"iboqwgyj"},{"name":"Day 4 - Lower B","exerciseText":"","id":"npgkpiza"}],"id":"hiiydqrd"},{"name":"Deload","days":[{"name":"Day 1 - Upper A","exerciseText":"","id":"ydogwryl"},{"name":"Day 2 - Lower A","exerciseText":"","id":"yyclpobi"},{"name":"Day 3 - Upper B","exerciseText":"","id":"uogmtrtu"},{"name":"Day 4 - Lower B","exerciseText":"","id":"xrdevysr"}],"id":"xbhagadg"}],"vtype":"planner"},"vtype":"program"},"version":"20250720120545","settings":{"timers":{"warmup":90,"workout":180,"reminder":900},"units":"lb"}},"shouldSyncProgram":false,"isMobile":false,"revisions":[]}