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. Delete Week Add New Week Duplicate Week
Week Description (Markdown)
Delete Week Description
Add Day Description
Delete Day
Add Day Description
Delete Day
Add Day Description
Delete Day
Add Day Description
Delete Day
Add Day
Week Stats Total Sets: 40
Strength Sets: 18, 45%
Hypertrophy Sets: 22, 55%
Upper Sets: 21 (10s , 11h ), 4d Lower Sets: 19 (8s , 11h ), 4d Core Sets: 0
Push Sets: 24 (10s , 14h ), 4d Pull Sets: 6 (3s , 3h ), 2d Legs Sets: 13 (5s , 8h ), 3d Shoulders: 14↓ (8s , 6h ), 3d Abs: 0↑
Hamstrings: 10↑ (4s , 6h ), 4d Quadriceps: 16↓ (7s , 10h ), 4d Forearms: 0↑
{"maxWidth":2400,"url":"/planner","isLoggedIn":false}
{"exportedProgram":{"customExercises":{"wxgoxjam":{"name":"Paused Bench Press, Barbell","types":["push","upper"],"id":"wxgoxjam","isDeleted":false,"meta":{"synergistMuscles":["Pectoralis Major Sternal Head","Triceps Brachii"],"targetMuscles":["Pectoralis Major Clavicular Head"],"bodyParts":[],"sortedEquipment":[]},"vtype":"custom_exercise"},"lwlmgozr":{"name":"Paused Squat, Barbell","types":["legs","lower","push"],"id":"lwlmgozr","isDeleted":false,"meta":{"synergistMuscles":["Hamstrings","Erector Spinae"],"targetMuscles":["Quadriceps"],"bodyParts":[],"sortedEquipment":[]},"vtype":"custom_exercise"}},"program":{"id":"jdzieise","name":"SBS 2.0 Last Set RIR + Hypertrophy Auxiliary","url":"","author":"","shortDescription":"","description":"","nextDay":1,"weeks":[],"isMultiweek":false,"days":[{"id":"eqyfziiw","name":"Day 1","exercises":[]}],"exercises":[],"tags":[],"deletedDays":[],"deletedWeeks":[],"deletedExercises":[],"clonedAt":1746106058674,"planner":{"name":"SBS 2.0 Last Set RIR + Hypertrophy Auxiliary","weeks":[{"name":"Week 1","days":[{"name":"Day 1","exerciseText":"t: Last Set RIR Update / used: none / 0x1 0lb / update: custom() {~\n\n// Week to intensity mapping\n if (week == 1) {\n var.intensity = 70\n } else if (week == 2) {\n var.intensity = 75\n } else if (week == 3) {\n var.intensity = 80\n } else if (week == 4) {\n var.intensity = 72.5\n } else if (week == 5) {\n var.intensity = 77.5\n } else if (week == 6) {\n var.intensity = 82.5\n } else if (week == 7) {\n var.intensity = 60\n } else if (week == 8) {\n var.intensity = 75\n } else if (week == 9) {\n var.intensity = 80\n } else if (week == 10) {\n var.intensity = 85\n } else if (week == 11) {\n var.intensity = 77.5\n } else if (week == 12) {\n var.intensity = 82.5\n } else if (week == 13) {\n var.intensity = 87.5\n } else if (week == 14) {\n var.intensity = 60\n } else if (week == 15) {\n var.intensity = 80\n } else if (week == 16) {\n var.intensity = 85\n } else if (week == 17) {\n var.intensity = 90\n } else if (week == 18) {\n var.intensity = 85\n } else if (week == 19) {\n var.intensity = 90\n } else if (week == 20) {\n var.intensity = 95\n } else if (week == 21) {\n var.intensity = 60\n } else {\n var.intensity = 60\n }\n\n weights[*] = (var.intensity/100) * 0.9 * rm1\n\n // Intensity → reps and RIR mapping\n if (var.intensity <= 50) {\n reps = 8\n RPE[*] = 3\n \n } else if (var.intensity <= 52.5) {\n reps = 8\n RPE[*] = 3\n \n } else if (var.intensity <= 55) {\n reps = 8\n RPE[*] = 3\n \n } else if (var.intensity <= 57.5) {\n reps = 8\n RPE[*] = 3\n \n } else if (var.intensity <= 60) {\n reps = 7\n RPE[*] = 3\n \n } else if (var.intensity <= 62.5) {\n reps = 7\n RPE[*] = 3\n \n } else if (var.intensity <= 65) {\n reps = 6\n RPE[*] = 3\n \n } else if (var.intensity <= 67.5) {\n reps = 6\n RPE[*] = 3\n \n } else if (var.intensity <= 70) {\n reps = 5\n RPE[*] = 3\n \n } else if (var.intensity <= 72.5) {\n reps = 5\n RPE[*] = 3\n \n } else if (var.intensity <= 75) {\n reps = 4\n RPE[*] = 2\n \n } else if (var.intensity <= 77.5) {\n reps = 4\n RPE[*] = 2\n \n } else if (var.intensity <= 80) {\n reps = 3\n RPE[*] = 2\n \n } else if (var.intensity <= 82.5) {\n reps = 3\n RPE[*] = 2\n \n } else if (var.intensity <= 85) {\n reps = 2\n RPE[*] = 1\n \n } else if (var.intensity <= 87.5) {\n reps = 1\n RPE[*] = 1\n \n } else if (var.intensity <= 90) {\n reps = 1\n RPE[*] = 1\n \n } else if (var.intensity <= 92.5) {\n reps = 1\n RPE[*] = 1\n \n } else if (var.intensity <= 95) {\n reps = 1\n RPE[*] = 1\n \n } else if (var.intensity <= 97.5) {\n reps = 1\n RPE[*] = 0\n \n } else if (var.intensity <= 100) {\n reps = 1\n RPE[*] = 0\n }\n~}\n\nt: Last Set RIR Progress / used: none / 0x1 0lb / progress: custom(rir_on_last_set+: 3, additional_overload: 0) {~\n\n if (completedNumberOfSets == 0) {\n rm1 = rm1\n \n } else if (completedNumberOfSets <= numberOfSets - 2) {\n rm1 = rm1 * 0.95\n \n } else if (completedNumberOfSets == numberOfSets - 1 || state.rir_on_last_set < RPE[1]) {\n rm1 = rm1 * 0.98\n \n } else if (state.rir_on_last_set == RPE[1]) {\n rm1 = rm1 * (1 + state.additional_overload)\n \n } else if (state.rir_on_last_set == RPE[1] + 1) {\n rm1 = rm1 * (1.005 + state.additional_overload)\n \n } else if (state.rir_on_last_set == RPE[1] + 2) {\n rm1 = rm1 * (1.01 + state.additional_overload)\n \n } else if (state.rir_on_last_set == RPE[1] + 3) {\n rm1 = rm1 * (1.015 + state.additional_overload)\n \n } else if (state.rir_on_last_set == RPE[1] + 4) {\n rm1 = rm1 * (1.02 + state.additional_overload)\n \n } else if (state.rir_on_last_set >= RPE[1] + 5) {\n rm1 = rm1 * (1.03 + state.additional_overload)\n }\n~}\n\n\nt: Hypertrophy Update / used: none / 0x1 0lb / update: custom() {~\n\n// Week to intensity mapping\n if (week == 1) {\n var.intensity = 65\n } else if (week == 2) {\n var.intensity = 67.5\n } else if (week == 3) {\n var.intensity = 75\n } else if (week == 4) {\n var.intensity = 67.5\n } else if (week == 5) {\n var.intensity = 70\n } else if (week == 6) {\n var.intensity = 72.5\n } else if (week == 7) {\n var.intensity = 55\n } else if (week == 8) {\n var.intensity = 67.5\n } else if (week == 9) {\n var.intensity = 70\n } else if (week == 10) {\n var.intensity = 72.5\n } else if (week == 11) {\n var.intensity = 70\n } else if (week == 12) {\n var.intensity = 72.5\n } else if (week == 13) {\n var.intensity = 75\n } else if (week == 14) {\n var.intensity = 55\n } else if (week == 15) {\n var.intensity = 70\n } else if (week == 16) {\n var.intensity = 72.5\n } else if (week == 17) {\n var.intensity = 75\n } else if (week == 18) {\n var.intensity = 72.5\n } else if (week == 19) {\n var.intensity = 75\n } else if (week == 20) {\n var.intensity = 77.5\n } else if (week == 21) {\n var.intensity = 55\n } else {\n var.intensity = 60\n }\n\n weights[*] = (var.intensity/100) * 0.9 * rm1\n\n // Intensity → reps and RIR mapping\n if (var.intensity <= 50) {\n reps = 20\n reps[numberOfSets] = 25\n }\n\n else if (var.intensity <= 52.5) {\n reps = 18\n reps[numberOfSets] = 23\n }\n\n else if (var.intensity <= 55) {\n reps = 17\n reps[numberOfSets] = 21\n }\n\n else if (var.intensity <= 57.5) {\n reps = 15\n reps[numberOfSets] = 19\n }\n\n else if (var.intensity <= 60) {\n reps = 14\n reps[numberOfSets] = 18\n }\n\n else if (var.intensity <= 62.5) {\n reps = 13\n reps[numberOfSets] = 16\n }\n\n else if (var.intensity <= 65) {\n reps = 12\n reps[numberOfSets] = 15\n }\n\n else if (var.intensity <= 67.5) {\n reps = 11\n reps[numberOfSets] = 13\n }\n\n else if (var.intensity <= 70) {\n reps = 10\n reps[numberOfSets] = 12\n }\n\n else if (var.intensity <= 72.5) {\n reps = 9\n reps[numberOfSets] = 11\n }\n\n else if (var.intensity <= 75) {\n reps = 8\n reps[numberOfSets] = 10\n }\n\n else if (var.intensity <= 77.5) {\n reps = 7\n reps[numberOfSets] = 9\n }\n\n else if (var.intensity <= 80) {\n reps = 6\n reps[numberOfSets] = 8\n }\n\n else if (var.intensity <= 82.5) {\n reps = 5\n reps[numberOfSets] = 6\n }\n\n else if (var.intensity <= 85) {\n reps = 4\n reps[numberOfSets] = 5\n }\n\n else if (var.intensity <= 87.5) {\n reps = 3\n reps[numberOfSets] = 4\n }\n\n else if (var.intensity <= 90) {\n reps = 2\n reps[numberOfSets] = 3\n }\n\n else if (var.intensity <= 92.5) {\n reps = 2\n reps[numberOfSets] = 2\n }\n\n else if (var.intensity <= 95) {\n reps = 2\n reps[numberOfSets] = 2\n }\n\n else if (var.intensity <= 97.5) {\n reps = 1\n reps[numberOfSets] = 1\n }\n\n else if (var.intensity <= 100) {\n reps = 1\n reps[numberOfSets] = 1\n }\n\n~}\n\nt: Hypertrophy Progress / used: none / 0x1 0lb / progress: custom(additional_overload: 0) {~\n\n if (completedNumberOfSets <= numberOfSets - 2) {\n rm1 = rm1 * 0.95\n \n } else if (completedNumberOfSets == numberOfSets - 1 || completedReps[numberOfSets] < reps[numberOfSets]) {\n rm1 = rm1 * 0.98\n \n } else if (completedReps[numberOfSets] == reps[numberOfSets]) {\n rm1 = rm1 * (1 + state.additional_overload)\n \n } else if (completedReps[numberOfSets] == reps[numberOfSets] + 1) {\n rm1 = rm1 * (1.005 + state.additional_overload)\n \n } else if (completedReps[numberOfSets] == reps[numberOfSets] + 2) {\n rm1 = rm1 * (1.01 + state.additional_overload)\n \n } else if (completedReps[numberOfSets] == reps[numberOfSets] + 3) {\n rm1 = rm1 * (1.015 + state.additional_overload)\n \n } else if (completedReps[numberOfSets] == reps[numberOfSets] + 4) {\n rm1 = rm1 * (1.02 + state.additional_overload)\n \n } else if (completedReps[numberOfSets] >= reps[numberOfSets] + 5) {\n rm1 = rm1 * (1.03 + state.additional_overload)\n }\n~}\n\nSquat[1-21] / 5x5 70% @3 / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom(rir_on_last_set+: 3, additional_overload: 0) { ...t: Last Set RIR Progress }\n\nPaused Bench Press, Barbell[1-21] / 3x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom(additional_overload: 0) { ...t: Hypertrophy Progress }\n\nDeficit Deadlift[1-21] / 3x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom(additional_overload: 0) { ...t: Hypertrophy Progress }\n","id":"uqyythvn"},{"name":"Day 2","exerciseText":"Bench Press[1-21] / 5x5 70% @3+ / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom() { ...t: Last Set RIR Progress }\n\nHack Squat[1-21] / 5x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom() { ...t: Hypertrophy Progress }\n\nPush Press, Barbell[1-21] / 4x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom() { ...t: Hypertrophy Progress }\n","id":"mygloans"},{"name":"Day 3","exerciseText":"Overhead Press[1-21] / 5x5 70% @3 / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom() { ...t: Last Set RIR Progress }\n\nPaused Squat, Barbell[1-21] / 3x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom() { ...t: Hypertrophy Progress }\n","id":"bfoabecw"},{"name":"Day 4","exerciseText":"Deadlift[1-21] / 3x5 70% @3 / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom(rir_on_last_set+: 4) { ...t: Last Set RIR Progress }\n\nBench Press Close Grip[1-21] / 4x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom() { ...t: Hypertrophy Progress }\n","id":"hqhqchgz"}],"description":"# SBS 2.0 Last Set Reps in Reserve + Hypertrophy Auziliary Program\n\n\n## How to make a program\n\n\nTo add a lift to your program, you will need to both provide a \"progress\" and an \"update\" script from the given templates. There is one each for RIR and Hypertrophy. So for the main lifts, you would use something like:\n\n\n```\nBench Press[1-21] / 5x5 / 70% @3 / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom() { ...t: Last Set RIR Progress }\n```\n\n\nand for an auxiliary, use:\n\n\n```\nHack Squat[1-21] / 5x10 / warmup: none / update: custom() { ...t: Hypertrophy Update } / progress: custom() { ...t: Hypertrophy Progress }\n```\n\n\nThe number of _sets_ specified in the lift's definition will be the number of sets used by the program. However the number of reps will be determined by the `update` script. So you will need to select how many sets you'll do for each, but the reps will change from week to week, automatically.\n\n\nIf you want to change the adjustment to training max when you exceed the target RIR or the rep out target, pass the `additional_overload` parameter to the progress script.The value given will be the extra percent increase to 1rm, so it should be a fraction like: 0.0025 would at 0.25% to the table in the Quick Setpup script in the original program sheet.\n\nFor the back and accessories, add whatever you like using whatever progression you like. The example here is a 4-day program, but this will adapt to any number of days.\n\n```\nBench Press[1-21] / 5x5 / 70% @3 / warmup: none / update: custom() { ...t : Last Set RIR Update } / progress: custom(additional_overload: 0.00025) { ...t: Last Set RIR Progress }\n```\n\nThis works on an lift-by-lift basis. So you can adjust this differently for each lift.\n\n\n## How to track\n\n\nLogging workouts should be straightforward but with one catch: what the App call RPE, the program uses at RIR. So if the app shows a target RPE of 3, this is actually a target *RIR* of 3.When you do your last set, you'll be prompted for you RIR.\n\n\n## How it works\n\nThe way it works is that the `update` script checks the program week and selects the intensity as given in the orignial program table in the Quick Setup tab.\n\nThe intesnisty is then mapped to a number of reps and either a rep out target or a target RPE. The weight is specificed as the `intensity x training max`, which is hard-coded as `0.9 * 1rm`. The progress script will update the 1rm depending on the number of sets and reps completed and the RIR or rep-out hit in the final set.\n\nIf you want to tune the program further, for example, changing the number of reps for a given intensity for only one lift, you'd have to make a copy of the update script to use for just that lift and edit those values directly.","id":"rgzdmhad"},{"name":"Week 2","days":[{"name":"Day 1","exerciseText":"","id":"levhhbpf"},{"name":"Day 2","exerciseText":"","id":"ntraehqa"},{"name":"Day 3","exerciseText":"","id":"jxsjkwbw"},{"name":"Day 4","exerciseText":"","id":"volkppyj"}],"id":"gdohcgks"}],"vtype":"planner"},"vtype":"program"},"version":"20260304084247","settings":{"timers":{"warmup":90,"workout":120,"reminder":900},"units":"lb"}},"shouldSyncProgram":false,"isMobile":false,"revisions":[]}