@voltras/workout-analytics
v0.2.0
Published
Hardware-agnostic workout analytics library for analyzing reps, sets, estimating RPE/RIR, calculating strength (1RM), velocity profiles, and fatigue estimates
Maintainers
Readme
@voltras/workout-analytics
A hardware-agnostic TypeScript library for analyzing workout telemetry data. Process real-time exercise samples into structured reps and sets with automatic boundary detection and O(1) metric access.
Features
- Real-time Processing: Stream
WorkoutSampledata and get automatic rep/set boundaries - O(1) Metrics: Running aggregates computed incrementally - no re-scanning
- Immutable Data Structures: All operations return new objects, safe to share
- Hardware Agnostic: Works with any telemetry source that provides
WorkoutSampledata - TypeScript: Full type definitions included
Installation
npm install @voltras/workout-analyticsQuick Start
import {
MovementPhase,
createSet,
addSampleToSet,
completeSet,
getRepMeanVelocity,
getRepTempo,
} from '@voltras/workout-analytics';
// Create a new set
let set = createSet();
// Process samples as they arrive from your device
for (const sample of telemetryStream) {
set = addSampleToSet(set, sample);
}
// Finalize when done (trims trailing idle time)
set = completeSet(set);
// Access metrics
for (const rep of set.reps) {
console.log(`Rep ${rep.repNumber}: ${getRepMeanVelocity(rep).toFixed(2)} m/s, tempo ${getRepTempo(rep)}`);
}Core Concepts
WorkoutSample
The fundamental telemetry data point. Adapters convert device-specific data into this format.
interface WorkoutSample {
sequence: number; // Incrementing sequence (for drop detection)
timestamp: number; // Timestamp in ms since epoch
phase: MovementPhase; // IDLE, CONCENTRIC, HOLD, or ECCENTRIC
position: number; // Position in ROM (0 = start, 1 = full extension)
velocity: number; // Instantaneous velocity (m/s, always positive)
force: number; // Force reading (lbs, absolute value)
}Movement Phases
enum MovementPhase {
IDLE = 0, // Ready / resting
CONCENTRIC = 1, // Lifting phase (muscle shortening)
HOLD = 2, // Isometric hold at top of rep
ECCENTRIC = 3, // Lowering phase (muscle lengthening)
}Data Hierarchy
Set
└── Rep[]
├── concentric: Phase (lifting + hold at top)
└── eccentric: Phase (lowering + hold at bottom)
└── samples: WorkoutSample[]Rep boundaries are detected automatically: a new rep starts when transitioning from eccentric → concentric.
API Reference
Set Functions
| Function | Description |
|----------|-------------|
| createSet() | Create an empty set |
| addSampleToSet(set, sample) | Add a sample, returns new set with automatic rep detection |
| completeSet(set) | Finalize set, trims trailing idle from last rep |
| getSetRepCount(set) | Number of reps |
| getSetDuration(set) | Total duration in seconds |
| getSetTimeUnderTension(set) | Movement time excluding holds |
Rep Functions
| Function | Description |
|----------|-------------|
| createRep(repNumber) | Create a new rep (usually handled by Set) |
| addSampleToRep(rep, sample) | Add a sample, routes to appropriate phase |
| getRepDuration(rep) | Total rep duration in seconds |
| getRepTempo(rep) | Tempo string (e.g., "3-1-2-0") |
| getRepMeanVelocity(rep) | Mean concentric velocity (m/s) |
| getRepPeakVelocity(rep) | Peak concentric velocity (m/s) |
| getRepPeakForce(rep) | Peak force across both phases |
| getRepRangeOfMotion(rep) | ROM as position value (0-1) |
| getRepSamples(rep) | All samples in the rep |
Phase Functions
| Function | Description |
|----------|-------------|
| addSampleToPhase(phase, sample) | Add a sample to phase |
| rebuildPhaseFromSamples(samples) | Reconstruct phase from samples |
| getPhaseDuration(phase) | Total duration in seconds |
| getPhaseHoldDuration(phase) | Hold/pause time in seconds |
| getPhaseMovementDuration(phase) | Movement time (excluding holds) |
| getPhaseMeanVelocity(phase) | Mean velocity during movement |
| getPhaseMeanForce(phase) | Mean force during movement |
| getPhaseRangeOfMotion(phase) | Absolute position change |
Tempo
import { formatTempo, parseTempo } from '@voltras/workout-analytics';
// Format parts into standard tempo notation
formatTempo({ eccentric: 3, holdTop: 1, concentric: 2, holdBottom: 0 }); // "3-1-2-0"
// Parse tempo string into parts
parseTempo("3-1-2-0"); // { eccentric: 3, holdTop: 1, concentric: 2, holdBottom: 0 }Repository Structure
src/ - Public SDK
The main library with immutable data structures and O(1) metric access:
src/
├── models/
│ ├── types.ts # MovementPhase enum, PhaseNames
│ ├── sample.ts # WorkoutSample interface
│ ├── phase.ts # Phase type and functions
│ ├── rep.ts # Rep type and functions
│ ├── set.ts # Set type and functions
│ └── tempo.ts # Tempo formatting/parsing
└── index.ts # Public exportsv0/ - Reference Implementation
Contains analytics code extracted from the Voltras mobile app. Serves as reference for:
- Rep detection algorithms
- VBT (velocity-based training) utilities
- RPE/RIR estimation
- Load-velocity profiling
- Fatigue assessment
This code is being incrementally migrated and refined into src/.
Development
# Install dependencies
npm install
# Run tests
npm test
# Type check
npm run typecheck
# Lint
npm run lint
# Build
npm run buildLicense
MIT License - see LICENSE for details.
