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

@gum-jsx/maps

v2.0.0

Published

Static geographic maps for Gum.

Readme

@gum-jsx/maps

Static projected maps for Gum. The package accepts GeoJSON or TopoJSON, projects geometry with d3-geo, and draws it through Gum's vector path system. It does not fetch data while rendering.

For complete, offline figures, see the Maps gallery in the main docs.

Bundled geography

The package includes two small TopoJSON atlases, available without file loading or network access:

| Accessor | Source | Feature IDs | | --- | --- | --- | | world_countries(options?) | world-atlas 2.0.2, 1:110m countries | Three-digit country IDs, plus three stable local IDs | | us_states(options?) | us-atlas 3.0.1, 1:10m states and territories | Two-digit state FIPS IDs |

Each call returns a fresh TopoJSONSource with its version and source URL in provenance. You can inspect or modify its data without affecting later calls. See bundled data for the original files, licenses, and local IDs.

Pass { ids: ['276', '040'] } to world_countries to select Germany and Austria, or { ids: ['06', '32'] } to us_states for California and Nevada. IDs are exact strings, including leading zeros. Unknown IDs are errors; repeated IDs select a feature once and source order is retained. Omit ids for everything, or use ids: [] for no features. Filtering preserves shared TopoJSON arcs and rebuilds borders from the selected geometries. GeoDataOptions describes this option.

import { render_element, px } from '@gum-jsx/core'
import { GeoMap, world_countries } from '@gum-jsx/maps'

const world = world_countries()

const result = render_element(new GeoMap({
  source: world,
  width: px(900),
  height: px(500),
  fit_to: 'sphere',
  padding: px(12),
  background: '#dceef7',
  styles: { '840': { fill: '#4079ad' } },
  border_color: '#ffffff',
  border_width: px(0.7),
}))

if (result.kind === 'svg') await Bun.write('world.svg', result.svg)

The CLI includes the map elements and accessors by default, alongside math. For example, save this as world.jsx:

<GeoMap
  source={world_countries()}
  width={px(900)}
  height={px(500)}
  background={interp(white, blue, 0.15)}
  styles={id => id === '840' ? { fill: blue } : undefined}
/>

Then render it with the CLI:

gum world.jsx -o world.svg

Gum .jsx files use the plugin's exports directly, without package imports. For an embedded evaluator, import the package with import * as maps from '@gum-jsx/maps', then construct new Evaluator({ scope: maps }). In JSX, write dashed property names such as fit-to and border-color.

Your own source

geojson(data) expects RFC 7946 longitude/latitude coordinates and winding by default. It stitches antimeridian and polar cuts and changes polygon winding for D3's spherical pipeline. Use { winding: 'd3' } only for GeoJSON that already uses D3/TopoJSON's convention. topojson(data, objectName) reads a named Topology object and retains its shared arcs for one-pass borders.

Both constructors accept ids too: geojson(data, { ids: ['A', 'B'] }) or topojson(data, 'regions', { ids: ['A', 'B'] }). Filtering honors id_property and does not mutate the input. Numeric source IDs are matched as strings; features without explicit IDs cannot be selected by generated positional IDs.

Use the IDs present in your own source. The example key 840 is the numeric ISO country ID used by some world TopoJSON files. Style dictionaries reject unknown IDs, and all features must have explicit IDs when feature styles are used. For GeoJSON whose IDs live in properties, set id_property, for example geojson(data, { id_property: 'ADM0_A3' }). Name matching is left to the data preparation step.

Feature styles

styles accepts either (id: string) => GeoStyle | undefined or an ID-to-style dictionary. For example, use styles: id => ({ fill: colors[id] }), or styles: { '840': { fill: '#4079ad', stroke: '#263238', stroke_width: px(2) } }. Missing entries, undefined callback results, and omitted fields inherit the map's style. The exported GeoStyle, GeoStyleMap, and GeoStyles types describe these forms.

Styles support Gum paint properties, including fill, opacity, stroke, stroke_width, stroke_dasharray, caps and joins, plus point_radius for point features. Theme colors and px/em/fractional lengths resolve during layout. Feature strokes are drawn after the shared borders. Shared borders keep their map-wide paint; set border_mode: 'none' to draw only feature outlines, whose adjacent edges can overlap.

Callbacks are evaluated once per feature when constructing a map with source; their results are snapshotted and are not reevaluated during resizing. With source_resource, use a style dictionary so the element remains an immutable description independent of a particular layout pass.

Projection and layout

| Preset | Good starting point | | --- | --- | | naturalEarth1 (default) | General world illustrations | | equalEarth | World thematic maps with comparable areas | | albersUsa | United States with Alaska and Hawaii insets | | orthographic | Globe views | | equirectangular | Simple rectangular world views | | mercator | Views where Mercator is specifically wanted |

The default fit target is sphere, except for albersUsa, which fits data. Set fit_to: 'data' for a regional map or fit_to: ['feature-id'] for a stable selected extent. The fit target does not depend on feature styles.

Use bounds: [west, south, east, north] to fit a coordinate box in longitude/latitude degrees, independently of source features. Bounds fit a sampled geographic rectangle under the chosen projection and clip the map to its projected outline, including water, borders, and child elements. Fitting preserves proportions: a narrow region in a wide allocation leaves transparent space beside it. Source features remain intact; clipping only limits the rendered view.

Combine source selection and bounds fitting:

<GeoMap
  source={world_countries({ ids: ['276', '040'] })}
  bounds={[5, 45, 18, 56]}
  background={lightgray}
/>

Longitudes must be in [-180, 180], latitude limits in [-90, 90] with south less than north, and longitude span must be positive. West greater than east crosses the antimeridian; [170, -20, -170, 20] with rotate={[-180, 0, 0]} gives a continuous Pacific view. Bounds preserve the chosen rotation and clipping, and fit only their visible portion. A target with no visible extent is an error. Use [-180, south, 180, north] for a full longitude span. The exported GeoBounds type names the four components. When supplied, bounds overrides fit_to for fitting, clipping, and natural sizing; the unused fit target is not looked up. Without bounds, fit_to accepts only 'sphere', 'data', or an array of IDs. An empty selection can still use sphere or bounds fitting, but cannot fit to data.

Set center: [longitude, latitude] to pan that geographic point to the viewport midpoint after fitting. The fit target still determines the scale; panning can move some fitted geometry outside the viewport. Omit center to keep the fit target centered automatically. center does not turn the globe or change which hemisphere is visible. Use rotate: [-longitude, -latitude, 0] to face a location on an orthographic globe. When both are supplied, center still refers to the original geographic coordinates.

rotate, clip_angle, and precision follow D3's degree/pixel conventions. albersUsa has fixed center, rotation, and clipping; it excludes US territories beyond the lower 48 states, Alaska, and Hawaii.

The map derives its natural proportions from the projected fit target, including rotation and clipping, and adds padding around that extent. Specify only height to derive the width, or only width to derive the height. Box, Frame, and stacks can hug the resulting size. With no dimensions or offers, the map fits within 720 × 400 px. An explicit aspect overrides the preferred outer ratio; two exact dimensions retain their allocated rectangle. Explicit width and height use ordinary Gum sizing. Padding defaults to 0. padding, border_width, and point_radius use Gum lengths; px() makes the intended unit unambiguous.

Nest core marks and annotations inside GeoMap. Use {lon, lat} records in degrees for mark coordinates and direct-child pos values. The aliases [longitude, latitude] and {x: longitude, y: latitude} also work. Both components are required; mixing lon/lat with x/y in one record is an error. Points, sampled Arrow routes, and labels follow the map's fit, center, rotation, padding, and resizing. Hidden points are omitted and sampled paths break at them. Child marker sizes, arrowheads, and text remain layout lengths. Set route strokes explicitly, since children inherit map styles.

<GeoMap source={world_countries()} background="lightblue">
  <Points points={[{lon: 2.35, lat: 48.86}]} point-size={px(8)} fill="red" />
  <Text pos={{lon: 2.35, lat: 48.86}} anchor={['start', 'end']}>Paris</Text>
</GeoMap>

Core projections map only supplied points; they do not resample paths or split antimeridian crossings. Supply sampled routes and separate marks at seams as needed. space="local" opts marks out; a Cartesian pos such as [px(12), px(24)] positions annotations in local space. Local lengths require x and y; geographic components must be numeric. GeoJSON, TopoJSON, center, and the geographic projection helpers retain their established array formats.

For a point annotation outside the map subtree, project_geo_point(source, view, width, height, [longitude, latitude]) returns local pixel coordinates or null if hidden by the projection's spherical clipping. Bounds and viewport clips apply to the GeoMap subtree; external annotations need their own clipping. Pass the same projection, fit target, and padding to this helper as to GeoMap. The helper's padding value is a number of pixels because it does not run within Gum layout.

Borders and large sources

background fills the projected sphere behind the features, providing a water color while leaving the area outside the projection transparent. It defaults to none and accepts the same color strings and theme paints as other backgrounds. The fill follows the map's projection, rotation, clipping, and fitted extent; it forms a circle for an orthographic globe. With bounds fitting, the sphere is cropped to the projected geographic box; all maps also clip to their allocated rectangle. Albers USA uses its composite projection's clip regions. This fills gaps and polygon holes in the supplied geography, so lakes appear only where the source leaves them unfilled. Use an outer Box background to give the surrounding rectangle a separate color.

border_mode accepts all (default), interior, or none. With TopoJSON, the chosen borders are drawn once from a shared-arc mesh. GeoJSON can draw all feature edges, but adjacent edges are repeated; interior requires TopoJSON. Fills are always drawn before borders. Points render as small circular paths.

One GeoMap owns one source. For a large source used in several maps, install it once on a LayoutPass and pass source_resource rather than copying it into each map's immutable props:

import { LayoutPass, render_element } from '@gum-jsx/core'
import { prepare_geo_source } from '@gum-jsx/maps'

const prepared = prepare_geo_source(world)
const pass = new LayoutPass({ geography: { value: prepared, version: '2026-09' } })
const result = render_element(new GeoMap({
  source_resource: 'geography',
  width: px(900),
  height: px(500),
}), { pass })

Data preparation

For general world and regional illustrations, start with a versioned Natural Earth Admin 0 countries or Admin 1 states/provinces dataset. Choose 110m for a small world locator, 50m for a page-sized map, or 10m for a detailed region. Record the scale, release, boundary viewpoint, and original URL in provenance. Convert the source to RFC 7946 GeoJSON or to geographic TopoJSON, preserving a stable ID field. Inspect disputed boundaries against the source's stated viewpoint.

For current US state and county maps, the Census cartographic boundary files are another source. Prepare the files outside rendering and commit or pin the result so a rerun uses the same geometry. Use topology-preserving simplification when producing a compact TopoJSON file; projection precision is a separate control for the curves generated at render time.

Performance

Run bun run perf in this package to measure bundled data, source preparation, projections, clipping, and SVG output. Use --list, --filter <regex>, --smoke, or --json to narrow or save a run. See performance workloads and methodology.