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

@mattduffy/calories

v1.5.7

Published

A dependency-free library to estimate energy expenditure, in calories, using either Pandolf-Santee, LCDA or Metabolic Equivalent Task equations.

Readme

Contents

Estimating Energy Expenditure and Calories Burned

This package is a dependency-free ES module that estimates calories burned during physical activities (walking, hiking, rucking, etc) with functions for both simple calorie estimates, and more advanced methods utilizing GPS data.

Creating accurate estimates of the number of calories burned during a physical activity period is notoriously difficult, especially when attempting to incorporate positional data. Most instances of estimating calories burned are simply calculated as an exertion effort based on body weight, time duration and a known MET (Metabolic Equivalent Task) value for a given activity. This method doesn't include positional data such as distance, velocity or elevation changes. This can be considered a simple calorie estimate.

There are several, more advanced methods for estimating calories burned that do attempt to incorporate GPS data for a richer, more nuanced estimate. This package provides more advanced functions to calculate calories burned using either the Pandolf-Santee, Minimum Mechanics or LCDA predictive models.

Using

npm install --save @mattduffy/calories
import {
  lcdaCalories,
  simpleCalories,
  pandolfCalories,
  calorieEnsemble,
  minimumMechanicsCalories,
} from '@mattduffy/calories'

Simple Calories

Using Metabolic Equivalent Tasks

The simple calories calculation takes 3 parameters: minutes, weights, and MET, and returns a positive floating point value. The function throws an Error if the required parameters are missing, or of the wrong type. The required body weight parameter is measured in kilograms. You need to know the MET value for any specific activity you are measuring. A good list of MET values can be found at the Compendium of Physical Activities.

// The number of minutes MET activity is performed.
// Required and must be greater than zero.
const minutes = 35
// Weights, measured in Kilograms.  Body weight is
// required.  If a ruck weight was carried, include
// that too.  Optionally include weight of water
// carried as well.
// useful conversions:
//   1Kg == 2.2lbs or 1lbs === 0.45359Kg
//   1 fl oz of water === 1.042oz or 15.355 fl oz === 1lbs or 33.781 fl oz === 1kg
const weights = {
  body: 70, // required Kg
  ruck: 5,  // optional Kg
  water: 0, // optional Kg
}
// The MET number for a particular task.  For example:
// Walking slowly:         2.0
// Walking, 2.5 mph:       3.0
// Walking, for pleasure:  3.5 <-- Default value
// Weight lifting:         5.0
// Backpacking:            7.5
// Swimming:               8.0
// Rope jumping (84/min): 10.5
// Jogging, 6.8 mph:      11.2
const MET = 7.5 // Backpacking
const simple_calories = simpleCalories(minutes, weights, MET)
console.log(simple_calories)
// 143.381765625

Advanced Calorie Predictive Models

The Pandolf-Santee Model

This method of estimating energy expenditure is based on the Pandolf-Santee equation. The required parameters include an array of GPS coordinate data, and a body weight, measured in kilograms. Additional values can be provided in the options parameter; including the weight of a ruck load, the weight of additional water carried, and the type of terrain covered. There is also an option to smooth out the GPS elevation data. If the elevation data comes from a GPS sensor (rather than a barometric pressure sensor), it can be useful to smooth out the values with a rolling average because some GPS sensors can provide pretty jittery values for this field.

The pandolfCalories() function expects the coordinates parameter to be an array of arrays with the following format: [longitude, latitude, heading, altitude (m), accuracy (m), timestamp (ms)]. In this particular implementation, the heading and accuracy fields are not currently being used. Those fields can be empty or null. The fields for longitude, latitude, altitude and timestamp must be valid, non-null values. Altitude is measured in meters and the timestamp is Javascript default milliseconds.

The Santee correction factor for including downhill travel (negative grade values) is being applied when calculating the advanced estimates. This correction factor results in energy expenditure estimates that are typically about 16% - 25% higher when the GPS data contains significant amounts of downhill travel vs the original pandolf equation that couldn't account for negative grade values.

To calculate the results, the pandolf-santee model is executed over each consecutive pair-wise GPS points in the the coordinates array. Each of these pair-wise calculations is referred to as a segment. To get the final results, the segments are aggregated together. The boolean options property options.returnSegments controls whether an array of segment results is included in the function return value. The default value is false. Setting this to true includes this segments array.

const cooords = [
//[gps longitude,       gps latitude,      heading (in deg), altitude (meters),  gps accuracy (m),  timestamp (ms)], 
  [-122.18413372578239, 37.82762389320808, 289.500900176593, 410.60703301243484, 6.935079779936697, 1781733047033],
  [-122.18414765202105, 37.827625731095864, 291.71648070840496, 411.11239344626665, 6.935079779936697, 1781733048037],
  [-122.1841647535281, 37.82762780033335, 286.09169894511865, 410.85964420530945, 7.091013324104003, 1781733049031],
  [-122.18417633225566, 37.827625146283225, 284.4996500921467, 411.22145825996995, 7.091013324104003, 1781733050034],
  ...,
]
// Optional terrain characterization values include:
// Paved road / treadmill:              1.0
// Dirt path / packed trail:            1.1
// Light off-trail, grass:              1.2
// Soft sand, deep grass, loose gravel: 1.5
// Snow, heavy brush, swamp:            1.8

// To remove GPS elevation jitter, set smooth to true.
// The window size sets amount of smoothing, 5 is usually
// sufficient.  If elevation data comes from a barometric
// sensor, set smooth to false.
const options = {
  bodyWeightKg: 70,     // Required, measured in kilograms
  loadKg: 13.6,         // optional, measured in kilograms
  waterKg: 0,           // optional, measured in kilograms
  terrain: 1.1,         // optional, default value = 1.1
  smooth: true,         // optional, smooth GSP elvation values
  smoothWindow: 5,      // optional, default value = 5
  returnSegments: false // optional, return calculated GPS segments
}
const pandolf_calories = pandofCalories(coords, options)
console.log(pandolf_calories)
// {
//   totalKcal: 581.492205191523,
//   totalDistanceM: 5544.758689134893,
//   totalDurationSec: 3829.9640000000027,
//   avgSpeedMs: 1.4477312813214143,
//   segments: [{...},{...},...], /* only included if options.returnSegments === true */
// }

The LCDA Model

A much more recently developed predictive model for calculating energy expenditure over distance, while carrying a load is the Load Carrying Decision Aid model. LCDA is considered to be slightly more accurate than the Pandolf model at the extra expense of requiring parameters to calculate basal metabolic rate.

The coords and options parameters for lcdaCalories() are the same as for the above pandolfCalories() function. The values in the BMR parameter object are used to create a value for basal metabolic rate using the Mifflin-St Jeor equation.

const BMR = {
  height: 162.5 // Required, measured in centimeters
  weight: 70    // Required, measured in kilograms
  age: 45       // Required, measured in years
  sex: 'm'      // Required, either 'm' or 'f'
}
const options = {
  bodyWeightKg: 70,     // Required, measured in kilograms
  loadKg: 13.6,         // optional, measured in kilograms
  waterKg: 0,           // optional, measured in kilograms
  terrain: 1.1,         // optional, default value = 1.1
  smooth: true,         // optional, smooth GSP elvation values
  smoothWindow: 5,      // optional, default value = 5
  returnSegments: false // optional, return calculated GPS segments
}
const lcda_calories = lcdaCalories(coords, BMR, options)
console.log(lcda_calories)
// {
//   totalKcal: 590.292205191523,
//   totalDistanceM: 5544.758689134893,
//   totalDurationSec: 3829.9640000000027,
//   avgSpeedMs: 1.4477312813214143
// }

The Minimum Mechanics Model

The Minimum Mechanics predictive model was developed by Ludlow & Weyland as a less complex model altrnative to the negative grade-corrective Pandolf-Santee model. This model incorporates the basal metabolic rate, like the LCDA model above, but forgoes terrain characterization. The function signature is the same as that for LCDA.

const BMR = {
  height: 162.5 // Required, measured in centimeters
  weight: 70    // Required, measured in kilograms
  age: 45       // Required, measured in years
  sex: 'm'      // Required, either 'm' or 'f'
}
const options = {
  bodyWeightKg: 70,     // Required, measured in kilograms
  loadKg: 13.6,         // optional, measured in kilograms
  waterKg: 0,           // optional, measured in kilograms
  smooth: true,         // optional, smooth GSP elvation values
  smoothWindow: 5,      // optional, default value = 5
  returnSegments: false // optional, return calculated GPS segments
}
const minMech_calories = minimumMechanicsCalories(coords, BMR, options)
console.log(lcda_calories)
// {
//   totalKcal: 476.211434723359,
//   totalDistanceM: 5544.758689134893,
//   totalDurationSec: 3829.9640000000027,
//   avgSpeedMs: 1.4477312813214143
// }

The Calorie Ensemble

If you would like to compare the results of each of the predictive models for a given hike's dataset, you can use the calorieEnsemble() function. This function maps each of the predictive models over each segment of the coordinates array in a single pass, to give comparative results. For this function, the BMR parameter is combined into the options parameter. You will notice that each of the predictive models gives a slightly different result for totalKcal. This is expected and indicative of the differences in the respective models.

const options = {
  bodyWeightKg: 70,     // Required, measured in kilograms
  loadKg: 13.6,         // optional, measured in kilograms
  waterKg: 0,           // optional, measured in kilograms
  smooth: true,         // optional, smooth GSP elvation values
  smoothWindow: 5,      // optional, default value = 5
  returnSegments: false // optional, return calculated GPS segments
  BMR: {
    height: 162.5       // Required, measured in centimeters
    weight: 70          // Required, measured in kilograms
    age: 45             // Required, measured in years
    sex: 'm'            // Required, either 'm' or 'f'
  },
}
const resultSet = calorieEnsemble(coords, options)
console.log(resultSet)
// {
//   lcda: {
//     totalKcal: 590.292205191523,
//     totalDistanceM: 5544.758689134893,
//     totalDurationSec: 3829.9640000000027,
//     avgSpeedMs: 1.4477312813214143
//   },
//   pandolf: {
//     totalKcal: 581.492205191523,
//     totalDistanceM: 5544.758689134893,
//     totalDurationSec: 3829.9640000000027,
//     avgSpeedMs: 1.4477312813214143
//   },
//   minMech: {
//     totalKcal: 476.211434723359,
//     totalDistanceM: 5544.758689134893,
//     totalDurationSec: 3829.9640000000027,
//     avgSpeedMs: 1.4477312813214143
//   }
// }

List Available Models

A list of model names, their respective function name, the authors associated with each model and a brief description is available with the models() function.

import { models } from '@mattduffy/calories'
console.log(models())
// {
//   models: [
//     {
//       name: 'Pandolf-Santee',
//       function: 'pandolfCalories',
//       desc: 'The Santee corrected version of the original energy expenditure model developed by USARIEM in the 1970s.  This model incorporates positional data, slope/grade, terrain characterizations, body weight and load carried to predict the energetic costs non-mechanized, cross-country movement, carrying loads.',
//       authors: [Array]
//     },
//     {
//       name: 'Load Carrying Decision Aid (LCDA)',
//       function: 'lcdaCalories',
//       desc: "Developed as part of a mission-planning software tool for the US military and published in 2017, this model attempts to provide more accurate energy expenditure predictions over steeper terrain variations while carrying heavier loads than previous models.  This model attempts to improve the original Pandolf-Santee model with modern GPS positional data and participant's BMR values.",
//       authors: [Array]
//     },
//     {
//       name: 'Minimum Mechanics',
//       function: 'minimumMechanicsCalories',
//       desc: `A predictive model published in 2017 which posits that the metabolic energy of the human walking economy can be accurately predicted using a minimum of three variables: "speed, surface grade, and total gravitational load".  This model uses GPS positional data, along with participant's BMR values to estimate total energy expeditures.`,
//       authors: [Array]
//     }
//   ],
//   collections: [
//     {
//       name: 'Calorie Ensemble',
//       function: 'calorieEnsemble',
//       desc: 'Perform all of the available predictive model calculations at once over a given dataset.'
//     }
//   ]
// }

Koa-style Router Middleware

Because this package is a dependency-free, single-file module, it also works well executing in the browser. If you are running a Koajs compatible web app server, you can use the getCaloriesJs() middleware function as a route handler to emit the module file as a text/javascript; charset=utf-8 response to an HTTP GET request. You can assign whatever URL route for the file that makes sense for your app, and have access to all the calorie estimating functions within the module.

import * as Koa from 'koa'
import { Router } from '@koa/router'
import { getCaloriesJs } from '@mattduffy/calories'

const app = new Koa.default()
const router = new Router()
// Create a GET route and assign the getCaloriesJs() function as the route handler.
// This example creates a 'named' route called calories.
// The route in this case is /js/calories.js, but it can be whatever fits your needs.
// The getCaloriesJs() handler function emits a full copy of the src/index.js module file.
router.get('calories', '/js/calories.js' getCaloriesJs)
app.use(router.routes())
<script type="module">
  import {
    pandolfCalories,
    lcdaCalories,
    minimumMechanicsCalories,
  } from '/js/calories.js'

  const pandolf = pandolfCalories(coords, options)
</script>

Sample Data

This package includes a sample data file to help illustrate the data format. sample_data.json is a GEOJson formatted data file containing a single LineString feature with a coordinates array that can be passed into the calorie functions. In this sample data, the features[0].properties.weights object contains the necessary weight values to supply in the options parameter of the calories functions (these weights are recorded in lbs so convert them to kgs).

The coordinates array in this sample data does not conform exactly to the GEOJson specification, which only defines longitude and latitude values in the array. No guarantee is given to the validity of values following latitude. In this case, an app tracking the progress of a hike is populating typical GPS values of accuracy, altitude, heading, and timestamp into the coordinate arrays in a format appropriate for the calorie functions.

import pandolfCalories from '@mattduffy/calories'
import sample_data from '@mattduffy/calories/sample_data.json' with { type: 'json' }

const coords = sample_data.features[0].geometry.coordinates
const opts = {
  bodyWeightKg: sample_data.features[0].properties.weights.body / 2.2, // convert lbs to kgs
  loadKg: sample_data.features[0].properties.weights.ruck / 2.2,       // convert lbs to kgs
}
const kcals = pandolfCalories(coords, opts)
console.log(kcals)
// {
//    totalKcal: 187.1436731904045,
//    totalDistanceM: 1899.4192932570354,
//    totalDurationSec: 949,
//    avgSpeedMs: 2.001495567183388,
// }