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

@magnaboy/maps

v0.0.1

Published

Pure TypeScript coordinate maths, geographic bounds, DMS parsing and GeoJSON utilities.

Readme

@magnaboy/maps

Pure TypeScript coordinate maths, geographic rectangles, DMS parsing, point layout and GeoJSON builders. No runtime dependencies, React, MapLibre, DOM or Node APIs. Runs in browsers and Node.js. ESM with TypeScript declarations; follows this repository's Node 25+ tooling requirement.

Install

pnpm add @magnaboy/maps

Usage

import {
  XLocation, XRect, haversineDistance, destinationPoint,
  toRadians, fullDmsToDecimal, createPathGeojson, spreadMapItems
} from '@magnaboy/maps';

const start = { lat: 51.5, lng: -0.12 };
const end = destinationPoint(start, 1000, toRadians(90));
const distance = haversineDistance(start, end); // approximately 1000 metres
const tuple = new XLocation(start).toLngLat(); // [longitude, latitude]

const bounds = new XRect({ southWest: start, northEast: { lat: 51.6, lng: 0 } });
const inside = bounds.contains(end);
const coordinate = fullDmsToDecimal(`51°30'0"N 0°7'12"W`);

const path = createPathGeojson(
  [{ ...start, time: 1 }, { ...end, time: 2 }],
  point => ({ time: point.time })
);
const markers = spreadMapItems([start, start], {
  maxDistanceMeters: 10,
  radiusMeters: 20
});

API and conventions

Location (also exported as ILocation) contains lat and lng in decimal degrees. GeoJSON uses [lng, lat]. Distances are metres. The earth model is a sphere with radius EARTH_RADIUS_M = 6_371_000; it is not an ellipsoidal survey model.

| Export | Behaviour | | --- | --- | | distanceMeters(aLat, aLng, bLat, bLng) / haversineDistance(a, b) | Great-circle distance | | toRadians, toDegrees, normalizeHeading | Angle conversion; normalized heading in [0, 360) degrees | | offsetMeters(lat, lng, meters, bearingRad) | Local flat-earth offset | | bearingTo(fromLat, fromLng, toLat, toLng) | Local flat-earth bearing in radians, clockwise from north | | destinationPoint(from, meters, bearingRad) | Great-circle destination; longitude normalized to [-180, 180) | | XLocation | Clone, distance, cardinal movement, random bearing displacement, JSON/string/tuple conversion | | XRect | Width/height, approximate area, centre, containment, expansion and random sampling | | dmsToDecimal / fullDmsToDecimal | Parse one DMS coordinate / latitude-longitude pair | | spreadMapItems(items, options) | Spread nearby groups on circles, preserving extra fields and input order | | roundLatLngs(location, gridMeters) | Approximate grid rounding with explicit metre spacing | | pointsToGeoJson(points, properties?) | Point feature collection | | createPathGeojson(points, properties?) | Line followed by point features; omit the line for fewer than two points | | isValidLocation / assertLocation | Check finite coordinates and latitude/longitude ranges |

The root exports all APIs. @magnaboy/maps/geo and @magnaboy/maps/geojson offer focused imports. GeoJSON structural types are exported without an ambient GeoJSON namespace or external type dependency.

Limits and input behaviour

  • Existing low-level maths and class constructors expect valid numeric coordinates; they do not validate input. Use assertLocation at input boundaries. Local offsets, cardinal movement and bearingTo are for short distances away from poles and the antimeridian. They do not wrap longitude or constrain latitude. Use destinationPoint for spherical movement across those boundaries.
  • destinationPoint validates coordinates and finite distance/bearing. Negative distance moves in the opposite direction. moveRandom chooses a bearing at exactly the requested distance; it does not sample within a disk.
  • Rectangles use numeric latitude/longitude intervals, not wrapped intervals. They do not model rectangles across the antimeridian. contains and random sampling accept inverted corners; signed width/height preserve corner order. expand expects ordered corners. Metric area is width times height, an approximation for small regions. Sampling is uniform in degrees, not surface area. randomPointsEven uses jittered grid cells and accepts nonnegative integer counts, including zero.
  • DMS accepts ASCII or Unicode degree/minute/second marks and a required hemisphere. Minutes/seconds must be below 60; latitude/longitude limits apply. Pairs require latitude first, separated by whitespace or a comma. Malformed input throws RangeError.
  • Point layout and GeoJSON builders reject invalid coordinates with RangeError. They do not mutate the input. Spreading is deterministic, order-dependent and O(n²): each group uses its first point as the anchor, not transitive clustering. All output items are shallow copies; nested metadata retains its references.
  • Rounding uses longitude scale at the input latitude, so it is an approximation, not a global projected grid or privacy guarantee. Spacing must be finite and positive. Pole longitude is set to zero.
  • GeoJSON builders include only properties returned by the callback; default properties are empty. They preserve path order and do not split lines crossing the antimeridian. Callers must supply JSON-serializable properties.

Development

From this repository root:

pnpm --filter @magnaboy/maps build
pnpm --filter @magnaboy/maps test:types
pnpm --filter @magnaboy/maps test:unit
pnpm --filter @magnaboy/maps check:publish

Tests retain the extracted maths/class regression cases and add generic utility and boundary cases. Coverage uses the shared repository thresholds. prepack builds and checks dist/index.js; README packing follows the shared hide/restore convention.

Extraction from CX

This package extracts the pure utilities from cx/packages/maps. CX remains operational with its existing code until this package is published and installed there.

  • Replace CX's core imports with @magnaboy/maps or @magnaboy/maps/geo after publication.
  • Location types are now local; no @cx/schemas dependency exists.
  • XLocation.distanceTo and XRect.contains also accept plain coordinate objects.
  • spreadMapItems now requires grouping distance and radius, returns copies, and rejects invalid coordinates instead of dropping them.
  • roundLatLngs now requires grid spacing and does not apply the old fixed decimal truncation.
  • Replace duplicate pathPointsToGeoJson / createPathGeojson calls with createPathGeojson; pass date/thumbnail properties explicitly when the app needs them.
  • Replace createClipFeatures with pointsToGeoJson(items, item => item).features; normalize string coordinates in the app first.
  • Keep React hooks/components, clip/entity types, Austin constants, map styles, controls and rendering in CX.