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

@orbat-mapper/tactical-map-sheet

v0.4.7

Published

Scale-accurate projected vector tactical map-sheet renderer.

Readme

Tactical map sheet

Public package for deterministic, scale-accurate tactical map sheets.

The package creates transparent or explicitly backed, grid-north-up UTM/UPS SVG and PDF sheets from physical page data, a geographic center, nominal true-ground scale, and normalized authored layers. It supports automatic or explicit projection selection, deterministic UTM/UPS MGRS grids, control measures, renderer-neutral point symbols, custom vector symbols, host-prepared raster basemaps, physically registered overlays, and complete configurable marginalia. One center-selected CRS is retained across zone and polar transitions and any usable distortion or fallback is reported through structured warnings.

Install and entry points

pnpm add @orbat-mapper/tactical-map-sheet

The root entry point exports createTacticalMapSheet and all request, result, warning, metadata, layer, MGRS, marginalia, and vector-symbol capability types. The optional PDF implementation is only exported from @orbat-mapper/tactical-map-sheet/pdf, keeping PDF code and dependencies out of the main SVG module graph.

import {
  createTacticalMapSheet,
  type TacticalMapSheetRequest,
} from "@orbat-mapper/tactical-map-sheet";

const request: TacticalMapSheetRequest = {
  page: { widthMm: 297, heightMm: 210, marginMm: 10, orientation: "landscape" },
  center: [-2.5, 49.2],
  scaleDenominator: 25_000,
  grid: { intervalMeters: 1_000 },
  layers: [],
  marginalia: {},
};

const { svg, footprint, warnings, metadata, resources } = createTacticalMapSheet(request);

TacticalMapSheetResult contains deterministic SVG bytes, the densified geographic printable footprint, structured warnings, resolved projection/page/grid metadata, and the font and pattern resources used by the document. Identical requests produce identical results independently of a browser viewport or device-pixel ratio.

Contract and failure behavior

The page and map frame use millimetres. The package derives one printable footprint from the page, center, and scale; it does not accept a competing extent. projection: "auto" selects one UTM or UPS CRS from the center and retains it for the whole sheet. Layers render bottom-to-top in request order, and each layer preserves authored graphic order. Requested control measures and symbols stay vector in both output formats.

Invalid coordinates, contradictory page geometry, unavailable point-symbol capabilities, projection failures, and SVG content outside the controlled vector subset throw. A usable but lossy result is returned only with an identifying warning; requested content is never silently omitted or rasterized.

Host-prepared raster basemaps

An ordinary map sheet may include one rasterBasemap beneath its MGRS grid and every authored vector layer. The basemap is an ordered source-over stack. Each layer has a stable ID, one shared opacity, structured attribution, and ordered PNG/JPEG tiles. Each tile has a stable ID, original bytes, declared intrinsic pixel dimensions, and a page-relative millimetre destination. Every layer must independently tessellate the complete map frame with axis-aligned rectangles; a regular tile grid is not required.

Resolve the target before a host renders or warps source map pixels:

import {
  mapSheetRasterPointToGeographic,
  resolveMapSheetRasterPlan,
} from "@orbat-mapper/tactical-map-sheet";

const plan = resolveMapSheetRasterPlan({
  page: { widthMm: 297, heightMm: 210, marginMm: 10 },
  center: [-2.5, 49.2],
  scaleDenominator: 25_000,
});

const topLeft = mapSheetRasterPointToGeographic(plan, 0, 0);

plan reports the resolved grid CRS and EPSG code, physical frame, projected bounds, and projected metres per millimetre from the same resolver used by document generation. Normalized coordinates are finite values from 0 through 1, use a top-left origin, and convert through the package's GeographicLib UTM/UPS backend.

request.rasterBasemap = {
  layers: [
    {
      id: "terrain",
      opacity: 0.85,
      attribution: [{ text: "National mapping authority", required: true }],
      tiles: [
        {
          id: "terrain-full",
          mediaType: "image/png",
          data: pngBytes,
          pixelWidth: 3272,
          pixelHeight: 2244,
          frame: plan.frame,
        },
      ],
    },
  ],
};
request.marginalia = {};

Validation runs before serialization. IDs and attribution text must be non-blank; layer and tile IDs must be unique; opacity must be in [0, 1]; pixel dimensions must be positive integers; and tiles must cover the frame without gaps or overlaps within 1e-6 mm. PNG signature, dimensions, and APNG markers are inspected. JPEG signature, baseline/progressive dimensions, and EXIF orientation are inspected; only absent orientation or orientation 1 is accepted. Empty, malformed, mismatched, or unsupported images reject the complete request. Inspection reads image containers only — compressed pixel data is never decoded, and tile bytes are embedded exactly as supplied.

Resolved raster metadata preserves canonical layer/tile order, opacity, de-duplicated attribution, physical placement, media type, intrinsic dimensions, and effective horizontal/vertical DPI without echoing image bytes. low-raster-dpi identifies a tile below 150 DPI on either axis; raster-dpi-anisotropy identifies a horizontal/vertical difference above 1%. Required attribution is de-duplicated in stable first-occurrence order and wrapped into a reserved marginalia band. The request fails if marginalia is disabled or the required text cannot fit without overlap.

SVG embeds self-contained data URLs; PDF consumes the same PNG/JPEG payload and physical rectangles. Both preserve PNG transparency, layer opacity, clipping, and ordinary source-over layer order. MGRS, authored graphics, symbols, text, and marginalia remain vector above the basemap. Identical request values and image bytes produce deterministic output. Registered transparent overlays cannot include a raster basemap.

The host remains responsible for basemap selection and licensing, network acquisition, engine/style rendering, reprojection into plan.projectedBounds, warp quality, DPI choice, image encoding, and tile sizing. The package accepts no MapLibre/OpenLayers/Leaflet object, style, URL, canvas, or Web Mercator tile coordinate and performs no I/O. For a MapLibre reference host, render a flat Mercator map at pitch/bearing zero with no globe or terrain, wait for idle, keep style layout at 96 CSS px/in, use drawing-buffer pixel ratio for export DPI, and warp the captured texture into the UTM/UPS target before encoding tiles. The preview reference host qualifies one coherent MapLibre source canvas per layer with 256 logical CSS pixels of padding on every side, a 0.5-source-pixel adaptive warp tolerance, and sequential destination tiles no larger than 4096 pixels per edge. It never automatically reduces output DPI, padding, tolerance, dimensions, or layer count.

MapLibre's Web Mercator latitude domain and the browser/GPU single-source-canvas and memory limits qualify that preview-host implementation only. They do not narrow this package's raster plan: resolveMapSheetRasterPlan and mapSheetRasterPointToGeographic remain UTM/UPS-capable, including polar vector-only exports. A host using another renderer or a different source strategy may support other source domains while supplying the same projection-aligned package input.

Warnings are deterministic records with these public codes and payloads:

  • cross-zone-footprint reports the center-selected UTM selectedZone and all intersectedZones when the printable footprint enters another UTM zone.
  • cross-projection-footprint reports the selectedProjection and the ordered intersectedProjections (ups, utm) when the footprint crosses the UTM/UPS boundary. A UTM footprint crossing that boundary and another UTM zone reports both warnings.
  • scale-deviation reports maximumRelativeDeviation when frame scale differs from center scale by at least 0.001 (0.1%). Smaller usable distortion remains available in result metadata.
  • graphic-clipped, graphic-outside-frame, and graphic-hidden identify the affected layerId and graphicId.
  • point-symbol-fallback identifies a layerId and graphicId whose point-symbol capability returned visible fallback vector content.
  • low-raster-dpi identifies layerId/tileId, both effective DPI values, and the 150 DPI threshold.
  • raster-dpi-anisotropy identifies layerId/tileId and the relative axis difference above 1%.

Regular/Caps, Italic, and Light semantic text use complete package-owned Open Sans static TTFs and one final-size metrics service. Their license, immutable provenance, and SHA-256 identities live under src/assets/.

The package owns public MGRS utilities for parsing, normalization, conversion, formatting, and snapping. MGRS text accepts case and whitespace variations and normalizes to compact uppercase. Finite-precision references identify the southwest intersection of their grid cell, never its center. Geographic positions use GeoJSON order ([longitude, latitude]); projected results carry an explicit UTM or UPS crs alongside metre easting and northing values. The geographiclib-mgrs backend is qualified against GeographicLib/GEOTRANS vectors, Norway/Svalbard zone rules, explicit-zone and round-trip behavior, UTM/UPS transitions, poles, MGRS precision boundaries, TypeScript/ESM, Node, and browser bundling.

Registered physical overlays

Add registration to turn a normal sheet into a registered overlay. The page, map frame, geographic center, projection, and nominal scale remain authoritative: registration validates the chosen sheet and never fits, rotates, resizes, or relocates it.

const registered = createTacticalMapSheet({
  page: { widthMm: 297, heightMm: 210, marginMm: 10 },
  center: [-2.5, 49.2],
  scaleDenominator: 25_000,
  registration: {
    marks: [
      { id: "southwest", mgrs: "30u wv 33924 48309", label: "SW" },
      { id: "northeast", mgrs: "30UWV3892451309" },
    ],
    snapIntervalMeters: 1_000,
  },
  marginalia: { showFrameCornerMarks: false, showCalibrationMarks: false },
  printerCalibration: {},
});

Registration requires at least two marks with unique non-empty IDs. Every MGRS reference is normalized and resolves to its southwest grid intersection, then optionally snaps at 100 m, 1 km, 10 km, or 100 km. A mark must use the sheet's UTM zone and hemisphere, or the same UPS hemisphere. Its complete fixed 8 mm black crosshair and labels must fit inside the printable frame. A non-empty authored label is placed inward from the crosshair. Otherwise, the MGRS easting is placed to its left and the northing below it in the conventional abbreviated arrangement. At 100 km precision, the grid-square column and row letters take those positions. At least two marks must resolve to distinct positions. Any invalid mark rejects the complete request; marks are never omitted or moved.

Registered overlays are transparent. An explicit non-transparent page.background is rejected. SVG and PDF results expose the same ordered registrationMarks, each containing the authored ID, normalized mgrs, GeoJSON-order position, and derived sheetPositionMm. The optional full MGRS grid, tactical layers, and marginalia remain independent.

printerCalibration: {} adds a 100 mm diagnostic line, endpoint ticks, and length label centered in the bottom page margin. Set a positive lengthMm to choose another length. The request fails if the complete calibration artwork does not fit; calibration never changes sheet geometry, coverage, scale, or mark positions.

Print registered SVG or PDF output at 100% / Actual Size with Fit to page disabled. If the calibration line measures incorrectly, correct the printer settings and reprint; do not compensate by resizing the overlay.

Point-symbol renderers enter through a capability that returns complete SVG, bounds, doctrinal and octagon anchors. Point and custom symbols then use the same conservative vector subset. Raster, linked, scripted, malformed, or otherwise unsupported SVG throws instead of being omitted or rasterized.

The checked conformance assets live beside normandy-conformance.spec.ts. Update both the canonical SVG bytes and the 1188-pixel-wide PNG rendered by the exactly pinned @resvg/resvg-js dependency with:

pnpm --filter @orbat-mapper/tactical-map-sheet fixtures:update

Review the SVG and PNG visually before committing an update. The visual comparison permits at most 0.01% of pixels to differ by more than 8 in any RGBA channel; semantic assertions remain exact.

The optional direct PDF backend is a separate entry point, so SVG consumers never load jsPDF or its dependencies:

import { renderMapSheetPdf } from "@orbat-mapper/tactical-map-sheet/pdf";

const result = renderMapSheetPdf(request);
const pdfBytes = result.pdf;

PDF is serialized directly from the same private millimetre scene as SVG. It retains vector paths, tiling patterns, map-frame clipping, opacity, symbol transforms, embedded searchable Open Sans text, canonical ordering, warnings, resources, footprint, and resolved metadata. The serializer fixes the document timestamp and identifier, disables variable compression, and normalizes geometry through the shared six-decimal formatter so identical requests produce identical bytes. Update the ordinary, patterned, cross-zone, and polar canonical PDF and rendered PNG fixtures with:

pnpm --filter @orbat-mapper/tactical-map-sheet fixtures:update:pdf

The PDF fixtures are rendered by pinned PDF.js and @napi-rs/canvas, then compared both byte-for-byte with their checked PNGs and visually with the sibling SVG render. The cross-renderer comparison allows at most 2% of pixels to differ by more than 24 in one RGBA channel, or 10% for one-pixel repeating hatching where the two vector rasterizers cover opposite edge pixels.

Application code remains responsible for content selection, authorization, export preferences, footprint preview, displaying warnings and validation failures, and saving the returned bytes. Application stores and map-engine output are not part of the public request contract.

API reference

Request

TacticalMapSheetRequest has these fields:

  • page: required physical widthMm and heightMm, with optional non-negative marginMm, orientation, and CSS background (or "transparent").
  • center: required GeoJSON longitude/latitude position; scaleDenominator: required positive nominal true-ground scale at that center.
  • mapFrame: optional { xMm, yMm, widthMm, heightMm } inside the page. It is mutually exclusive with page.marginMm.
  • projection: "auto" (default), { kind: "utm", zone, hemisphere }, or { kind: "ups", hemisphere }.
  • grid: false or MgrsGridOptions (intervalMeters of 100, 1,000, 10,000, or 100,000; matching precision 3, 2, 1, or 0; plus color, line width, and label size).
  • layers: ordered TacticalMapSheetLayer[]; pointSymbols: the optional renderer capability; marginalia: false or display options; metadata: optional document text.
  • registration: optional grouped MGRS marks and snapIntervalMeters; its presence activates strict transparent registered-overlay validation.
  • printerCalibration: optional bottom-margin diagnostic line; lengthMm defaults to 100.
  • rasterBasemap: optional ordered raster layer stack described above. It is incompatible with registration.

Each layer has a stable id, ordered { graphic }[], and optional shared portrayal defaults for color, line/dash/cap/join, and label size/clamp. A graphic is a control-measure ControlMeasure, a MapSheetPointSymbol, or a MapSheetCustomSymbol.

Control-measure label sizes and Text sizes authored in metres retain their existing Web Mercator construction-unit meaning. The renderer converts the sheet's true-ground scale at each graphic's control-point bounding-box midpoint latitude for both label layout and final SVG/PDF text sizing. For example, a labelSize of 280 at 60° latitude prints at 14 CSS pixels when the sheet represents 10 true-ground metres per CSS pixel. Ordinary ground labels use the layer's clamp band; ground Text graphics instead scale freely and hide above their maxSizePixels threshold. Screen sizes remain fixed CSS reference pixels. Authored graphics are never rewritten by export.

Point symbols carry id, sidc, position, rotation in radians, pixel- or metre-based size, optional amplifiers/modifiers, and renderer style/options. MapSheetPointSymbolCapability.render(symbol) must return a ControlledVectorSymbol: stable resource ID, controlled-subset SVG, complete width and height, octagon size, placement anchor, octagon anchor, and optional validation state. Custom symbols carry that same vector record directly. Metre sizes may specify pixel clamps.

Paper presets

PAPER_SIZES contains exact portrait millimetre dimensions for a0 through a4, letter, legal, tabloid, ansi-c, ansi-d, ansi-e, and arch-d. ledger aliases tabloid; ansi-a aliases letter; and ansi-b aliases tabloid, so aliases share one physical definition. ANSI D is 558.8 × 863.6 mm and remains distinct from 609.6 × 914.4 mm ARCH D.

resolvePaperSize(name, orientation) returns { widthMm, heightMm } for direct use as a page input. Portrait is the default and landscape swaps the axes. Presets are optional conveniences: callers can continue supplying arbitrary positive widthMm and heightMm, which remain authoritative during rendering.

MGRS utilities

  • parseMgrsReference validates a complete UTM or UPS reference and returns its compact-uppercase form, precision, explicit grid CRS, projected metre coordinates, and GeoJSON-order position.
  • normalizeMgrsReference, mgrsToProjected, and mgrsToGeographic expose focused forms of that parsed result. Geographic conversion always returns the southwest grid-cell intersection.
  • geographicToMgrs and projectedToMgrs format coordinates at precision 0 through 5 (100 km through 1 m). Projected input includes its explicit UTM zone/hemisphere or UPS hemisphere.
  • snapGeographicToMgrs and snapProjectedToMgrs accept 100 m, 1 km, 10 km, or 100 km. Already aligned intersections stay fixed; exact halfway ties move toward increasing easting and northing.

MapSheetMarginaliaOptions controls color and visibility of declared scale, scale bar, grid/north, frame-corner marks, legacy calibration marks, and footprint. Grid/north marginalia includes the MGRS grid-zone designation for the sheet center. Use showFrameCornerMarks for the canonical ungeoreferenced corner crosses. Deprecated showRegistrationMarks remains an alias; when both are supplied, showFrameCornerMarks takes precedence. Deprecated showCalibrationMarks continues to control the existing pair of 10 mm legacy marks and is independent of printerCalibration. MapSheetMetadata supplies optional title, subtitle, classification, and preparer text.

Results and resolved metadata

createTacticalMapSheet(request) returns TacticalMapSheetResult:

  • svg: complete deterministic SVG; footprint: densified GeoJSON polygon.
  • warnings: ordered structured warnings described below.
  • metadata: resolved center, scale denominator, physical page and map frame, optional source document metadata, optional resolved MGRS interval/precision, and resolved CRS (kind, zone or hemisphere, EPSG, center point scale, center convergence in degrees, and maximum frame scale deviation).
  • metadata.rasterBasemap: canonical layer, attribution, tile placement, media type, dimensions, and effective DPI metadata; image bytes are intentionally omitted.
  • resources: identities for embedded Open Sans fonts and deterministic pattern resources.
  • registrationMarks: when registered, the ordered resolved IDs, normalized MGRS references, longitude/latitude positions, and physical sheet positions in millimetres.

renderMapSheetPdf(request) accepts the identical request and returns TacticalMapSheetPdfResult: pdf: Uint8Array plus the same footprint, warnings, metadata, resources, and resolved registration marks as the SVG result.

Warning union

TacticalMapSheetWarning is a discriminated union on code. Zone, projection, and scale warnings carry the payloads documented earlier. graphic-clipped, graphic-outside-frame, graphic-hidden, and point-symbol-fallback carry both layerId and graphicId. Warning order is deterministic.