Interactive human body muscle map SDK for the web.
TypeScript/Canvas port of the MuscleMap SwiftUI SDK.
![]() | ![]() | ![]() | ![]() |
- 🎨 Canvas2D rendering — crisp, DPR-aware drawing on HiDPI/Retina displays
- 👤 4 body models — Male/Female × Front/Back, 86 body parts total
- 💪 36 muscles — 22 base + 14 sub-groups (upper-chest, front-deltoid, inner-quad, etc.)
- 🖱️ Full interaction — click, hover, long press (500ms), drag-to-select
- 🌈 Heatmap visualization — 6 color scales, intra-muscle gradient fills, configurable interpolation
- 💡 Tooltip overlay — positioned HTML tooltip above each muscle, custom renderer support
- ↩️ Undo / Redo — selection history with configurable depth
- ✨ Animations — smooth highlight cross-fade and sin-wave pulse on selected muscles
- 🗺️ Legend component —
HeatmapLegendcolor bar (horizontal/vertical) - 🌍 11 locales — Arabic, Chinese, English, French, German, Japanese, Korean, Portuguese, Russian, Spanish, Turkish
- 🎨 4 style presets — Default, Minimal, Neon, Medical
- 💾 State serialization — save/restore highlighted muscles as plain JSON
- Zero dependencies — pure browser Canvas2D + DOM APIs
<!-- Add a sized container --><divid="muscle-map" style="width: 400px; height: 600px;"></div><scripttype="module">import{MuscleMapWidget}from'./MuscleMapJS/src/index.ts';constmap=newMuscleMapWidget(document.getElementById('muscle-map'),{gender: 'female',side: 'front',style: 'default',multiSelect: true,});// Listen for muscle clicksmap.on('muscleClick',(muscle,side)=>{console.log(`Selected: ${muscle} (${side})`);});// Get selection for saving to DBdocument.querySelector('#save').addEventListener('click',()=>{constdata=map.getHighlightData();// → [{ muscle: 'chest', color: '#00c853', opacity: 1 }, ...]});</script>💡 Works out of the box with Vite, Astro, or any bundler that supports TypeScript imports.
git submodule add https://github.com/abdofallah/MuscleMapJS.git src/lib/MuscleMapJSgit clone https://github.com/abdofallah/MuscleMapJS.gitThen import directly from the src/index.ts entry point.
constmap=newMuscleMapWidget(container: HTMLElement,options?: MuscleMapOptions);| Option | Type | Default | Description |
|---|---|---|---|
gender | 'male' | 'female' | 'male' | Body model gender |
side | 'front' | 'back' | 'front' | Body face to display |
style | StylePreset | BodyViewStyle | 'default' | Visual theme |
interactive | boolean | true | Enable pointer interactions |
multiSelect | boolean | true | Allow selecting multiple muscles |
showSubGroups | boolean | false | Show sub-group regions |
onMuscleClick | (muscle, side) => void | — | Shorthand event listener |
onSelectionChange | (muscles) => void | — | Shorthand event listener |
// Solid colormap.highlight('chest','#ff4444',0.9);map.highlightMany(['biceps','triceps'],'#00c853');// Gradients (ported from BodyView.swift modifiers)map.highlightLinearGradient('abs',['#ffeb3b','#f44336'],0,0,0,1);map.highlightRadialGradient('gluteal',['#ff9800','#f44336']);// Raw MuscleHighlight objectmap.setHighlight('chest',{muscle: 'chest',fill: {type: 'color',color: 'red'},opacity: 1});// Removalmap.removeHighlight('chest');map.clearHighlights();// Inspectionmap.getHighlightedMuscles();// → Muscle[]map.getHighlightData();// → serializable array (for DB storage)map.setHighlightData(saved);// restore from DBmap.select('biceps');map.selectMany(['chest','abs','obliques']);map.deselect('chest');map.toggleSelect('biceps');map.clearSelection();map.getSelectedMuscles();// → Muscle[]// Integer intensity (0–4 scale)map.setIntensities({chest: 4,biceps: 2,calves: 1},'workout');// Float intensity (0.0–1.0) with full configmap.setHeatmap([{muscle: 'chest',intensity: 0.9},{muscle: 'quadriceps',intensity: 0.7},],{colorScale: 'thermal',// 'workout' | 'thermal' | 'medical' | 'monochrome' | ...interpolation: {type: 'easeInOut'},threshold: 0.1,// skip muscles below this intensitygradientFill: true,// use intra-muscle gradientgradientDirection: 'topToBottom',gradientLowFactor: 0.2,});Available color scales:workout, thermal, medical, monochrome, workoutStepped, thermalSmooth
import{HeatmapLegend}from'./MuscleMapJS/src/index.ts';constlegend=newHeatmapLegend(container,{colorScale: 'workout',orientation: 'horizontal',// or 'vertical'barThickness: 16,labelMin: 'Low',labelMax: 'High',steps: 48,});// Default: shows muscle display namemap.enableTooltip();// Custom HTML renderermap.enableTooltip((muscle,side)=>{return`<strong>${muscle}</strong><br><small>${side} side</small>`;});map.disableTooltip();map.enableHistory(50);// enable with max 50 entriesmap.undo();// → Muscle[] | null (restored selection)map.redo();// → Muscle[] | nullmap.canUndo;// → booleanmap.canRedo;// → boolean// Smooth cross-fade on highlight changesmap.enableAnimation(300);// duration in msmap.disableAnimation();// Pulse effect on selected musclesmap.enablePulse(1.5,// speed (cycles/sec)0.6,// min opacity1.0,// max opacity);map.disablePulse();map.on('muscleClick',(muscle: Muscle,side: MuscleSide)=>void);map.on('muscleEnter',(muscle: Muscle,side: MuscleSide)=>void);map.on('muscleLeave',()=>void);map.on('selectionChange',(muscles: Muscle[])=>void);map.on('muscleLongPress',(muscle: Muscle,side: MuscleSide)=>void);map.on('muscleDrag',(muscle: Muscle,side: MuscleSide)=>void);map.on('muscleDragEnd',()=>void);map.off('muscleClick',handler);import{setLocale,getMuscleName,getUIString}from'./MuscleMapJS/src/index.ts';setLocale('ar');// ArabicgetMuscleName('chest');// → 'الصدر'getMuscleName('biceps','ja');// → '上腕二頭筋'getUIString('legendLow');// → 'منخفض'Supported locales:en · ar · de · es · fr · ja · ko · pt-BR · ru · tr · zh-Hans
map.setGender('female');map.setSide('back');map.setStyle('neon');// 'default' | 'minimal' | 'neon' | 'medical'map.setInteractive(false);map.setLongPressDuration(700);// msmap.getBoundingRect('chest');// → { x, y, width, height } in CSS pixelsmap.redraw();map.destroy();// cleanup — removes canvas + listeners| Preset | Fill | Selection | Shadow | Best For |
|---|---|---|---|---|
default | Light gray | Green | None | General use |
minimal | Lighter gray | Green | None | Embedded UI |
neon | Dark charcoal | Cyan | Cyan glow | Dark mode apps |
medical | Clinical blue-gray | Blue | None | Clinical/professional |
All 36 muscles (click to expand)
Base muscles (22):abs · biceps · calves · chest · deltoids · feet · forearm · gluteal · hamstring · hands · head · knees · lower-back · obliques · quadriceps · tibialis · trapezius · triceps · upper-back · rotator-cuff · serratus · rhomboids
Sub-groups (14):ankles · adductors · neck · hip-flexors · upper-chest · lower-chest · inner-quad · outer-quad · upper-abs · lower-abs · front-deltoid · rear-deltoid · upper-trapezius · lower-trapezius
npm install
npm run dev
# → http://localhost:5173/demo/index.htmlThe demo showcases all features: muscle selection, heatmaps, gradient fills, tooltip, pulse animation, undo/redo, locale switching, and the legend component.
---// src/components/MuscleSelector.astro---
<divid="muscle-map"class="w-full h-[600px]"></div>
<buttonid="save-btn">Save Muscles</button>
<script>
import { MuscleMapWidget, setLocale, getMuscleName } from '../lib/MuscleMapJS/src/index';
const map = new MuscleMapWidget(document.getElementById('muscle-map'), {
gender: 'female',
side: 'front',
style: 'medical',
multiSelect: true,
});
map.enableTooltip((muscle) => getMuscleName(muscle));
map.enableHistory();
document.getElementById('save-btn').addEventListener('click', () => {
const muscles = map.getHighlightData();
// persist to your DB / API
});
</script>The SDK is written entirely in TypeScript with strict mode. All types are exported from src/index.ts:
importtype{Muscle,MuscleSide,BodySide,BodyGender,MuscleHighlight,MuscleIntensity,HeatmapConfig,StylePreset,BodyViewStyle,MuscleMapOptions,MuscleEvent,}from'./MuscleMapJS/src/index.ts';src/
index.ts ← Public API entry point
types.ts ← All interfaces and type unions
core/
body-renderer.ts ← Canvas2D engine (render, hitTest, boundingRect)
body-path-data.ts ← ViewBox configs and path data provider
muscles.ts ← 36 muscles, hierarchy, display names
data/
male-front-paths.ts ← SVG paths for male front body (auto-generated)
male-back-paths.ts
female-front-paths.ts
female-back-paths.ts
heatmap/
color-scale.ts ← HeatmapColorScale + 6 presets
color-interpolation.ts ← 6 interpolation curves
styles/
body-view-style.ts ← 4 style presets + resolver
utils/
color.ts ← parseColor, interpolateColor, toCSSColor
widget/
muscle-map-widget.ts ← Main widget class (primary entry point)
heatmap-legend.ts ← Standalone legend component
i18n/
locales.ts ← 11 locales, 396 translated strings
demo/
index.html ← Interactive feature showcase
MIT © 2026
This project is a JavaScript/TypeScript port of the excellent MuscleMap SwiftUI SDK created by Melih Çolpan.
The original Swift SDK provided:
- The SVG body part path data (86 paths across 4 body models)
- The muscle taxonomy (36 muscles with full sub-group hierarchy)
- The heatmap configuration API design
- The style preset system and visual design language
- The accessibility string keys
MuscleMapJS recreates these features natively in TypeScript using browser Canvas2D, adds web-specific capabilities (tooltip, undo/redo, i18n, legend component, drag/long-press gestures, animations), and packages them as a zero-dependency library suitable for any modern web project.
A heartfelt JazakAllah Khair and thanks to Melih Çolpan for open-sourcing the original SDK under the MIT License — this project would not exist without it. 🤝
Built with ❤️ for the web.



