@verifyhash/wbgt-heat-stress
v0.1.0
Published
Zero-dependency heat-stress indices: NWS heat index, Environment Canada humidex, and a Wet-Bulb Globe Temperature (WBGT) approximation with risk flags.
Maintainers
Readme
wbgt-heat-stress
TODO (owner): pick the final npm name/scope before publishing. The npm package name is not finalized.
package.jsonkeeps the working slugwbgt-heat-stressas a placeholder — replace it (and the install line below) with the real published name/scope before anynpm publish. Graduation to npm is a needs-human decision, not something this project does.
A tiny, zero-dependency Node library for the three most-used heat-stress indices, each returned with a plain-language risk category:
heatIndex(tempC, relHumidityPct)— the US National Weather Service "feels-like" apparent temperature (Rothfusz regression).humidex(tempC, dewpointC)— Environment Canada's humidex comfort index.wbgt(tempC, relHumidityPct, opts)— a Wet-Bulb Globe Temperature approximation with the white/green/yellow/red/black flag band.
Every export is a pure function: no I/O, no network, no daemon, no dependencies, and no mutation of its arguments. Same inputs → same output. Units are Celsius, percent RH, and (for outdoor WBGT) m/s wind and W/m² solar.
Who it's for
- Occupational safety — flag heat-stress risk for outdoor/industrial crews against the WBGT flag conditions used by OSHA guidance and the US military.
- Sports & athletics — apply the American College of Sports Medicine WBGT activity bands for training and event go/no-go decisions.
- Weather & wellness apps — show an honest "feels like" number (heat index or humidex) without pulling in a heavy scientific package or calling an API.
If you already have a psychrometrics library, this one is complementary: it focuses on the stress indices and their risk bands, not on general moist-air math.
Install / use
Zero dependencies — vendor the folder or (after the owner finalizes the name)
npm install <final-name>.
const { heatIndex, humidex, wbgt, wbgtFlag } = require('wbgt-heat-stress');
heatIndex(32.22, 70);
// { heatIndexF: 105.9, heatIndexC: 41.1, risk: 'danger' }
humidex(30, 15);
// { humidex: 33.97, risk: 'some discomfort' }
wbgt(30, 50);
// { wbgtC: 29.26, flag: 'green', mode: 'indoor' }
wbgt(30, 50, { solarWm2: 900, windMs: 1.5 });
// { wbgtC: ~31.0, flag: 'yellow', mode: 'outdoor' }
wbgtFlag(31.5); // 'red' — band a WBGT you measured elsewhereRunning the tests
One command, no framework, no dependencies:
node test/index.test.jsIt exits 0 on success and non-zero on any failure. The suite checks fixtures
at published reference points — a NWS heat-index table cell, an Environment
Canada humidex example, and every WBGT flag-band boundary — each within a stated
tolerance, plus the input guards.
The formulas (and their sources)
Heat index — NWS/NOAA Rothfusz regression
Apparent temperature from air temperature and relative humidity. The NWS first evaluates Steadman's simple formula; if that value is below 80 °F (26.7 °C) the Rothfusz regression does not apply and the simple value is used (the documented low-temperature fallback — below ~80 °F the heat index is essentially the air temperature). Otherwise the full Rothfusz polynomial runs, with the low-humidity (RH < 13 %) and high-humidity (RH > 85 %) corrections. This is the exact method behind the published NWS heat-index chart and is accurate to about ±1.3 °F. Source: Rothfusz, L.P. (1990), NWS Technical Attachment SR 90-23; Steadman, R.G. (1979).
Risk bands (NWS, °F): none < 80, caution 80–90, extreme caution 90–103,
danger 103–124, extreme danger ≥ 124.
Humidex — Environment Canada
humidex = Tair + 0.5555 * (e - 10)
e = 6.11 * exp(5417.7530 * (1/273.16 - 1/(Tdew + 273.15))) [hPa]Humidex is a unitless comfort index reported on the Celsius scale. When the dew
point implies dry air (e ≤ 10 hPa) humidex would fall below the air
temperature; Environment Canada does not report that, so the value is clamped to
the air temperature. Source: Masterton, J.M. & Richardson, F.A. (1979),
Environment Canada.
Comfort bands (°C-scale): none < 30, some discomfort 30–39,
great discomfort 40–45, dangerous ≥ 46.
WBGT — an APPROXIMATION (read this carefully)
True WBGT cannot be computed from air temperature and humidity alone. The
real index is WBGT = 0.7·Tnwb + 0.2·Tg + 0.1·Ta, where Tg is the temperature
of a 150 mm matte-black globe in the actual sun/wind and Tnwb is a naturally
ventilated wet-bulb — both require physical sensors. This library does not
pretend to that accuracy. It provides two documented approximations:
Indoor / shaded (default). The Australian Bureau of Meteorology simplified regression, valid where there is no direct solar load (indoors, or fully shaded):
WBGT = 0.567 * Ta + 0.393 * e + 3.94
e = (RH/100) * 6.105 * exp(17.27*Ta/(237.7 + Ta)) [hPa]This is the standard substitute when no globe sensor is available and is what many heat-safety apps display for indoor/shaded conditions.
Outdoor (when you pass opts.solarWm2). The shade estimate plus a coarse
solar-load term — direct sun raises the globe temperature and hence WBGT,
while wind ventilates the globe and lowers it:
dSolar = 3.2 * (solarWm2 / 1000) / sqrt(1 + windMs) [°C], capped at 4 °Cso ~1000 W/m² midday sun in light wind adds a few °C, tapering with wind.
Honest limits.
- The outdoor
dSolarterm is a rough heuristic, not a validated model. It is tuned to give plausible magnitudes, not sensor-grade accuracy. Do not use outdoor mode as the sole basis for a real occupational go/no-go decision in the sun — measure with a black-globe WBGT meter for that. - Even the indoor ABM regression carries its own scatter (order ~±1 °C) versus instrumented readings and was fit for typical outdoor screen conditions.
- Humidity must be a real measurement; a bad RH propagates directly into WBGT.
- This library computes numbers and risk bands only. It is not a substitute for an employer's heat-illness prevention program or medical judgement.
Flag bands (US military / American College of Sports Medicine), °C converted from the canonical °F cut-points:
| Flag | WBGT (°C) | WBGT (°F) | Meaning | |--------|-------------|-------------|----------------------------------| | white | < 27.8 | < 82.0 | low risk | | green | 27.8 – 29.3 | 82.0 – 84.9 | use discretion, hydrate | | yellow | 29.4 – 31.0 | 85.0 – 87.9 | active caution; limit exertion | | red | 31.1 – 32.1 | 88.0 – 89.9 | high risk; curtail hard activity | | black | ≥ 32.2 | ≥ 90.0 | extreme; cancel/relocate |
wbgtFlag(wbgtC) is exported separately so you can band a WBGT you obtained
from a real sensor.
License
MIT — see LICENSE. (Copyright holder is a placeholder pending owner sign-off.)
