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

@slow-bloom/runner-tools

v0.2.0

Published

Pure client-side exercise science algorithms, running pace formulas, and track utilities.

Downloads

161

Readme

🏃 Runner Tools

Pure client-side exercise science algorithms, running pace formulas, and track utilities with zero dependencies. Built for runners, coaches, and sports data hackers.

License: MIT TypeScript CI


Live Demo

Experience these algorithms live in action on the web:


Highlights

  • Pure & Zero Dependencies: 100% pure TypeScript formulas with zero runtime dependencies. Runs anywhere: Node.js (dual ESM and CommonJS with full .d.ts / .d.cts), browsers, Bun, Deno, and Cloudflare Workers.
  • Scientifically Grounded: Implements Daniels & Gilbert's oxygen consumption models, Riegel's endurance power laws, Karvonen heart rate reserve equations, and World Masters Athletics (WMA) road standards.
  • Built-in i18n & Extensible: Multilingual support with hierarchical locale fallback (exact tag $\to$ base language $\to$ English default) and deep custom dictionary merging.
  • Strict Null Safety: Clear contracts where invalid, unphysiological, or unsolvable inputs return null instead of throwing or generating NaN.
  • No Silent Clamping: Discontinuous boundary cases and out-of-domain offsets are explicitly exposed rather than clamped silently.
  • Local File Conversion: Read FIT, GPX, TCX, KML and CSV; export all five plus GeoJSON. A standalone Web Worker keeps decoding, editing and encoding off the browser's UI thread, without CDN parser imports or file uploads.
  • Honest Track Comparison: Align tracks on overlapping timestamps or explicitly labeled route progress, interpolate mismatched sampling rates, and keep measured device distance separate from GPS-derived estimates.
  • Deterministic Interactive Tools: Audio scheduling follows the Web Audio clock, strength intervals follow monotonic elapsed time, and race-week calendar output is testable and locale-aware.

Installation

# npm
npm install @slow-bloom/runner-tools

# pnpm
pnpm add @slow-bloom/runner-tools

# yarn
yarn add @slow-bloom/runner-tools

Or directly via CDN in HTML:

<script src="https://cdn.jsdelivr.net/npm/@slow-bloom/[email protected]/dist/runner-tools.global.js"></script>
<script>
  const result = RunnerTools.calculateVDOT({ distanceMeters: 5000, timeSeconds: 1200 });
  if (result) {
    console.log('VDOT:', result.vdotFormatted); // "49.8"
  }
</script>

The browser bundle and dist/runner-tools.worker.js are supported distribution artifacts. Host both on the same origin when using createFileConverterClient; the worker installs a message handler and should not be imported into application code as a regular module.


Quickstart

import {
  calculateVDOT,
  predictRaceTime,
  calculateHeartRateZones,
  solvePace,
  parseGPX,
  serializeToTCX,
  analyzeTrack,
  createCadenceMetronome,
  createStrengthTimer,
  createRaceWeekPlan,
} from '@slow-bloom/runner-tools';

// 1. Calculate Daniels VDOT & training paces
const vdot = calculateVDOT({ distanceMeters: 5000, timeSeconds: 1200 });
console.log('Easy Pace:', vdot?.zones.E.lowPaceFormatted); // "5'03\""

// 2. Predict marathon finish time from a 10K
const marathonSecs = predictRaceTime(10000, 2700, 42195, 1.06); // ~12421s (3:27:01)

// 3. Calculate Karvonen Heart Rate Reserve (HRR) zones
const hr = calculateHeartRateZones({ method: 'karvonen', maxHR: 190, restingHR: 55 });
console.log('Zone 2:', hr?.zones[1].bpmFormatted); // "137 - 150 bpm"

// 4. Solve pace from distance and duration
const pace = solvePace({ distance: 10, timeSeconds: 2700, unit: 'km' });
console.log('Pace:', pace?.paceFormatted); // "4'30\""

// 5. Parse GPX and export as Garmin TCX
const activity = parseGPX(gpxContent);
const tcxContent = serializeToTCX(activity);

// 6. Analyze GPS distance without treating it as ground truth
const track = analyzeTrack(activity);

Modules & Documentation

Detailed mathematical derivations, physiological domains, and complete API specifications are documented in dedicated guides:

| Module | Category | Scientific Model / Basis | Documentation | |:---|:---|:---|:---| | vdot | Formula | Daniels-Gilbert oxygen power equation & E/M/T/I/R training paces | docs/formulas/vdot.md | | race-predictor | Formula | Peter Riegel's endurance power law ($T_2 = T_1 \cdot (D_2/D_1)^b$) | docs/formulas/race-predictor.md | | heart-rate-zones | Formula | Karvonen (HRR), %MaxHR, and Joe Friel 5-zone LTHR models | docs/formulas/heart-rate-zones.md | | age-grading | Formula | World Masters Athletics (WMA) 2020 road standards & scoring tiers | docs/formulas/age-grading.md | | running-efficiency | Formula | Vertical Ratio (VR), Duty Factor (DF), and Aerobic Efficiency Factor (EF) | docs/formulas/running-efficiency.md | | pace | Formula | 3-way pace/time/distance solver, unit conversions & split tables | docs/formulas/pace.md | | weekly-mileage | Formula | 10% progression rule, ACWR recovery periodization & deload cycles | docs/formulas/weekly-mileage.md | | files | Tool | FIT, GPX, TCX, KML and CSV parsing, GeoJSON export, cropping, merging, GPS redaction and local Web Worker conversion | docs/files/running-file-converter.md | | track-analysis | Tool | Recorded-vs-GPS provenance, timestamp/progress alignment, interpolation, split and drift indicators | docs/files/track-analysis.md | | race-week | Planner | Localized race-week template, pacing/fueling timeline and RFC 5545 calendar export | docs/formulas/race-week.md | | audio | Tool | Cadence target/tap tempo, cancellable Web Audio metronome, WAV and optional MP3 export | docs/audio/cadence-metronome.md | | timers | Tool | Workout schema/presets, timeline, elapsed-time strength state machine and cue adapter | docs/timers/strength-timer.md | | i18n | Guide | Custom dictionaries, locale registration, and fallback resolution | docs/guides/i18n-and-customization.md |


Operating Ranges & Principles

All algorithms conform to strict physiological domains:

| Module | Input Boundaries | Return Contract on Out-of-Domain | |:---|:---|:---| | VDOT | Distance: 400 m – 200 km; Time: 30 s – 100 h; VDOT: 15 – 85 | Returns null | | Race Predictor | Base/Target Distance > 0 m; Exponent: 1.00 – 1.30 | Returns null | | Heart Rate Zones | Max HR: 80 – 240 bpm; Resting HR: 30 – 120 bpm (Max > Rest) | Returns null | | Age Grading | Age: 5 – 100 years; Standard road distances (5K, 10K, Half, Full) | Returns null | | Running Efficiency | Cadence: 100 – 260 spm; GCT: 100 – 500 ms; Duty Factor < 50% | Returns null for invalid components | | Pace Solver | Distance: 0.01 – 10,000; Pace: 60 – 3600 s/unit; Exactly 2 defined fields | Returns null | | Weekly Mileage | Volume: 1 – 500 units; Max Weekly Increase: 1% – 50% | Returns null | | Track Analysis | 2+ GPS points; comparison samples: 2–10,001 | Throws FileConversionError | | Race Week | Standard 5K/10K/Half/Marathon; volume: 1–500; frequency: 2–7 | Returns null | | Cadence Audio | 120–210 spm; export: 1–900 s; WAV: 8–192 kHz | Throws CadenceAudioError | | Strength Timer | 1–100 exercises; rounds: 1–10; import: ≤1 MiB | Throws StrengthTimerError |


Contributing

We welcome community contributions, sports science peer reviews, and bug reports! Please review CONTRIBUTING.md for local development workflows and test guidelines.

# Run unit tests
npm test

# Verify type definitions
npm run typecheck

# Build dual bundle & browser distribution
npm run build

# Verify the packed ESM, CommonJS, and TypeScript consumer entry points
npm run test:package

# Measure coverage
npm run test:coverage

# In the Apex Run collection checkout, build and copy the browser bundles,
# source maps and license into both ../website/apexrun and ../website/apexrun-zh
npm run sync:website

License

MIT License © 2026 Slowbloom Studio