Open-source project
astashov/liftosaur avatar
astashov/liftosaur

Liftosaur, a weightlifting tracker where the program is a program

Weightlifting tracker app for coders

759 stars127 forksTypeScriptAGPL-3.0

At a glance

What is it?
astashov/liftosaur is a progressive web app for tracking barbell training whose distinguishing feature is Liftoscript, a small JavaScript-like language that expresses the progression and deload logic behind each exercise, so any program from 5/3/1 to a bespoke scheme can be written rather than picked from a menu. It is AGPL-3.0 licensed and works offline.
Who is it for?
Adopt Liftosaur if you follow a structured program and want to adjust its progression rules yourself rather than accept the settings a tracker offers, and you are happy with a browser app that works offline. Skip it if you want a simple log of sets and weights, because the scripting layer is more than you would use.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The idea: the program is code, not a settings page

Liftosaur is an open source weightlifting tracker PWA for coders, and the main idea is stated as making a tracker flexible enough to implement pretty much any weightlifting routine. The framing is that it would be a platform for your experiments in weightlifting, so you can try any progression and deloading logic to see what suits you better, and it handles progressive overloads and deloads automatically from the logic you define.

What makes that possible is a built-in scripting language called Liftoscript, described as a very simple programming language with JavaScript-like syntax, with built-in variables and custom number types such as kg and lb. The README gives the Stronglifts 5x5 logic as an example:

js
if (completedReps >= reps) {
  state.weight = state.weight + 5lb
} else {
  state.failures = state.failures + 1
}
if (state.failures > 2) {
  state.failures = 0
  state.weight = state.weight * 0.9
}

That snippet is the whole design in miniature. The weight goes up by five pounds when the reps are hit, a failure is counted, and more than two failures trigger a ten percent deload. There is no progression wizard, no dropdown of rules and no preset that partly matches what you want. The logic is the program, written in a language that a developer already reads.

The named programs the app ships with are 5/3/1, GZCLP and Starting Strength among others, and the README is explicit that any program should be possible to implement, whether it is 5/3/1, GZCLP, any 5/3/1 variant or a push-pull-legs split. Every program in the app is written in Liftoscript, so every part of it can be changed.

For anyone who does not want to write code, there is a simple exercise editor that still allows simple progression and deload logic, and an advanced editor for the full language. The README describes the simple one as the way to avoid messing with Liftoscript and the advanced one as unleashing the full power of it.

The feature list and the parts that are unusual

Beyond the scripting, the feature list has a few items that are worth calling out because they are not what a tracker normally does.

The plates calculator is on the progress screen. Each weight is prefixed with the plates needed to reach it, shown as 45/25/25/10 255lb, meaning one 45 pound plate, two 25 pound plates and one 10 pound plate on each side of the bar. You define your plate inventory in Settings, and all weights are rounded according to the bars and plates you have set up, so the app never suggests a weight you cannot physically load.

The muscle map shows which muscles get activated on a given day or across the whole program, relative to each other, and exercise substitution is based on similar activated muscles. That is a way of answering the question of what to do when an exercise is temporarily unavailable.

Playgrounds are the other distinctive one. When editing an exercise you can test the logic, and each program has a preview with a playground, so you can see what a program would actually do before you commit to it. The README links a Basic Beginner Routine preview as an example.

Then there are the features you would expect and a few you would not. Workout history, offline mode that needs no internet, and cloud storage if you create an account. Graphs you define yourself. Warmup sets configurable as a percentage of the first set's weight or as an absolute value, with per-exercise defaults. Rest timers configurable globally and per exercise, with a push notification when the timer expires, which works only on the native apps. Bodyweight and other measurements such as biceps, chest and waist, with the ability to correlate bodyweight changes against lift graphs. Custom exercises. A web editor for creating programs. Shareable programs, where you build one, generate a link and import it on another phone. And an optional public profile page.

One small feature is a good illustration of the tone: if you did a similar set of reps for an exercise previously, it shows your last results, and the same for AMRAPs.

How it is built and how it runs locally

The app is a regular Preact and TypeScript application. The state manager is custom, described as similar to Redux plus thunks but using lens-shmens to avoid Redux-like boilerplate. It is a PWA with a simple service worker that caches the network calls, and the setup is described in a blog post on the site about offline mode.

The author is explicit about the size budget: the whole app weighs about 200 kilobytes, of which about 100 are third-party libraries, and the third-party list is deliberately short. CodeMirror is the code editor, Preact is the view layer, Prism does the syntax highlighting, uPlot draws the graphs, Rollbar handles error reporting, 11ty builds the blog, Cypress runs the integration tests and Tailwind handles the CSS. Jimp is there to generate the dynamic og:image images used for social media, such as the profile image.

For RPE multiplier calculations the app uses a formula from the OpenPowerlifting source, which is a nice detail: the numbers follow an existing standard rather than being invented locally.

The server side is AWS Lambda with DynamoDB and S3 and a number of other AWS services. The author is candid that DynamoDB is not a great choice for this app and that a relational database would be preferable, but the combination is cheap, easily scalable, fully managed and has backups, so it is being kept for now. Deployment is through AWS CDK, and there is a blog post about moving the project from Cloudflare Workers to Lambda, plus a separate AWS CDK Lambda TypeScript starter repository to make it easier to set up a similar environment for other projects.

Running it locally is straightforward for the front end. You need Node 18 and npm, you comment out the devServer block from the webpack.config.js file, then run npm install and npm start, and open http://localhost:8080/app. The README is honest that this gives you an offline-like experience with no local API server, and that running the server is trickier and still tied to the liftosaur.com domain, so you would need to modify a good deal in the liftosaur-cdk/liftosaur-cdk.ts file.

That last point is the honest boundary of the project for a self-hoster. The client is fully usable locally and offline, and the account-backed server is not something you can simply point at your own infrastructure without work.

The app surfaces, the licence and what to weigh

The same codebase is shipped in three forms. The PWA is the base, reachable in a browser and installable to a home screen so it behaves like a regular app. The Android app is a thin wrapper around that PWA with some native features added, and the iOS app is a thin wrapper with some native features added. The native parts that matter are the ones the web platform cannot do, and the README names one: the rest timer push notification only works on the native apps.

The licence is AGPL-3.0, and for a self-hosted app the practical question is whether you intend to modify and serve it to others. The program files are Liftoscript and the exercise logic is data in the app, so a shared program is a link, not a fork, and that is the mechanism the README describes for the shareable programs feature.

The repository layout is large and shows the two halves of the project side by side. There is an android/ directory and an ios/ directory for the native wrappers, a lambda/ directory for the server functions, a liftosaur-cdk/ directory for the infrastructure, a blog/ directory, a docs/ directory, an assets/ directory, fonts/, images/ and icons/. There are also some less obvious files that explain the project: liftoscript.grammar, which is a grammar definition for the scripting language, logic.txt, a .cursor-adjacent llms/ directory, an aihelpers/ directory, an openai-apps-challenge directory, a WRITING.md, a PROSE.md and a COMMUNITIES.md. The liftoscript.grammar file is the clearest signal of intent, because it means the language is meant to be edited in a text editor with syntax highlighting, not only inside the app's CodeMirror instance.

The comparison to make is with the trackers people usually use, which are apps with settings for progression increments and deload triggers. Those are easier to start with and they cover the common programs. What they do not do is let you express a rule the settings do not cover, and they cannot be checked before you start a cycle. Liftosaur's cost is that you now maintain a program, which is a real ongoing effort for a training plan.

The case for it is that training logic is genuinely a program, and the people who think in programs are the people who write them. The case against is that an app whose main feature is a scripting language has a higher floor for a beginner than one with a dropdown.

Editorial conclusion

Adopt Liftosaur if you follow a structured program and want to adjust its progression rules yourself rather than accept the settings a tracker offers, and you are happy with a browser app that works offline. Skip it if you want a simple log of sets and weights, because the scripting layer is more than you would use. Verify first by opening a built-in program in the exercise editor, changing the progression, and running the preview before you commit it to your training.

Frequently asked questions

What is Liftoscript and what does it do?

It is a built-in scripting language with JavaScript-like syntax that expresses the progression and deload logic behind each exercise, with built-in variables and custom number types such as kg and lb. The README shows Stronglifts 5x5 logic written in it, and every built-in program in the app is written this way.

In what forms is the Liftosaur app available?

As a PWA you open in a browser and add to your home screen, as a thin Android app wrapping that PWA with some native features added, and as a thin iOS app with the same arrangement. The rest timer push notification is one of the features that only works on the native apps.

How do I run Liftosaur locally?

With Node 18 and npm installed, comment out the devServer block in the webpack.config.js file, then run npm install and npm start and open http://localhost:8080/app. The README notes this gives an offline-like experience with no local API server, and that running the server is still tied to the liftosaur.com domain.

What does the plates calculator in Liftosaur do?

It prefixes each weight with the plates needed to reach it, shown as 45/25/25/10 255lb for one 45 pound, two 25 pound and one 10 pound plate on each side of the bar. You define your plate inventory in Settings and all weights are rounded to the bars and plates you have.

What licence is Liftosaur released under, and what are its dependencies?

AGPL-3.0. Its third-party libraries are CodeMirror, Preact, Prism, uPlot, Rollbar, 11ty, Cypress, Tailwind CSS and Jimp, with the whole app weighing about 200 kilobytes of which about 100 are third-party code.

Official sources

  1. astashov/liftosaur on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/astashov-liftosaur.svg)](https://hysenlabs.com/projects/astashov-liftosaur)

Was this useful?