npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ngx-body-part-selector

v1.0.0

Published

A tappable human body silhouette for selecting body parts, for Angular.

Readme

ngx-body-part-selector

A tappable human body silhouette for selecting body parts, for Angular.

This is an Angular port of the Flutter/Dart body_part_selector package (front/left/back/right silhouettes, ~24 selectable regions, and a 4-sided "turntable" rotation UI). It ships as a single library — the original's separate rotation_stage subpackage is folded in as an internal implementation detail here, not a public API.

Installation

npm install ngx-body-part-selector

Usage

Two standalone components are exported: BodyPartSelectorComponent (a single fixed side) and BodyPartSelectorTurnableComponent (all four sides, with drag-to-rotate / tap-to-rotate). Both are fully controlled — they take no internal state, only a two-way bodyParts binding.

import { Component, signal } from '@angular/core';
import {
  BodyPartSelectorTurnableComponent,
  DEFAULT_BODY_PARTS,
} from 'ngx-body-part-selector';

@Component({
  selector: 'app-root',
  imports: [BodyPartSelectorTurnableComponent],
  template: `<ngx-body-part-selector-turnable [(bodyParts)]="bodyParts" />`,
})
export class AppComponent {
  protected readonly bodyParts = signal(DEFAULT_BODY_PARTS);
}

For a single fixed side, use BodyPartSelectorComponent directly:

<ngx-body-part-selector [(bodyParts)]="bodyParts" side="front" />

BodyParts

A plain object with 24 boolean fields (head, neck, leftShoulder, rightShoulder, abdomen, leftFoot, rightFoot, ...). Use DEFAULT_BODY_PARTS (all false) or BODY_PARTS_ALL (all true) as a starting point, and withToggledId(bodyParts, id, mirror?) to toggle a part by its string id — the same ids used as <path id> in the rendered SVG, so this is also what you'd use to build your own custom UI against the same model.

mirror: true also syncs the opposite side's counterpart to match (e.g. toggling leftKnee with mirror: true also sets rightKnee to the same new value) — this is what the mirrored input on both components enables for user-driven clicks.

Note: vestibular is part of the BodyParts model for API completeness (matching the original package), but has no corresponding region in the body silhouette — it's never rendered or clickable. It can still be set programmatically.

BodyPartSelectorComponent inputs

| Input | Type | Default | Description | |---|---|---|---| | bodyParts | model<BodyParts>() | required | Two-way selection state. | | side | BodySide ('front' \| 'left' \| 'back' \| 'right') | required | Which side to render. | | mirrored | boolean | false | Sync left/right counterparts on click. | | selectedColor | string \| undefined | theme default | Fill color for selected parts. | | unselectedColor | string \| undefined | theme default | Fill color for unselected parts. | | selectedOutlineColor | string \| undefined | theme default | Outline color for selected parts. | | unselectedOutlineColor | string \| undefined | theme default | Outline color for unselected parts. |

BodyPartSelectorTurnableComponent inputs

All of the above (except side, which cycles automatically) plus:

| Input | Type | Default | Description | |---|---|---|---| | padding | string | '0' | Outer CSS padding around each side's content. | | labelData | RotationStageLabelData | English | { front, left, back, right } label strings for the handle bar. | | barInteractable | boolean | true | When false, the handle bar is no longer draggable (tap-to-select still works). | | barHeight | string | '64px' | CSS height of the bottom handle bar. |

Theming

Colors default to a built-in palette and can be overridden per-instance via the inputs above, or globally via CSS custom properties on ngx-body-part-selector:

ngx-body-part-selector {
  --npbs-selected-color: #6750a4;
  --npbs-selected-outline-color: #4a3b78;
  --npbs-unselected-color: #ddd7e6;
  --npbs-unselected-outline-color: #a89fb8;
}

The outline color is a darker shade of its matching fill color in both states, so the boundary between adjacent regions stays visible.

Differences from the original Flutter package

This is a port, not a 1:1 transliteration — a few things were deliberately changed for the web:

  • Rendering: real inline SVG (<svg><path>) with native click handling and CSS transitions, instead of a CustomPainter + manual canvas hit-testing. Selection-change animation is now per-part (only the changed region's fill/stroke transitions), not a whole-scene crossfade.
  • No async SVG loading: the silhouettes are bundled with the library and render synchronously — no loading spinner.
  • Rotation physics: hand-rolled (pointer events + requestAnimationFrame) since there's no web equivalent of Flutter's PageController fling/snap behavior. The 3D flip's rotation direction is also mirrored relative to the Dart original's Matrix4 transform — Flutter and CSS disagree on which way is "positive" around the Y axis for this kind of screen-space fake-3D rotation, so a literal sign port looked backwards.
  • Shortest-path rotation fix: the original's animateToSide only corrected the "3 steps forward" wraparound case, not the symmetric "3 steps backward" one, causing an unnecessarily long spin in one direction. This port corrects both directions.
  • barInteractable: in the original, this only made the handle bar's chips visually transparent — the bar remained draggable regardless. Here it also disables the drag gesture.
  • API shape: a two-way bodyParts model binding ([(bodyParts)]) instead of a separate value + change-callback pair.

Development

This library lives in an Angular CLI workspace alongside a demo app used for manual verification. From the workspace root:

npm install
npx ng test ngx-body-part-selector   # unit tests
npx ng build ngx-body-part-selector  # build the library
npx ng serve demo                    # run the demo app