Skip to content
longtimec0mingPublic

About

Sub-muscle volume tracker for Hevy, open source. Hevy tracks muscle groups coarsely ("chest", "shoulders"). HevyMap pulls in your workouts.

Resources

Contributing

Security policy

Stars

22 stars

Watchers

0 watching

Forks

Repository files navigation

HevyMap

CI License: MIT

Sub-muscle volume tracker for Hevy, open source.

Hevy tracks muscle groups coarsely ("chest", "shoulders"). HevyMap pulls in your workouts — via the Hevy API or a free CSV export, your choice — and allocates every set to 32 fine-grained sub-muscles (front/side/rear delts, upper/mid/lower chest, triceps heads, and more), visualized on an interactive anatomical body heat map, with weekly volume tracked against evidence-based targets.

Each deployment is your own, private copy: your data lives in Hevy and in your browser. There's no shared hosted app, no accounts, and no database.

Screenshots

Dashboard: monthly body heat map (front and back), neglect radar and recent workouts

Analytics: 12-month consistency heatmap, sets by sub-muscle with a group filter, sets by muscle group, hours trained

Requirements

You need Hevy workout data to get in, but not Hevy Pro. Two ways to connect, chosen on first run:

  • A Hevy API key — requires Hevy Pro. Get one from the Hevy app under Settings → Developer (or the developer settings at hevy.com; exact wording may vary by app version — check Hevy's own help docs if you can't find it). You can either set this once in the deployment's environment (HEVY_API_KEY), or paste it into the app itself the first time you open it — no redeploy needed.
  • A Hevy CSV export — free, no Pro required. In the Hevy app: Settings → Export data. Upload the file on first run; it's parsed entirely in your browser and never leaves your device. CSV imports can't sync incrementally, so re-upload a fresh export to bring in new workouts.

Run it

A. Deploy your own copy on Vercel (recommended)

Deploy with Vercel

This forks the repo into your own GitHub account and prompts for the env vars during setup — all optional, leave any of them blank. It's a private instance of the app on your own Vercel account — nobody else can see your data unless you set ACCESS_PASSWORD and share it.

  • HEVY_API_KEY (optional) — your key from Hevy Pro, if you'd rather set it once here than paste it into the app. Leave blank to connect in-app instead (via a pasted key or a CSV upload).
  • ACCESS_PASSWORD (optional) — if your deployment is reachable on the open internet (which any default Vercel URL is), set this so random visitors can't load your workout data. Use a long passphrase: there's no built-in rate limiting on login attempts (if you want one, Vercel's Firewall can add a rate-limit rule on /api/auth). Leave it blank only if you're comfortable with the URL being unprotected.
  • HEVYMAP_SECRET (optional) — see Bring your own API key below. Only matters if you're connecting a key in-app rather than setting HEVY_API_KEY.

B. Run it locally

git clone https://github.com/longtimec0ming/hevymap.git
cd hevymap
npm install
cp .env.example .env.local   # optional: fill in HEVY_API_KEY, or connect in-app instead
npm run dev

Open http://localhost:3000. On first run, either connect your Hevy API key (in the app, if HEVY_API_KEY isn't set) or upload a Hevy CSV export.

Environment variables

Variable Required Purpose
HEVY_API_KEY no Server-side only, used by the Hevy API proxy. Never exposed to the client. If unset, you can connect a key in-app instead, or use a CSV import.
ACCESS_PASSWORD no If set, gates the whole app behind a password form — set this for any deployment reachable by others. Unset = no gate.
HEVYMAP_SECRET no Encrypts the cookie used to store a key connected in-app (see below). Falls back to ACCESS_PASSWORD if that's set, then to a random per-process secret. Only relevant if HEVY_API_KEY is unset.

Bring your own API key

If HEVY_API_KEY isn't set, the first-run screen lets you paste your own Hevy API key instead. It's validated against the real Hevy API, then stored as an encrypted, httpOnly cookie — never in localStorage/IndexedDB, never sent to client-side JavaScript, never logged. Encryption uses AES-256-GCM, keyed from (in order) ACCESS_PASSWORD, then HEVYMAP_SECRET, then — if neither is set — a random secret generated once when the server process starts.

That last case has a real tradeoff: without ACCESS_PASSWORD or HEVYMAP_SECRET set, a restart or redeploy invalidates the encryption key, so any in-app-connected API key is silently disconnected and you'll need to reconnect (or re-upload your CSV, or set HEVY_API_KEY) next time. Set HEVYMAP_SECRET on any real deployment to avoid this. Settings has a "Disconnect" action to clear the cookie deliberately.

Commands

npm run dev         # local dev server
npm run build       # production build
npm run test         # Vitest (includes muscle-map validation)
npm run lint         # ESLint
npm run typecheck   # tsc --noEmit

Privacy & security

  • A server-configured HEVY_API_KEY is read only by the server-side proxy route and is never sent to the browser, logged, or stored anywhere but your own deployment's environment variables.
  • A key connected in-app is validated server-side, then stored as an encrypted, httpOnly cookie — never in localStorage/IndexedDB, never sent to client-side JavaScript, never logged. See Bring your own API key.
  • A CSV export is parsed entirely in your browser (File API) — it's never uploaded anywhere.
  • Your workout data (from either source) is cached in your browser's IndexedDB. It isn't sent to any third-party server or database — HevyMap doesn't run one.
  • No accounts, no sign-up, no telemetry or analytics.
  • Because each deployment is single-user, set ACCESS_PASSWORD on any copy reachable from the open internet (this is the default for a Vercel deploy).

Features

  • Dashboard
    • A compact stat strip for the selected period (workouts, hard sets, volume, avg volume/workout, hours trained, current streak, most-trained sub-muscle, longest workout) with vs-previous-period deltas.
    • The body heat map for the current period — rolling 7 days, calendar week, calendar month, custom range, or all-time — beside a neglect radar of under-trained muscles (each row links to that muscle's pre-filtered Exercises view), a click-a-muscle drill-down (which exercises fed it, plus "Find exercises"), and a recent-workouts card.
    • A full-width 12-month consistency heatmap and a full-width sets-by-sub-muscle chart (filter by muscle group), then sets by muscle group, hours trained, volume progression, workouts per week, and PRs over time — each chart with its own ALL/1Y/6M/3M/1M range and week/month bucket toggle. Per-muscle sparklines sit behind a collapsible toggle.
  • Trends — per-sub-muscle trend lines (3m/6m/1y/All range) with a 4-week-average-vs-prior signal on each card, with the 32 sub-muscles grouped under their 7 coarse regions; hover a sub-muscle's trend card for a link to its pre-filtered view on Exercises.
  • Workouts — your full history from Hevy; every row shows its muscle-group distribution at a glance, and each workout and exercise expands into its own body map.
  • Exercises — a searchable, filterable mapping browser: filter by sub-muscle (with a contribution threshold — primary/significant/any), equipment, and source/confidence (repo-map tier, override, estimated, custom-only), sort by name/contribution/confidence, each result showing its top contributions and confidence as chips. Deep-linkable via /exercises?muscle=<id>&group=<region> (used by the dashboard's neglect radar, muscle drill-down panel, and Trends' sub-muscle links) with a dismissible banner showing that muscle's current-week volume vs target. Picking an exercise shows its body-map contribution split next to a compact per-sub-muscle slider editor (grouped by region, lock a value to pin it while adjusting the rest), with confidence/source badges and auto-rebalancing sliders that always sum to 100% (needed for custom exercises, and to override any mapping you disagree with). Its header also links out to the exercise on Hevy and a YouTube form-check search.
  • Settings — kg/lbs units, warm-up-set toggle, per-muscle weekly targets, override export/import, a light/dark/system theme toggle (also in the sidebar), and (depending on your data source) a force re-sync button, or a re-upload CSV / switch-to-API-key affordance.

How the muscle mapping works

The 32 sub-muscles are grouped into 7 regions: Shoulders (front/side/rear delt, rotator cuff), Chest (upper/mid/lower chest, serratus anterior), Back (upper/lower lats, spinal erectors), Traps (upper/mid/lower traps, neck), Arms (biceps, brachialis/brachioradialis, triceps long head, triceps lateral/medial heads, forearms), Core (rectus abdominis, obliques, hip flexors) and Legs (rectus femoris, vasti, hamstrings, glute max, glute med/abductors, adductors, gastrocnemius, soleus, tibialis anterior). Rotator cuff, serratus and neck only receive volume when you log exercises that target them (Hevy's standard bank has few); custom exercises with those keywords are recognised automatically.

Every standard Hevy exercise has an entry in data/muscle-map.json: the exercise ID, its name, and a set of sub-muscle contribution weights that sum to exactly 1.0. A set of Incline Bench Press, for example, might allocate 0.55 to upper chest, 0.25 to front delt, and the rest split across the triceps heads — one hard set is one hard set's worth of stimulus, distributed across whatever it actually trains. Each entry also carries a confidence level (high / medium / low) so you can see at a glance which splits are well-established versus best-effort guesses.

Exercises resolve in this order: your own override (set in the mapping editor) → the repo's muscle-map.json → keyword/equipment-based inference rules → a coarse fallback. Anything below a repo-defined mapping is visibly badged "estimated" in the UI: custom Hevy exercises have per-account IDs so the repo can't ship a split for them — define one in the mapping editor and it's used from then on. (Tonnage for bodyweight exercises counts only logged added weight; sets count normally.) If you spot a mapping you think is wrong, or want to improve a low-confidence entry, see CONTRIBUTING.md — mapping PRs are the highest-value way to contribute, since a better split helps every user immediately on their next sync.

Contributing / architecture

For details on the muscle-map schema, the sum-to-1.0 rule, confidence levels, and how to submit a mapping PR, see CONTRIBUTING.md. The full technical/product spec this project was built against lives in PLAN.md, if you want the deeper architecture picture.

License

MIT

About

Sub-muscle volume tracker for Hevy, open source. Hevy tracks muscle groups coarsely ("chest", "shoulders"). HevyMap pulls in your workouts.

Resources

Contributing

Security policy

Stars

22 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages