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

gnss-js

v2.6.0

Published

Comprehensive GNSS library for JavaScript — time scales, coordinates, RINEX parsing, RTCM3 decoding, orbit computation, and signal analysis

Readme

gnss-js

A comprehensive, dependency-free GNSS toolkit for JavaScript and TypeScript — from raw receiver bytes to a positioning solution, and everything between. Runs in Node.js, browsers, Deno, Bun, and Workers.

It decodes the formats a GNSS workflow actually meets in the wild (RINEX, RTCM 2/3, and the Septentrio/u-blox/NovAtel/Trimble/BINEX binary logs), reconstructs broadcast navigation down to the raw subframe, and solves positions from single-point all the way to PPP with integer ambiguity resolution — with consistent units and explicit JSDoc throughout.

Install

npm install gnss-js

Everything is exposed through subpath exports (gnss-js/rinex, gnss-js/positioning, …), so bundlers only pull in what you import.

What's inside

  • Formats in — RINEX 2/3/4 obs + nav (plain, Hatanaka .crx, .gz), SP3, RINEX CLK, IONEX, SINEX bias; RTCM3 (MSM + legacy obs, ephemeris, SSR/IGS-SSR, station); RTCM 2.x; and the receiver binaries SBF, UBX, NovAtel OEM4, Trimble, BINEX.
  • Formats out — RINEX 2/3/4 observation + navigation writers and Hatanaka (CRINEX) compression.
  • Navigation — Keplerian/GLONASS ephemeris handling plus raw-frame decoding of GPS LNAV/CNAV, Galileo I/NAV + F/NAV, BeiDou D1/D2, GLONASS strings, and Galileo HAS (E6 C/NAV) corrections.
  • Orbits — satellite position/velocity, Doppler, DOP, azimuth/elevation, pass prediction and almanac propagation.
  • Positioning — SPP, static and kinematic float PPP, PPP-AR (LAMBDA + wide-/narrow-lane FCB estimation), post-processed RTK, DGNSS, and SBAS/DFMC augmentation.
  • Quality — multipath, cycle slips, completeness and slant-TEC ionosphere analysis, with SINEX-DCB calibration.
  • Live — NTRIP client and a self-detecting RTCM/receiver stream stats accumulator.
  • Foundations — GNSS time scales, ECEF/geodetic coordinates, 14-parameter reference-frame transforms, signal/frequency definitions and physical constants.

Usage

Time, coordinates & reference frames

import { getGpsTime, getTimeOfWeek, getWeekNumber } from 'gnss-js/time';
import {
  geodeticToEcef,
  ecefToGeodetic,
  vincenty,
  deg2rad,
} from 'gnss-js/coordinates';
import { transformFrame } from 'gnss-js/frames';

const gpsTime = getGpsTime(new Date()); // ms since GPS epoch
const [x, y, z] = geodeticToEcef(deg2rad(48.8566), deg2rad(2.3522), 35);

// Time-dependent 14-parameter Helmert (IERS/EPSG): ITRF88–ITRF2020,
// ETRF2000/2014/2020, NAD83(2011). 'WGS84' aliases ITRF2020.
const itrf = transformFrame(
  [3924687.7, 301132.8, 5001910.8],
  'ETRF2000',
  'ITRF2020',
  2010.5
);

RINEX — read, write & products

import {
  parseRinexStream,
  parseNavFile,
  parseSp3,
  parseClk,
  parseIonex,
  writeRinexObsBlob,
  writeRinexNav,
  writeCrx,
} from 'gnss-js/rinex';

// Streaming observation parser — plain, Hatanaka .crx, or .gz
const { header } = await parseRinexStream(
  file,
  (pct) => {}, // optional progress
  undefined, // optional AbortSignal
  (time, prn, codes, values) => {
    /* per-satellite obs callback */
  }
);

const nav = parseNavFile(navText); // KeplerEphemeris[] | GlonassEphemeris[]
const sp3 = parseSp3(sp3Text); // precise orbits
const clk = parseClk(clkText); // precise clocks

// Writers: RINEX 2/3/4 obs + nav, and Hatanaka compression
const rnx = writeRinexObsBlob(header, epochs);
const crx = writeCrx(rnx); // → CRINEX

Receiver binary formats

One decoder per receiver family; each returns measurement epochs, and a companion nav parser reconstructs broadcast ephemeris from the raw frames.

import { parseSbfMeas, parseSbfNav, parseSbfHas } from 'gnss-js/sbf'; // Septentrio
import { parseUbxRawx, parseUbxRawNav } from 'gnss-js/ubx'; // u-blox
import { parseNovatelRange, parseNovatelNav } from 'gnss-js/novatel'; // NovAtel OEM4
import { parseTrimble, parseTrimbleNav } from 'gnss-js/trimble'; // Trimble
import { parseBinex } from 'gnss-js/binex'; // BINEX

const sbf = parseSbfMeas(bytes); // measurement epochs + counts
const nav = parseSbfNav(bytes); // GPS/GAL/BDS/GLO ephemeris from raw blocks
const has = parseSbfHas(bytes); // Galileo HAS (E6 C/NAV) SSR corrections

RTCM (RTCM3, RTCM2, SSR)

import {
  Rtcm3Decoder,
  decodeObs,
  decodeEphemeris,
  decodeSsr,
  decodeIgsSsr,
  updateStreamStats,
  createStreamStats,
} from 'gnss-js/rtcm3';

const decoder = new Rtcm3Decoder();
decoder.addData(chunk); // Uint8Array from an NTRIP stream
for (const frame of decoder) {
  const obs = decodeObs(frame); // ObsEpoch | null — MSM4-7 or legacy 1001-1012
  const eph = decodeEphemeris(frame); // broadcast ephemeris (all constellations)
  const ssr = decodeSsr(frame); // orbit/clock/bias corrections (1057-1068)
  const igs = decodeIgsSsr(frame); // IGS-SSR 4076 (multi-GNSS + phase bias + iono)
}
import { Rtcm2Decoder, rtcm2Observation, rtcm2Station } from 'gnss-js/rtcm2';

// Legacy RTCM 2.x — a wholly different wire format (30-bit words, 6-of-8)
const frames = new Rtcm2Decoder().decode(bytes);

Orbits, visibility & Doppler

import {
  computeAllPositions,
  computeVisibility,
  computeDop,
  dopplerHz,
} from 'gnss-js/orbit';

const positions = computeAllPositions(ephemerides, times, rxEcef);
const vis = computeVisibility(ephemerides, rxEcef, startMs, endMs, 300, 10);
// vis.passes: rise/peak/set; vis.pdop / vis.visibleCount per epoch;
// vis.elevation[prn]: elevation timeline for plotting.

Positioning — SPP → PPP → PPP-AR / RTK

import {
  solveSpp,
  ionoFree, // single-point
  solvePpp, // static/kinematic float PPP + optional AR
  postProcessRtk, // rnx2rtkp-style relative positioning
  solveDgnss, // code-differential
  SbasProcessor, // SBAS / DFMC augmentation
} from 'gnss-js/positioning';

// Single-point: ~10 m single-frequency; ionoFree(p1,p2,f1,f2) for metre-level.
const spp = solveSpp(pseudoranges, ephemerides, epochMs);

// Precise point positioning against SP3/CLK products (dm→cm; AR to cm).
const ppp = solvePpp(pppEpochs, sp3, pppOptions);

// Post-processed RTK: base + rover obs, ephemeris, base ECEF → fixed track.
const rtk = postProcessRtk(baseObs, roverObs, ephemerides, baseEcef);

Signal quality & ionosphere

import {
  analyzeQuality,
  parseSinexBiasDcb,
  applyIonoDcb,
} from 'gnss-js/analysis';

// One re-parse pass: multipath (per band, Anubis-style), cycle slips,
// completeness, and slant-TEC series.
const q = await analyzeQuality(file, header);

// Calibrate STEC with satellite DCBs (ESA .BIA / CAS .BSX); receiver bias
// from the night-time floor.
const { result, receiverDcbTecu } = applyIonoDcb(
  q.iono,
  parseSinexBiasDcb(biasText, epochMs)
);

The individual accumulators (MultipathAccumulator, CycleSlipAccumulator, CompletenessAccumulator, IonoAccumulator) are exported too, for a custom parseRinexStream pass.

NTRIP, NMEA & ANTEX

import { fetchSourcetable, connectToMountpoint } from 'gnss-js/ntrip';
import { parseNmeaFile, computeStats } from 'gnss-js/nmea';
import { parseAntex } from 'gnss-js/antex';

const { reader, abort } = await connectToMountpoint(
  'https://proxy.example.com',
  {
    host: 'caster.example.com',
    port: 2101,
    mountpoint: 'MOUNT',
    username: 'user',
    password: 'pass',
    version: '2.0',
  }
);

const track = parseNmeaFile(nmeaText); // fixes, satellites, per-sentence records
const antex = parseAntex(antexText); // antenna PCO/PCV calibrations

Constants & signals

import { C_LIGHT, FREQ, SYSTEM_NAMES } from 'gnss-js/constants';
import { CONSTELLATIONS, computePsdDb } from 'gnss-js/signals';

FREQ['G']['1']; // 1575.42e6 Hz (GPS L1)
SYSTEM_NAMES['E']; // "Galileo"

Unit conventions

All functions use consistent units, with explicit @param/@returns JSDoc:

| Quantity | Unit | | ----------- | ---------------- | | Time values | milliseconds | | Angles | radians | | Distances | meters | | Frequencies | Hz |

Roadmap

  • Class-based API — ergonomic wrappers (GnssTime.fromUtc(date).gps, Position.fromGeodetic(...).utm) over the functional core.
  • RTCM3 MSM1–3 and NavIC 1041 ephemeris decoding.
  • Real-time SSR/HAS application — feeding decoded corrections into a live PPP solve.

Development

pnpm install
bash scripts/fetch-test-data.sh   # RINEX test fixtures (~5 MB, checksummed; gitignored)
pnpm test
pnpm run lint
pnpm run build

Without the fixtures, the data-backed suites skip silently (describe.skipIf), so run the fetch script before trusting a green run.

Releasing: bump the version and push the tag — CI publishes to npm via Trusted Publishing and creates the GitHub Release:

npm version patch   # or minor/major; updates package.json + creates the tag
git push --follow-tags

Developing against gnsscalc without publishing:

cd ../gnsscalc && pnpm link ../gnss-js   # then `pnpm run build --watch` here
# undo with: pnpm unlink gnss-js && pnpm install

License

This project is dual-licensed:

  • AGPL-3.0 — free for open-source projects. Any software that uses gnss-js must also be open-sourced under a compatible license.
  • Commercial license — for proprietary/closed-source use. Contact [email protected] for terms.