Pose keypoint playground
Pick a keypoint scheme, click a joint, and see the index and name the same point carries in each of the 9 schemes this site reads from source (BlazePose 33, ML Kit 33, COCO 17, Halpe26, COCO-WholeBody 133, OpenPose BODY_25, OpenPose COCO 18, Apple Vision 2D, Apple Vision 3D), or “not in this scheme”. Then copy a TypeScript or Python dict that maps one scheme’s indices to another’s. Two points are paired only when their names match once lowercased with separators removed, which gives 391 pairs across 34 of the 36 scheme pairs; everything else is listed as unmapped, not guessed.
COCO 17: 13 left_knee
The same name in every scheme the dataset holds.
| Scheme | Index | Name |
|---|---|---|
| BlazePose 33 | 25 | LEFT_KNEE |
| ML Kit 33 | 25 | LEFT_KNEE |
| COCO 17 | 13 | left_knee |
| Halpe26 | 13 | left_knee |
| COCO-WholeBody 133 | 13 | left_knee |
| OpenPose BODY_25 | not in this scheme | |
| OpenPose COCO 18 | not in this scheme | |
| Apple Vision 2D | no index | leftKnee |
| Apple Vision 3D | no index | leftKnee |
“Not in this scheme” means no point with this name: Two points share a crosswalk row only when their names are identical after lowercasing and removing every character that is not a letter or a digit. left_knee, LEFT_KNEE and leftKnee all become leftknee and share a row; MOUTH_LEFT and LEFT_MOUTH, or RShoulder and right_shoulder, do not, and stay unmapped rather than guessed. It is a statement about names, not anatomy. Apple Vision joints are named constants with no numeric index.
All 17 points of COCO 17
COCO 17 → BlazePose 33 as code
17 of 17 COCO 17 points have a name match in BlazePose 33; the other 0 are listed in a comment, not mapped.
// COCO 17 -> BlazePose 33: 17 of 17 COCO 17 points have a name match.
// From the aifitnessapi.com keypoint crosswalk (sources read 2026-10-17): a pair exists
// only where both names match after lowercasing and dropping non-alphanumerics.
// A name match is not a guarantee that two models place the point identically.
// https://aifitnessapi.com/tools/keypoint-playground?from=coco-17&to=blazepose-33
export const COCO_17_TO_BLAZEPOSE_33: Readonly<Record<number, number>> = {
0: 0, // nose -> NOSE
1: 2, // left_eye -> LEFT_EYE
2: 5, // right_eye -> RIGHT_EYE
3: 7, // left_ear -> LEFT_EAR
4: 8, // right_ear -> RIGHT_EAR
5: 11, // left_shoulder -> LEFT_SHOULDER
6: 12, // right_shoulder -> RIGHT_SHOULDER
7: 13, // left_elbow -> LEFT_ELBOW
8: 14, // right_elbow -> RIGHT_ELBOW
9: 15, // left_wrist -> LEFT_WRIST
10: 16, // right_wrist -> RIGHT_WRIST
11: 23, // left_hip -> LEFT_HIP
12: 24, // right_hip -> RIGHT_HIP
13: 25, // left_knee -> LEFT_KNEE
14: 26, // right_knee -> RIGHT_KNEE
15: 27, // left_ankle -> LEFT_ANKLE
16: 28, // right_ankle -> RIGHT_ANKLE
};
// Every COCO 17 point has a name match in BlazePose 33.
What the mapping is built from
Every index and name comes from this site’s pose keypoint reference, which reads each scheme from the model’s own source file or documentation (321 points, read on 2026-10-17). The pairing rule is that reference’s crosswalk, unchanged: Two points share a crosswalk row only when their names are identical after lowercasing and removing every character that is not a letter or a digit. left_knee, LEFT_KNEE and leftKnee all become leftknee and share a row; MOUTH_LEFT and LEFT_MOUTH, or RShoulder and right_shoulder, do not, and stay unmapped rather than guessed.
So a pair says the two sources use the same name. It does not say the two models put the point in the same place on the body, and it does not join points whose names differ only in style. OpenPose spells sides as L and R (LShoulder), so its points pair with its own two schemes and little else; ML Kit writes LEFT_MOUTH where MediaPipe writes MOUTH_LEFT, so those two stay apart. OpenPose BODY_25 and Apple Vision 3D; OpenPose COCO 18 and Apple Vision 3D share no name at all, and the snippet says so. If you decide two differently named points are the same joint for your model, that is your call to write down; this tool will not make it for you.
Pairs per scheme
How many points of the row’s scheme have a name match in the column’s. The table is symmetric because each crosswalk row holds at most one point per scheme.
| Scheme | BlazePose 33 | ML Kit 33 | COCO 17 | Halpe26 | COCO-WholeBody 133 | OpenPose BODY_25 | OpenPose COCO 18 | Apple Vision 2D | Apple Vision 3D |
|---|---|---|---|---|---|---|---|---|---|
| BlazePose 33 | – | 31 | 17 | 19 | 19 | 1 | 1 | 17 | 12 |
| ML Kit 33 | 31 | – | 17 | 19 | 19 | 1 | 1 | 17 | 12 |
| COCO 17 | 17 | 17 | – | 17 | 17 | 1 | 1 | 17 | 12 |
| Halpe26 | 19 | 19 | 17 | – | 23 | 2 | 2 | 18 | 12 |
| COCO-WholeBody 133 | 19 | 19 | 17 | 23 | – | 1 | 1 | 17 | 12 |
| OpenPose BODY_25 | 1 | 1 | 1 | 2 | 1 | – | 18 | 2 | 0 |
| OpenPose COCO 18 | 1 | 1 | 1 | 2 | 1 | 18 | – | 2 | 0 |
| Apple Vision 2D | 17 | 17 | 17 | 18 | 17 | 2 | 2 | – | 13 |
| Apple Vision 3D | 12 | 12 | 12 | 12 | 12 | 0 | 0 | 13 | – |
Using the snippet
- The dict maps the first scheme’s index to the second’s. Apple Vision joints have no numeric index, so on that side the key or value is the joint name string as Apple spells it.
- Points with no name match are named in a comment under the dict and given no value, so a lookup for one of them fails loudly in your code instead of returning a plausible wrong joint.
- Each snippet carries the source date and a link back to the exact view, so a reviewer can check where it came from. The address bar holds the same state (
?from=&to=&joint=) for sharing. - A name match does not settle which side a source means. In ML Kit 33, the source’s own description of RIGHT_EYE_INNER reads
The landmark which corresponds to the inner left eye.
(and 2 more like it). Read the scheme page before converting a trained model’s output.
How this works, and what it sends
The page is static. The 9 schemes and the 53-row crosswalk are built into it at deploy time, and every lookup and snippet is computed in your browser by the same module this site’s tests check against the dataset: that every pair emitted is a crosswalk row and that mapping A to B and back returns every point it started from. Nothing is sent anywhere.
The body is a drawing. Dots are placed from the words in each point’s name and are not measurements or any model’s output. COCO-WholeBody’s face and hand points are listed under the figure rather than drawn, because names like face-12 do not say where the point sits. The dataset has names and indices but no skeleton connections, so no lines are drawn between points.
The underlying data is published under CC BY 4.0 on open datasets, and choosing a model in the first place is covered in pose estimation models compared.
Next step
Turning this into a choice of API:
A free tool from AIFitnessAPI. The full index tables are on the pose keypoint maps; every topic in camera-based tracking is at AI motion tracking.