The strength training log that keeps up with you.
Build your plans, log every set with a single tap and watch your progress grow.
Free and offline-first. No ads, no subscription, no account.
Try it in your browser · Download for Android · Changelog · Roadmap
Most workout trackers are either cluttered, locked behind a subscription or both. Grynd does one thing: it gets out of your way between sets.
- Faster than pen and paper. Last time's weights and reps are already filled in. Check the value, tap once, done. The rest timer starts by itself.
- Works anywhere. Everything runs on your device. No signal in the basement gym? No problem.
- Your data stays yours. No account, no tracking, no analytics. Export a backup file whenever you like.
- Progress you can see. Personal records are detected automatically, and the history shows volume, strength per exercise, muscle groups and streaks.
- Simple by design. A plan is one workout, a fixed list of exercises. Running a split? Create one plan per day. That's the whole concept.
Features · Get Grynd · Development · Architecture · Contributing · Releases and deployment · Documentation · Privacy · Acknowledgements · License
|
|
|
|
More screenshots
Grynd is in early development (0.x). Things work, but expect changes.
| Platform | How to get it |
|---|---|
| Web | Open fit.michael-isler.com. Data is stored in your browser. |
| Android | Download grynd-vX.Y.Z-debug.apk from the latest release and install it (how to). |
| iOS | Coming via TestFlight. CI already builds the iOS project on every release. |
App Store and Google Play listings will follow once signing is set up (see docs/release.md).
- Node.js 24 (see
.nvmrc) - pnpm, activated through Corepack (the version is pinned in
package.json) - For native builds: Android Studio and/or Xcode
git clone https://github.com/mcalihe/grynd.git
cd grynd
corepack enable
pnpm install
pnpm startOpen http://localhost:4200. In the browser the SQLite database runs on jeep-sqlite and is persisted in IndexedDB. Every shared component is shown in all its states at http://localhost:4200/dev/components (dev builds only).
| Command | Description |
|---|---|
pnpm start |
Dev server on port 4200 |
pnpm test |
Unit tests with Vitest (pnpm test:watch to watch) |
pnpm e2e |
End-to-end tests with Playwright on a phone-sized viewport |
pnpm lint |
ESLint (angular-eslint) |
pnpm format |
Prettier (pnpm format:check in CI) |
pnpm build |
Production build to dist/grynd/browser |
pnpm exec cap sync |
Copy the build into the Android and iOS projects |
pnpm catalog:import |
Rebuild the exercise catalog from free-exercise-db |
pnpm assets:generate |
Regenerate app icons and splash screens from assets/ |
Before the first E2E run, install the browser once with pnpm exec playwright install chromium.
pnpm build
pnpm exec cap sync
pnpm exec cap open android # or: pnpm exec cap open ios| Area | Choice |
|---|---|
| Framework | Angular (standalone components, signals, new control flow) |
| Native shell | Capacitor for Android and iOS |
| UI | Spartan UI (brain + helm) and Tailwind CSS v4 |
| Icons | Lucide via ng-icons |
| Animation | Motion and canvas-confetti |
| Database | SQLite via @capacitor-community/sqlite |
| i18n | Transloco (English, German) |
| Testing | Vitest and Playwright |
| Tooling | pnpm, angular-eslint, Prettier, GitHub Actions, release-please |
src/app/
├── core/ # data and business logic, no UI
│ ├── db/ # SQLite driver, migrations, repositories, catalog sync
│ ├── plans/ # plans and the plan editor draft
│ ├── workout/ # sessions, prefill, records, intervals, rest timer
│ ├── history/ # statistics and comparisons
│ ├── backup/ # JSON export and import
│ └── settings/ i18n/ services/ units/ utils/
├── features/ # routed pages: plans, workout, history, settings
└── shared/
├── ui/ # Spartan helm components
├── components/ # own components (set row, timer bar, charts, …)
└── motion/ # animation presets and the celebration service
docs/ # product plan, roadmap, decisions, design notes
e2e/ # Playwright tests
scripts/ # catalog import, screenshots, deployment
android/ ios/ # Capacitor native projects
Grynd has no backend. All data lives in a local SQLite database, and every screen reads it through services that expose their state as Angular signals.
flowchart LR
pages["Feature pages<br/>plans · workout · history · settings"]
services["Services<br/>signal state, business rules"]
repos["Repositories<br/>soft delete, timestamps"]
driver["SqlDriver"]
native[("SQLite<br/>Android · iOS")]
web[("jeep-sqlite<br/>IndexedDB")]
pages --> services --> repos --> driver
driver --> native
driver --> web
A few rules shape the code base:
- A workout is a copy of its plan. Reordering or adding sets during a workout never changes the plan.
- Sync-ready records. Every row has an app-generated UUIDv7
id,createdAt,updatedAtanddeletedAt(soft delete), so a future sync needs no migration. - Time comes from timestamps. Everything is stored in UTC, and durations are derived from timestamps. The rest timer stores its end time, not a counter.
- One unit internally. Weights are always stored in kg; lb exists only on screen.
- Design tokens only. Colors, spacing and radii come from the Figma file via generated CSS variables. Components mirror their Figma names.
Business logic such as prefill, record detection (estimated 1RM by Epley), intervals and unsaved-changes detection is covered by unit tests. The main flow from plan to history is covered by an end-to-end test.
Grynd is a personal project, but issues and ideas are welcome. Before you start on a pull request, please open an issue so we can agree on the approach. CONTRIBUTING.md explains the workflow and the contribution terms you accept by submitting a pull request; the short version:
- Read
docs/plan.mdfor the product decisions behind a feature. - Fork the repository, create a branch per change and keep commits small.
- Use only Spartan helm components, design tokens and Transloco keys (no hardcoded colors or text).
- Make sure
pnpm format:check,pnpm lint,pnpm testandpnpm e2epass. - Give the pull request a Conventional Commits title, for
example
feat(workout): show the previous set while logging. PRs are squash-merged and the title becomes the changelog entry, so CI checks it.
Pull requests from branches of this repository get their own preview deployment, linked in the PR. Pull requests from forks don't, because they have no access to the deployment secrets.
Updating the README screenshots
With the dev server running (pnpm start), run:
node scripts/readme-screenshots.mjsThe script loads generated demo data, freezes the clock and writes light and dark screenshots to
docs/readme/screenshots/.
Versioning is fully automated with release-please.
Every merge to main updates a release PR; merging that PR tags the version, publishes a
GitHub release with the changelog and attaches the
Android APK.
| Environment | URL | Updated on |
|---|---|---|
| Production | fit.michael-isler.com | Every release |
| Staging | fit-preview.michael-isler.com/main | Every merge to main |
| Preview | fit-preview.michael-isler.com/pr-<number>/ |
Every pull request |
Details on CI, native builds and signing are in docs/release.md.
Product and design documents are written in German.
Grynd collects no data. There is no account, no analytics and no server that stores your workouts. Plans and workouts never leave your device unless you export a backup yourself. The full privacy policy draft is in docs/store/privacy.md.
- Exercise data and images from free-exercise-db (public domain)
- Spartan, Lucide and Inter for the UI building blocks
- Angular and Capacitor for making one code base run everywhere
Grynd is source-available, not open source. The code is public so you can read it, learn from it and contribute to it, under the PolyForm Strict License 1.0.0.
- You may read the code, use it for personal and other noncommercial purposes and contribute through pull requests (contribution terms).
- You may not distribute copies, publish changed versions, sell the app or its code, or use the name Grynd or the app icon for other apps.
Third-party components, such as the dependencies, fonts and exercise catalog, keep their own licenses. For any other use, please open an issue.
Made with ☕ in Switzerland
