MuscleMap

MuscleMap

View in Storybook

A MuscleMap renders a human body outline as an SVG built from individually-shaped muscle-group regions — 40 in the front view, 49 in the back view — each identified by a semantic id (e.g. chest-upper-left, triceps-long-right). Given a list of "active" region ids, those regions render in the accent highlight color; every other region renders in a neutral, inactive fill.


Overview


When to use

  • As a small thumbnail on an exercise card, showing which muscle group(s) that exercise targets.
  • Anywhere a user needs to see, at a glance, which muscle regions are highlighted (e.g. "this exercise works your chest and shoulders").
  • Both front and back views are supported for exercises whose primary targets are on the back of the body (lats, traps, glutes, hamstrings, etc.).

When not to use

  • As an input control for picking muscle groups — MuscleMap is a read-only diagram, not a selector. Build a separate picker component if that interaction is needed.
  • At very large display sizes expecting photorealistic detail — the underlying path data is stylized line art, not anatomical illustration (see Attribution).

Crops

front / full

front / upper

front / lower

back / full

back / upper

back / lower

The full-body render is often "too zoomed out" for a small card thumbnail, so crop selects one of three fixed viewBox windows instead of a per-exercise custom crop. Front and back views share one coordinate space — the back view's path data is pre-offset by +37 on the x-axis, which is why the back viewBoxes start at x=37:

CropFront viewBoxBack viewBoxUse for
full0 0 35 9337 0 35 93Whole-body reference views.
upper0 0 35 5537 0 35 55Chest, shoulders, back, arms, abs.
lower0 40 35 5337 40 35 53Glutes, quads, hamstrings, calves.

These windows were calibrated by rendering test crops against the real region boundaries and adjusting until they framed cleanly — they are not arbitrary or eyeballed, so don't tweak the numbers without re-checking against the source regions. The rule for choosing one: classify an exercise's primary target region(s) as upper or lower body, then pick the matching crop. Keep the crop choice consistent for a given exercise across every screen that shows its thumbnail.

The full list of ~90 region ids (used both for activeRegionIds and for classifying upper vs. lower body) is documented in docs/apps/gym-plan.md (repo root, "Full region id list" section) rather than duplicated here — that file is the source of truth for the id list.


Attribution

The vendored path data (./data/muscle-map-front.json, ./data/muscle-map-back.json) is extracted from body-muscles by Ivan Vulović, licensed under the Apache License, Version 2.0:

Body Muscles
Copyright 2024 Ivan Vulović
https://github.com/vulovix/body-muscles

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Only the id and path (SVG d attribute) fields were extracted from the original source — the name/view fields were dropped during parsing. The full notice, source file references, and extraction date live alongside the data at ./data/LICENSE-body-muscles.txt; retain that file and this section if the data is ever moved or re-vendored again.

The data is vendored directly (rather than depending on the body-muscles npm package) because the package's own runtime does its own DOM manipulation targeting a plain element, which doesn't integrate cleanly with React state — only the geometry (the path data) is used here, wrapped in this component and styled with our own design tokens.


Controls

Interactive controls are available in Storybook. Open Storybook


Props


Token mapping

PropertyToken
inactive region fill--sunken-outer-light
region stroke--color-text-muted
active region fill--color-accent-highlight

Region stroke is rendered at stroke-width: 0.15 with stroke-opacity: 0.5, matching the CSS block documented in the "Muscle map" section of docs/apps/gym-plan.md.


Changelog

DateChange
2026-07-22Initial component created — vendored path data moved from docs/apps/gym-assets/ into src/MuscleMap/data/; added view/activeRegionIds/crop props, stories, and documentation