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

pose-form

v0.1.0

Published

Exercise form analysis and rep counting from pose landmarks. Zero dependencies, bring your own landmark source.

Readme

npm version CI runtime dependencies license TypeScript

Exercise form analysis and rep counting from pose landmarks. Pure TypeScript, zero runtime dependencies - no camera, no ML runtime of its own.

Why · Install · Quick start · What's in the box · Supported movements · Design notes · Limitations · API

You bring 33 BlazePose-style landmarks from wherever you like - MediaPipe Tasks Vision on the web, a native MediaPipe binding, TensorFlow.js MoveNet, a recorded file — and this library turns that stream into reps, phases, depth, form faults, and spoken cues.

flowchart LR
    L["33 landmarks<br/>per frame"] --> S["One Euro<br/>smoothing"]
    S --> M["20 form<br/>metrics"]
    M --> R["rep state<br/>machine"]
    R --> E["rules +<br/>cue selector"]
    E --> O["reps · phases · depth<br/>one cue at a time"]

Why

Rep counting and form checking are usually welded to one camera stack, so they die when the stack changes. Here the analysis is a plain function of landmarks. It runs in a browser, in React Native, in Node, and in a unit test with no device attached.

Install

npm install pose-form

Quick start

import { PoseAnalyzer, matchRuleSet } from 'pose-form';

const ruleSet = matchRuleSet('barbell back squat');
if (!ruleSet) throw new Error('No rules for that movement yet');

const analyzer = new PoseAnalyzer({
  ruleSet,
  // frameWidth / frameHeight. Without it, angles on a non-square frame are wrong.
  aspectRatio: 720 / 1280,
});

// Per frame, from your landmark source:
const update = analyzer.push({
  timestampMs: performance.now(),
  landmarks, // 33 points of { x, y, z, visibility }, normalised 0..1
});

if (!update.tracked) {
  // Body not fully in frame. Say so; do not report faults from bad data.
} else {
  console.log(update.reps, update.phase, update.depth);
  if (update.cue) speak(update.cue.text);
}

At the end of a set:

import { localFormReview } from 'pose-form';

const summary = analyzer.summary();
const issues = analyzer.issues();
const review = localFormReview('Barbell Back Squat', summary, issues);
// { overallScore, verdict, summary, issues, strengths, drills, safetyFlag }

localFormReview is deterministic and offline. If you also send the clip to a vision model, use this as the fallback when that call fails, so a user never loses their feedback.

What's in the box

| Module | What it does | | --- | --- | | Landmark helpers | Named indices for all 33 BlazePose points, visibility gating, dominant-side detection, and a tracking-quality score. isFrameUsable rejects a frame unless the core joints are individually visible, not merely good on average - one hidden hip is enough to invent a fault. | | Smoothing | A One Euro filter per coordinate: low lag when moving fast, low jitter when still. A fixed low-pass filter cannot do both. | | 20 metrics | Knee/hip/elbow/shoulder angles, torso lean and pitch, shin angle, body line, hip sag, knee separation (valgus), stance width, shoulder and hip tilt, left/right symmetry, neck angle, wrist stack, elbow flare, squat depth, heel lift. | | Rep counting | A state machine over the primary joint angle with hysteresis and a minimum rep duration, so jitter at the turnaround cannot double-count. Emits top / descent / bottom / ascent, live depth 0..1, and a RepEvent per rep carrying eccentric and concentric milliseconds, range of motion, peak depth, and whether it counted as full or partial. | | 12 rule sets | One per movement pattern below. Each rule has a severity, a short spoken cue, and a longer written fix. | | One cue at a time | The cue selector holds a fault for ~2.5s before speaking and will not repeat it for ~6s. Stacking three corrections on a lifter mid-set makes their form worse, not better. | | Isometric holds | Plank and similar use a hold timer instead of a rep counter. |

Supported movements

Camera is the placement the rules were written for — the wrong angle produces phantom faults.

| Movement | Rule set id | Camera | Mode | | --- | --- | --- | --- | | Squat | squat | either | reps | | Push-up | pushup | side | reps | | Hip hinge | hinge | side | reps | | Lunge | lunge | either | reps | | Overhead press | overhead_press | side | reps | | Biceps curl | curl | side | reps | | Row | row | side | reps | | Lateral raise | lateral_raise | front | reps | | Glute bridge | hip_extension | side | reps | | Crunch | trunk_flexion | side | reps | | Pull-up | vertical_pull | front | reps | | Plank | plank | side | hold (timer) |

Design notes

  • Bring your own landmarks. No camera, no wasm, no model download, no peer dependency on MediaPipe.
  • Aspect ratio matters. Landmarks are normalised per axis, so a 9:16 frame squashes every angle unless you pass aspectRatio.
  • Faults are suppressed when tracking is poor rather than reported with a shrug.
  • Coordinates follow the MediaPipe convention: x/y normalised to the frame, y increasing downward, z depth relative to the hips.

Limitations - read this

[!WARNING] Thresholds are heuristics tuned by hand, not clinically validated. They encode common coaching cues, not medical truth.

  • A single camera cannot see rotation, load, or intent. Depth from a bad angle is a guess.
  • 2D landmarks mean anything toward or away from the camera is weakly observed.
  • The rule sets cover common barbell, dumbbell and bodyweight patterns. Olympic lifts, gymnastics and machine work are not modelled.

[!CAUTION] This is not medical advice and not a substitute for a coach. Do not use it to clear anyone to train, to diagnose an injury, or as the only safety check on a heavy lift. If something hurts, stop and see a professional.

API

| Export | Purpose | | --- | --- | | PoseAnalyzer | The pipeline. push(frame), summary(), issues(), repEvents, reset() | | RepCounter, HoldTimer | The state machines, usable on their own against any scalar signal | | RuleEvaluator, CueSelector | Fault detection and cue throttling | | matchRuleSet, getRuleSet, listRuleSets, findRuleByCode | Rule set lookup | | METRICS, readMetric, readAllMetrics | The metric library | | LandmarkSmoother, OneEuroFilter | Smoothing | | localFormReview | Deterministic offline scoring | | LANDMARK, point, sided, trackingQuality, isFrameUsable | Landmark helpers |

Contributing

New rule sets are the most useful contribution. A rule needs a metric, the phases it applies to, a threshold, a severity, and cue/fix text a lifter would actually understand. Open an issue with the movement and the cue before writing code.

Licence

MIT. See LICENSE.