Starting off the Weekend Warrior series, we have a project that fits well with the quarantine times – a bootleg workout generator!

Endorphins: A Bootleg Workout Generator

Back in October (God, that feels like an eternity ago), a friend, looking to reclaim her fitness glory, asked me to write her workouts. Unfortunately for her, focusing was not something that I did well in 2019, so it took me many months and pandemic for me to get around to it. At the start, I had a long list of exercises, categorized by muscle group, and was handcrafting each workout plan, but after writing a couple, I decided to just build a tool to empower anyone keen on improving or maintaining their fitness during quarantine to create balanced yet challenging workouts.

Given that gyms and athletic facilities were closed nationwide, an interesting set of problems became clear:

  • Workouts need to be done at home.
  • People have limited access to workout equipment.
  • People of all fitness levels have been affected.
  • Users can have zero technical expertise.

Projecting Time: 16 hours for research/implementation + way too long for blog post

Generating well-rounded workouts

Looking at the first two requirements above, we realize that the only exercises that require minimal space and equipment are body weight exercises. The latter requirements speak towards user needs for tool flexibility (can generate workouts of varying difficulty) and usability (friendly ux for everyone), elements heavily considered during development.

If you just want to workout, hop on over to the project!


For the first iteration, I focused primarily on crafting a generic workout and the tool’s usability. The tool can be broken down into three different parts – the exercises, the workout builder, and the user support.

The Exercise List

Building well-rounded workouts requires a well-rounded selection of exercises. For v1, I listed every single body weight exercise I could think of and sorted them into three categories – core, legs, and upper body. The schema for each exercise is as follows:

type Exercise struct {
  name string
  description string // brief explanation of exercise if necessary
  difficulty string // easy, medium, hard
  reps int
  duration, rest int // for exercises like plank/wall sits

// exercises.json
    "core": [Exercise], 
    "legs": [Exercise], 
    "upper body": [Exercise],

The difficulty for each exercise is based on how long it will take to complete the provided number of reps and the physical difficulty of the exercise.

Building a Workout

One school of thought for building workouts is to focus on individual muscle groups, but because I am targeting the average human seeking wholistic fitness improvement, I decided to have workouts always include exercises from each of the three muscle groups. A important feature to highlight is the ability for the user to provide a desired workout DURATION, ranging from 30 - 120 minutes. Another cool feature is the idea of a focus group. The muscle group that the user spends the most time on will be the focus group for that workout. Underneath the hood, the implementation is pretty simple:

  1. Load first sets of exercises. Exercises are randomly sampled from each category in the exercise.json file provided.
  2. Until the estimated time to complete the sampled exercises is within a small window of DURATION, the tool will continue to add sets for existing exercises or randomly sample new ones.
  3. Write all exercise information out to a formatted PDF.

At first, I didn’t like the idea of randomly sampling exercises just for the sake of simplicity, but I think that forcing the user exercise across multiple muscle groups is better than allowing the user to control which muscle groups they want to target. People tend to favor training muscles that are already strong over working their weaknesses.

Thinking about UX

Anyone and everyone should be able to workout. To generate a workout, all someone has to do is run make install to install the necessary dependencies (brew, Python, etc.) and make workout to create a workout. The tool will collect each workout in a workout folder and automatically open the generated PDF for you. Assuming users have some basic technical skills, they can immediately view the workout and look back at workouts they’ve already completed.


The second iteration introduced workout Levels and some UX improvements. Having the tool generate workouts of varying difficulty enables people of all athletic levels to follow these workouts and also empowers them to use the tool as a long term fitness solution. The tool supports levels from 1 - 5, where 1 is the easiest level and 5 is the hardest. [Disclaimer: Level 5 is actually really hard, haha yikes.] In my opinion, the levels are the tool’s greatest asset. People pay loads of money for personal trainers or other fitness apps since they don’t have the faintest clue about how to properly train incrementally.

Updating the Exercises

I could’ve gone ahead and built an intelligent level curator, but instead, I took a more manual approach and hand crafted each level. The handy copy+paste replicated the sets of exercises across the five levels; the number of reps shifted up and down based on their level. Unfortunately, this produces half-assed results at best. The set of exercises I had in the v1 had glaring problems. It assumed that everyone could do all the exercises and had a poor spread of difficulty among exercises within each category. Some people who tested the v1 said that the legs and core portions of the workout were much easier than the upper body section and would often skip the upper body portion altogether – a suboptimal use of the tool.

Workouts should push people outside of their comfort zone, but not be difficult to the point of discouragement. With levels, we can fix this problem by having exercises between levels form a progression of difficulty. The most notable progression is one with pushups. The average person’s lower body strength far exceeds their upper body, so the lower levels should account for that. Below is an example of the push-up progression:

  • Level 1: Push-ups on knees
  • Level 2: More reps of push-ups on knees
  • Level 3: Regular push-ups
  • Level 4: More reps of regular push-ups
  • Level 5: Harder varities of push-ups (diamond, wide, etc.)

Equally as important as the exercise progressions was the improvement to exercise breadth within each category. Since we’re constrained to body weight exercises, upper body exercises boil down to push-ups and leg exercises boil down to squats. However, with some creativity and research, the exercise lists included both static and dynamic exercises and that collectively covered more muscle groups. In the end, without equipment, its impossible to properly hit some muscle groups, but its quite surprising to see how you can still train wholistically with your body and some everyday items.

You can find the exercises for each level here!

Minor Improvements

A notable minor improvement was updating the workout generation process to pull updates from Github. Non-technical users have a hard time using git, so now, the tool automatically git pull’s if necessary.

Sample Workout

Here is a sample workout with defaults enabled:

Sample Endorphins WorkoutSample workout that looks a lot like the swim workouts my coach used to write

Feel free to check out the final workout samples of all level’s here!

Personal Takeaways

  • Accommodating many athletic levels was much harder than I thought
  • Python dependencies are a struggle
  • Climbing has made my legs awfully weak
  • I should not take my athleticism for granted

If you want to get fit at home, please give Endorphins a try! And, if you have a questions about the tool, just shoot me a dm on twitter!

Cover photo: two friends getting strong in the desert