trAIner is a local-first workout PWA for one person on one device. It turns routines from human trainers or external LLMs into structured, editable, loggable workouts that work offline after install.
The source code is licensed under the GNU General Public License v3.0 or later.
The exercise data and animations are not covered by the GPL. They are proprietary third-party content used under a separate commercial license that permits use inside this app but prohibits redistributing the raw dataset or animations as a standalone library or product, or reselling them. The data is included here only so the app can function — it is not offered as a reusable standalone dataset. See NOTICE for details.
- Open the app and go to Prompts — copy the prompt template and paste it into any external LLM (ChatGPT, Claude, etc.).
- Describe your goals, schedule, and available equipment. The LLM returns a JSON workout program.
- Go to Import, paste the JSON, and step through exercise resolution. The app maps exercises to its built-in catalog and flags any it can't match so you can pick alternatives.
- Your program appears under Routines. Browse days, edit sets/reps, and reorder exercises inline.
- Go to Today to see the routine scheduled for the current day.
- Tap any set to log reps and weight. The app tracks your history across sessions.
- History shows a full log of past workouts. Profile shows the training heatmap and bodyweight history.
Each routine has an analysis card that scores volume, balance, coverage, and session structure.
- Working-volume analysis excludes exercises identified as ordinary warmup, activation, mobility, cooldown, rehabilitation, or prehabilitation work — they aren't counted as working sets when scoring muscle-group volume.
- Those exercises still count toward total programmed activity, exercise count, and estimated session duration.
- Analysis is recomputed every time you open a routine, so existing stored routines automatically show updated results — no action needed, and no data migration is required.
trAIner stores everything — programs, logs, and settings — in your browser's IndexedDB. Nothing is sent to any server. There are no accounts, no cloud sync, and no telemetry.
Because everything is local, a few things can erase your data:
| Action | Risk |
|---|---|
| Clearing browser site data / cookies | Wipes all data |
| Using a different browser or profile | Data is not shared across browsers |
| Private/incognito mode | Data is lost when the window closes |
| Reinstalling or resetting the browser | Wipes all data |
Back up regularly. Go to Workspace → Export full workspace to download a .json file. Keep it somewhere safe (cloud storage, email to yourself, etc.). To move to a new device or browser, use Import workspace on the new side.
You can also take in-app snapshots (Workspace → Snapshot current state) as quick checkpoints stored alongside your data — but these are in IndexedDB too, so they are not a substitute for exporting a file.
mise install
bun install
bun run devOpen http://localhost:5173/today.
bun run lint
bun x tsc --noEmit
bun x tsc --noEmit -p tsconfig.test.json
bun run test -- --runInBand
bun run build- No in-app AI calls
- No auth, billing, accounts, hosted runtime, or cloud sync
- Runtime app data lives in IndexedDB
- External LLMs are used through copy/paste prompts only
- Backup and restore use local JSON files
The bundled catalog merges four sources:
yuhonas/free-exercise-db— fetched at build time- wger fixture snapshot (
scripts/sources/wger-snapshot.json) - ExerciseDB snapshot via RapidAPI (
scripts/sources/exercisedb-snapshot.json) - ExerciseDB Pro — richer muscle/equipment metadata applied as an enrichment pass over the merged catalog (
scripts/sources/exercisedbpro-snapshot.json)
Local aliases and additions live in scripts/catalog-local-overrides.json. The generated output is src/lib/catalog/exercises.generated.json; src/lib/catalog/exercises.ts is a small typed wrapper used by the app.
bun run catalog:build# wger — no credentials needed
bun run catalog:ingest:wger
# ExerciseDB — requires a RapidAPI key
RAPIDAPI_KEY=<your-key> bun run catalog:ingest:exercisedbCommit the updated snapshot file(s) and re-run catalog:build.
ExerciseDB Pro was ingested from a locally downloaded dataset. If the source file is available:
# Requires exerciseDBpro720px/exerciseData_complete.json at the repo root
# Also requires exercises.generated.json to exist — run catalog:build first
bun scripts/ingest/ingest-exercisedbpro.mjsThis writes scripts/sources/exercisedbpro-snapshot.json and a review file (exercisedbpro-review.txt) listing uncertain matches. Commit the snapshot and re-run catalog:build.