# openGym **Repository Path**: Super_Rainbow/openGym ## Basic Information - **Project Name**: openGym - **Description**: No description available - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-21 - **Last Updated**: 2026-08-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
openGym
**A self-hosted gym & body-weight tracker you actually own.** Plan your week, run guided workouts, track every set and your body weight over time β€” on your phone, synced across devices, behind your own passkey login. No account on someone else's server, no subscription, no ads. Just `docker compose up`.
[![License: AGPL v3](https://img.shields.io/badge/license-AGPL--3.0-a3e635?style=flat-square)](LICENSE) ![Self-hosted](https://img.shields.io/badge/self--hosted-%F0%9F%8F%A0-60a5fa?style=flat-square) ![PWA](https://img.shields.io/badge/PWA-installable-a78bfa?style=flat-square) ![React](https://img.shields.io/badge/React-19-38bdf8?style=flat-square&logo=react&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-compose-2496ED?style=flat-square&logo=docker&logoColor=white) ![No tracking](https://img.shields.io/badge/telemetry-none-f472b6?style=flat-square)
![GitHub last commit](https://img.shields.io/github/last-commit/DuarteSantos8/openGym?style=flat-square) [![GitHub stars](https://img.shields.io/github/stars/DuarteSantos8/openGym?style=flat-square)](https://github.com/DuarteSantos8/openGym/stargazers) [![GitHub issues](https://img.shields.io/github/issues/DuarteSantos8/openGym?style=flat-square)](https://github.com/DuarteSantos8/openGym/issues)

Home
Home β€” today's workout & weight
Workout
Guided workout β€” animated demos & sets
Stats
Stats β€” heatmap, charts & PRs
### [🌐 opengym.duarte-santos.ch](https://opengym.duarte-santos.ch) Β· [β–Ά Try the live demo](https://duartesantos8.github.io/openGym/) No signup, nothing to install β€” it runs entirely in your browser on example data.
There's no server behind the demo, so passkey sign-in, sync across devices and the admin dashboard only exist in a self-hosted instance.
## Why Most workout apps lock your data behind a login on their servers, nag you to upgrade, or disappear when the startup does. openGym is the opposite: **it runs on your box, your data stays in a folder you control, and it's yours to fork.** It still feels modern β€” installable as a home-screen app, passkey sign-in, offline support, sync across your phone and laptop. ## Features - βš–οΈ **Body-weight tracking** β€” interactive chart with a goal line you set, gains/losses colored by whether they move toward it - πŸ‹οΈ **Weekly plan** β€” a routine per weekday, over a library of **1,324 exercises** (searchable, with animated demos) - πŸ—“οΈ **Reschedule any day** β€” sick, missed a session, or fewer gym days this week? Move a workout to another day without touching your weekly plan - ▢️ **Guided workouts** β€” it knows what day it is and starts today's session; asks your body weight first, pre-fills your weights from last time, rest timer, PR detection, per-exercise weight tracking - β˜€οΈ **The screen stays awake while you train** β€” no unlocking the phone and finding your place again between every set. On for as long as a workout is running, released the moment you finish it, and switchable off in Settings - πŸ”— **Supersets** β€” build them, and log them back-to-back with a rest only after the pair - ⏱️ **Timed exercises** β€” planks, hangs, wall sits and loaded carries are logged by time, not reps, with a work timer that counts the set itself (separate from the rest timer) and logs the time you actually held. They can carry weight too - πŸ“ˆ **Progression that follows a rule** β€” pick one per routine, override it per exercise: linear, **Greyskull LP** (AMRAP top set, double jumps, 10 % resets), double progression through a rep range, or adding time. Your weights are already right when the session opens, and every target says *why* it's that number. Missed reps never advance the load, stalls trigger a deload, and bodyweight exercises progress in reps instead - πŸ’ͺ **Estimated 1RM** β€” per exercise, from your best eligible set (it names which one), with its own progress curve and a calculator for sets you haven't done. Won't guess above 12 reps - 🎯 **Effort per set, in your scale** β€” an optional third column rating how hard a set was, as **RIR** (reps left in the tank) or **RPE** (the same judgement on a 10-point scale). Off by default; each set keeps the scale it was logged with, and nothing else reads the value β€” your progression and 1RM are unaffected - πŸ’ͺ **Bodyweight exercises, logged as bodyweight** β€” push-ups, pull-ups, dips and 300-odd others arrive knowing they carry no load, so there's no weight column and no working-weight prompt: one stepper, log the reps. Add a dip belt and it reads as an addition, and progression goes back to following the weight. Without one, reps climb β€” and past a ceiling you set, a set is added instead of a rep, up to the point where the honest advice is load or a harder variation - ↔️ **Reps per side** β€” for lunges, single-arm rows and the rest. You log the total, the app shows the split ("8 per side"), and the target steps in twos so it never lands on a number one side can't have - πŸƒ **Cardio** β€” log time + speed, not just weight Γ— reps - πŸ“€ **Share a plan** β€” send someone your routines and week schedule as a small file (no workouts, no weigh-ins), or print it as a clean PDF. Importing merges, so their plan is never overwritten - πŸ”§ **Filter by equipment** β€” narrow the library to what you actually own; the options adapt to what you've picked, so every combination on screen has results behind it - ✨ **Your own exercises** β€” a name and a body part is enough; they behave like built-in ones everywhere, with an optional description instead of an animation - 🟩 **Activity heatmap** β€” a GitHub-style year view, shaded by time spent training - πŸ’ͺ **Muscle map** β€” a front-and-back body diagram shaded by how much work each muscle got, over a week, a month or all time. It names the muscles you *haven't* trained in that period, previews what a routine hits while you build it, and shows what you just trained when you finish. Male or female figure, your pick - πŸ”” **Push notifications** β€” rest-timer alerts even with the app closed, plus an optional reminder on days you have a workout planned but haven't logged one. Opt in per profile; keys are generated on first run, nothing to configure - πŸ”‘ **Passkeys, not passwords** β€” Face ID / Touch ID / fingerprint login; each profile keeps its own data, synced across devices - πŸ› οΈ **Admin dashboard** (optional) β€” for whoever runs the instance: who's training right now, per-user history, disable accounts, and invite-only signup. Off by default, so a fresh instance stays open with no admin - 🎨 **Designed, not assembled** β€” light/dark themes and 8 accent colors saved to your profile, over a hand-drawn icon set instead of emoji, so it looks the same on every phone - 🌍 **12 languages** β€” full UI translation (EN, DE, ES, FR, IT, PT, PL, TR, RU, ZH, KO, HI); exercise instructions localized in 10 of them, loaded on demand so the app stays fast - πŸ“₯ **Bring your history with you** β€” import from **FitNotes** (Android and iOS), **Strong** and **Hevy**, or body weight straight out of an **Apple Health** export. Exercise names are matched against the library and anything unrecognised becomes one of your own exercises, so nothing in the file is dropped - πŸ“¦ **Yours to keep** β€” one-tap JSON export/import, guest mode, **no telemetry** - πŸ“± **Standalone Android app** β€” the whole tracker as a sideloadable APK: no account, no server, data on the phone, native workout reminders ([download](https://opengym.duarte-santos.ch)) ## Quick start (self-host) You need [Docker](https://docs.docker.com/get-docker/) with Compose. ```bash git clone https://github.com/DuarteSantos8/openGym cd openGym cp .env.example .env docker compose pull # grab prebuilt images (amd64 + arm64) β€” skip to build from source instead docker compose up -d ``` Open **http://localhost:8080**, tap **Create profile**, and you're in. First launch downloads the exercise media (~140 MB) once. Prefer building the images yourself instead of pulling from `ghcr.io`? Drop the `pull` step and run `docker compose up -d --build` β€” you don't need Node or a build step locally either way. > Want it reachable from your phone over the internet with passkeys? You'll need an HTTPS > domain β€” a two-line change in `.env`. See **[docs/SELF_HOSTING.md](docs/SELF_HOSTING.md)**. ## Mobile app (no server at all) The same codebase also builds a **standalone mobile app** (Capacitor): no account, no sync, no backend β€” everything stays on the phone, with native workout-day reminders and share-sheet backups. Self-hosting gets you multi-device sync and profiles for friends & family; the mobile app is the install-and-done flavor. - **Android:** [**download the APK**](https://opengym.duarte-santos.ch) and sideload it β€” openGym is deliberately not on the Play Store. Or build it yourself: **[docs/MOBILE.md](docs/MOBILE.md)**. - **iPhone:** Apple doesn't allow installing apps outside the App Store, so there is no iOS download. Self-host and add it to your home screen from Safari (it's a full PWA), or build the native app onto your own device from Xcode β€” see **[docs/MOBILE.md](docs/MOBILE.md)**. ## How it works ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Your phone │──HTTPS─▢│ web (nginx) β”‚ β”‚ / laptop β”‚ β”‚ β”œβ”€ serves the built app β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ └─ proxies /api ──────────┐│ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ api (Node + WebAuthn) β”‚ β”‚ └─ ./data (JSON files) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` - **frontend/** β€” React + Vite (React Router + Zustand), built to static files **inside Docker** - **api/** β€” Node with no framework, one dependency (`@simplewebauthn/server`), storing everything as plain JSON files under `./data` - **web/** β€” a multi-stage image that builds the frontend and serves it with nginx, proxying `/api` to the backend so it's all on **one origin** (passkeys require this) ## Your data Lives in `./data` on your host: `db.json` (profiles + public passkeys), `state-.json` (each user's plan, workouts, body weight, settings), and `secret` (the session-cookie key). **Back up `./data` and you've backed up everything.** Passkey private keys never touch the server β€” they stay in your phone's secure hardware / your password manager. ## Configuration All via `.env` (see `.env.example`): | Variable | What it is | Default | |---------------|------------------------------------------------------|-------------------------| | `RP_ID` | Hostname passkeys are bound to | `localhost` | | `ORIGIN` | Full URL the app is served from | `http://localhost:8080` | | `WEB_PORT` | Host port for the web UI | `8080` | | `RP_NAME` | Name shown in the passkey prompt | `openGym` | | `ADMIN_UIDS` | User ids that get the admin dashboard (comma-separated) | *(none)* | | `INVITE_ONLY` | Require an invite code to create a profile | *(off)* | Push notification keys are generated on first run and saved to `./data/vapid.json` β€” nothing to set. ## Roadmap Rough, community-driven β€” ideas and PRs welcome: - [x] Standalone mobile app β€” Android APK to sideload ([download](https://opengym.duarte-santos.ch)); on iOS as a self-hosted PWA (no store listings planned) - [x] Automatic progression programs (linear, Greyskull LP, double progression) with stalls and deloads - [x] Estimated 1RM per exercise - [ ] Percentage / training-max programming (5/3/1-style) on top of the progression engine - [ ] More starter plans (upper/lower, full-body, 5Γ—5) - [x] Importers from FitNotes / Strong / Hevy (including the RPE they record), and body weight from Apple Health - [x] Effort per set β€” RIR or RPE, whichever scale you think in - [ ] Body measurements (waist, arms…) alongside weight - [ ] Per-exercise notes & plate calculator - [ ] Exercise instructions in German & Portuguese (UI is translated; upstream dataset doesn't ship these yet) ## Tech React 19 + Vite (React Router, Zustand) Β· Node (no framework) Β· nginx Β· Docker Compose Β· WebAuthn Β· exercise data from [hasaneyldrm/exercises-dataset](https://github.com/hasaneyldrm/exercises-dataset). No database server, no cloud dependencies β€” the frontend builds inside Docker, so self-hosting stays a one-command `docker compose up`. The training logic β€” progression rules, 1RM estimation, how a logged session is read back β€” lives in pure functions under `frontend/src/lib/` with tests next to them: `npm test` in `frontend/`. Vitest is a dev dependency; the app itself ships no runtime dependencies beyond React, the router and Zustand. ## Community - **[Q&A](https://github.com/DuarteSantos8/openGym/discussions/categories/q-a)** β€” self-hosting help, passkey/login trouble, "how do I…". Most login problems turn out to be an `RP_ID`/`ORIGIN` mismatch. - **[Ideas](https://github.com/DuarteSantos8/openGym/discussions/categories/ideas)** β€” features worth talking through before anyone writes code. - **[Show and tell](https://github.com/DuarteSantos8/openGym/discussions/categories/show-and-tell)** β€” your setup, your plan templates, whatever you built on top. - **[Issues](https://github.com/DuarteSantos8/openGym/issues)** β€” bugs, and work that's already been agreed on. ## Contributing Issues and PRs welcome β€” see [CONTRIBUTING.md](CONTRIBUTING.md). Good first issues: more starter plans, exercise-data languages, import from other trackers. **A ⭐ helps more people find it.** openGym is free and stays free: AGPL, no subscription, no paid tier, nothing held back for sponsors. If it replaced a paid tracker for you and you want to chip in, the Sponsor button at the top of the page is there β€” a star, a bug report or a PR is worth just as much. ## License [GNU AGPL v3.0](LICENSE) β€” free and open source. You can self-host, use, modify and share it; if you run a modified version as a network service, you must offer that version's source under the same license. Nobody can turn openGym into a closed, proprietary product. Exercise images/GIFs are fetched from the upstream dataset and keep their own terms β€” see [NOTICE.md](NOTICE.md).