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

@zaes/tactical-graphics

v1.0.0

Published

MIL-STD-2525E tactical graphics as plain GeoJSON. Renders axis-of-advance arrows, phase lines, mission tasks, and range fans for OpenLayers or any GeoJSON consumer.

Readme

Tactical Graphics

Render MIL-STD-2525E tactical graphics — axis-of-advance arrows, phase lines, mission tasks, range fans, boundaries — as plain GeoJSON.

Describe a graphic by adding a tacticalGraphic object to any GeoJSON feature's properties. Call one function. Get GeoJSON back. Draw it with OpenLayers or anything else that reads GeoJSON.

This library complements milsymbol, which renders single-point unit symbols. Tactical Graphics handles the multi-point geometries milsymbol doesn't: arrows that bend along a drawn path, corridors with parallel rails, arcs and fans sized in metres.

171 graphics are implemented and verified today, across 13 categories — see Supported graphics for the full catalog.


Install

npm install @zaes/tactical-graphics

The only runtime dependency is @turf/turf.


Quick start

import {renderTacticalGraphic, TacticalGraphicName} from '@zaes/tactical-graphics';

const {graphic, labels, handles} = renderTacticalGraphic({
    type: 'Feature',
    geometry: {
        type: 'LineString',
        coordinates: [[-77.04, 38.89], [-76.95, 38.95]],
    },
    properties: {
        tacticalGraphic: {
            name: TacticalGraphicName.MainAxisOfAdvance,
            label: '1-508 IN',
            hostility: 'Friend',
            radius: 300,
        },
    },
});

graphic is a MultiLineString — the drawn symbol. labels is a MultiPoint of anchor points for text. handles is a MultiPoint of vertices an editor can expose as drag handles.

Everything is GeoJSON, in EPSG:4326 ([longitude, latitude]), in and out.


The properties object

Everything the library needs lives under properties.tacticalGraphic. Only name is required; each graphic ignores the fields that don't apply to it.

properties: {
    tacticalGraphic: {
        // Required — which graphic to draw.
        name: 'MainAxisOfAdvance',

        // Amplifiers — text rendered on the graphic.
        label: '1-508 IN',        // primary designation
        secondId: 'TF RAIDER',    // secondary designation
        startDate: '021200ZJUN26',
        endDate: '021800ZJUN26',
        minAltitude: '500',
        maxAltitude: '2000',
        weapon: 'M252 81mm',      // FinalProtectiveFire only
        grid: '18SUJ2345',

        // Symbology — affects colour and dash pattern.
        hostility: 'Friend',      // Friend | Hostile/Faker | Neutral | Unknown | ...
        status: 'present',        // present | planned  (planned ⇒ dashed)
        echelon: 'battalion',
        direction: 'ONE_WAY',     // route graphics

        // Geometry, in metres.
        radius: 300,              // arrow width / circle radius
        size: 1000,               // generic size scalar (point graphics)
        rotation: 45,             // degrees (point graphics)
    },
}

Because the config rides on the feature, a tactical graphic is just GeoJSON. Save it, POST it, put it in PostGIS, diff it in git — then render it back with renderTacticalGraphic().

The rendered output carries the same properties.tacticalGraphic plus a role of graphic, label, or handle, so your styling code can read a graphic's amplifiers straight off the feature it's drawing.


Which geometry does a graphic need?

Each graphic expects one base geometry type. Pass the wrong one and you get a clear error rather than a broken shape.

| Base geometry | Graphics | Example | |---|---|---| | LineString | arrows, phase lines, boundaries, corridors | MainAxisOfAdvance, PhaseLine | | Point | mission tasks, range fans, fighting positions | Secure, Contain, BaseDefenseZone | | Polygon | areas | ObjectiveArea, NamedAreaOfInterest |

renderTacticalGraphic({
    type: 'Feature',
    geometry: {type: 'Point', coordinates: [-77.0, 38.9]},
    properties: {tacticalGraphic: {name: 'Secure', size: 1000, rotation: 0}},
});

Discover what's available at runtime:

import {listTacticalGraphicNames, GRAPHIC_CATEGORIES, getDisplayName} from '@zaes/tactical-graphics';

listTacticalGraphicNames();                     // → ['MainAxisOfAdvance', 'PhaseLine', ...]
GRAPHIC_CATEGORIES['PhaseLine'];                // → 'Lines'
getDisplayName('MainAxisOfAdvance');            // → 'main axis of advance'

Rendering

toFeatureCollection() flattens a render into a FeatureCollection you can hand straight to a map. It returns the graphic and label features by default; ask for handle too when you're building an editor.

OpenLayers

renderTacticalGraphic emits EPSG:4326, so reproject on read:

import GeoJSON from 'ol/format/GeoJSON';

const features = new GeoJSON().readFeatures(
    toFeatureCollection(renderTacticalGraphic(feature)),
    {dataProjection: 'EPSG:4326', featureProjection: 'EPSG:3857'},
);
source.addFeatures(features);

Any GeoJSON renderer

The output is a standard FeatureCollection, so any renderer that reads GeoJSON can consume it — filter on properties.role (graphic / label / handle) to style each part. OpenLayers is the reference implementation because that is where the full MIL-STD-2525E styling lives; other renderers show the correct geometry but style it themselves.

Drawing the label text

labels gives you anchor points, not rendered text — you own the typography. Read the text from the properties, or from getLabel() for graphics whose abbreviation is fixed by doctrine:

import {getLabel} from '@zaes/tactical-graphics';

getLabel('PhaseLine');           // → 'PL'   (doctrinal, not user-editable)
getLabel('FinalProtectiveFire'); // → 'FPF'

Errors

renderTacticalGraphic throws TacticalGraphicError with an actionable message:

Feature has no "properties.tacticalGraphic" object. Add one naming the graphic,
e.g. {"tacticalGraphic": {"name": "PhaseLine"}}.

Unknown tactical graphic "AxisOfAdvnce". Call listTacticalGraphicNames() to see
the 199 supported names.

Graphic "Secure" expects a Point base geometry, got LineString.

Coordinate systems

The library is projection-agnostic in one specific way: it works entirely in EPSG:4326, and hands you EPSG:4326 back. Reproject at your renderer's boundary, not before you call it.

Sizes (radius, size) are in metres, and range-fan band ranges are in kilometres.


Supported graphics

The graphics below are fully implemented and verified — each can be drawn, labelled, rotated, resized, repositioned, and modified, with its shape and labels checked against FM 1-02.2. This is the library's real, proven capability.

Every proven tactical graphic rendered at once by the sample gallery

One sample of every graphic in the table below, drawn in a single sweep by the demo app's Draw all samples button.

(listTacticalGraphicNames() returns more names than this — the registry also carries variants still being finished. The table lists only the verified set.)

| Graphic | Category | |---|---| | Air Corridor | Airspace Coordinating Measures | | Air-To-Air Refueling Restricted Operations Zone | Airspace Coordinating Measures | | Airspace Coordination Area, Circular | Airspace Coordinating Measures | | Airspace Coordination Area, Irregular | Airspace Coordinating Measures | | Airspace Coordination Area, Rectangular | Airspace Coordinating Measures | | Base Defense Zone | Airspace Coordinating Measures | | High-Altitude Missile Engagement Zone | Airspace Coordinating Measures | | High-Density Airspace Control Zone | Airspace Coordinating Measures | | Identification, Friend-Or-Foe Switch Off-Line | Airspace Coordinating Measures | | Identification, Friend-Or-Foe Switch On-Line | Airspace Coordinating Measures | | Joint Engagement Zone | Airspace Coordinating Measures | | Low-Altitude Missile Engagement Zone | Airspace Coordinating Measures | | Low-Level Transit Route | Airspace Coordinating Measures | | Minimum-Risk Route | Airspace Coordinating Measures | | Missile Engagement Zone | Airspace Coordinating Measures | | Restricted Operations Zone | Airspace Coordinating Measures | | Safe Lane | Airspace Coordinating Measures | | Short-Range Air Defense Engagement Zone | Airspace Coordinating Measures | | Special Corridor | Airspace Coordinating Measures | | Standard Use Army Aircraft Flight Route | Airspace Coordinating Measures | | Transit Corridor | Airspace Coordinating Measures | | Unmanned Aircraft (UA) Corridor | Airspace Coordinating Measures | | Unmanned Aircraft Restricted Operations Zone | Airspace Coordinating Measures | | Weapon Engagement Zone | Airspace Coordinating Measures | | Weapons Free Zone | Airspace Coordinating Measures | | Airfield | Areas | | Airhead Line | Areas | | Area Of Operations | Areas | | Assault Position | Areas | | Assembly Area | Areas | | Attack Position | Areas | | Base Camp | Areas | | Battle Position | Areas | | Battle Position Planned But Not Prepared | Areas | | Battle Position Prepared But Not Occupied | Areas | | Brigade Support Area | Areas | | Corps Support Area | Areas | | Detainee Holding Area | Areas | | Division Support Area | Areas | | Drop Zone | Areas | | Encirclement | Areas | | Engagement Area | Areas | | Fortified Area | Areas | | Forward Arming And Refueling Point | Areas | | Guerrilla Base | Areas | | Kill Zone | Areas | | Landing Zone | Areas | | Named Area Of Interest | Areas | | Objective Area | Areas | | Pickup Zone | Areas | | Refugee Holding Area | Areas | | Strong Point | Areas | | Target Area Of Interest | Areas | | Unexploded Explosive Ordnance (UXO) Area | Areas | | Enemy Known Boundary | Boundaries | | Enemy Suspected Boundary | Boundaries | | Friendly Planned Boundary | Boundaries | | Friendly Present Boundary | Boundaries | | Area Defense | Defense Operations Planning | | Delay | Defense Operations Planning | | Mobile Defense | Defense Operations Planning | | Retirement | Defense Operations Planning | | Withdraw | Defense Operations Planning | | Withdraw Under Pressure | Defense Operations Planning | | Cover | Enabling Operations Planning | | Forward Passage Of Lines | Enabling Operations Planning | | Guard | Enabling Operations Planning | | Rearward Passage Of Lines | Enabling Operations Planning | | Relief In Place | Enabling Operations Planning | | Screen | Enabling Operations Planning | | Fighting Position | Field Fortification Symbols | | Fortified/Trench Line | Field Fortification Symbols | | Fields Of Fire/Sector Of Fire | Fire Support Coordination Control Measures | | Free-Fire Area, Circular | Fire Support Coordination Control Measures | | Free-Fire Area, Irregular | Fire Support Coordination Control Measures | | Free-Fire Area, Rectangular | Fire Support Coordination Control Measures | | Munition Flight Path (MFP) | Fire Support Coordination Control Measures | | No-Fire Area, Circular | Fire Support Coordination Control Measures | | No-Fire Area, Irregular | Fire Support Coordination Control Measures | | No-Fire Area, Rectangular | Fire Support Coordination Control Measures | | Position Area For Artillery, Circular | Fire Support Coordination Control Measures | | Position Area For Artillery, Irregular | Fire Support Coordination Control Measures | | Position Area For Artillery, Rectangular | Fire Support Coordination Control Measures | | Restrictive Fire Area, Circular | Fire Support Coordination Control Measures | | Restrictive Fire Area, Irregular | Fire Support Coordination Control Measures | | Restrictive Fire Area, Rectangular | Fire Support Coordination Control Measures | | Battlefield Handover Line | Lines | | Bridgehead Line | Lines | | Common Sensor Boundary | Lines | | Coordinated Fire Line | Lines | | Delay Line | Lines | | Engineer Work Line | Lines | | Final Coordination Line | Lines | | Fire Support Coordination Line | Lines | | Forward Edge Of The Battle Area | Lines | | Forward Line Of Own Troops | Lines | | Intelligence Coordination Line | Lines | | Limit Of Advance | Lines | | Line Of Contact | Lines | | Line Of Departure | Lines | | Line Of Departure Or Line Of Contact | Lines | | Phase Line | Lines | | Probable Line Of Deployment | Lines | | Release Line | Lines | | Restrictive Fire Line | Lines | | Airborne Or Aviation Axis Of Advance | Movement and Maneuver | | Attack Helicopter Axis Of Advance | Movement and Maneuver | | Aviation Direction Of Attack | Movement and Maneuver | | Direction Of Main Attack | Movement and Maneuver | | Direction Of Main Attack Feint | Movement and Maneuver | | Direction Of Supporting Attack | Movement and Maneuver | | Envelopment | Movement and Maneuver | | Frontal Attack | Movement and Maneuver | | Infiltration | Movement and Maneuver | | Infiltration Lane | Movement and Maneuver | | Main Axis Of Advance | Movement and Maneuver | | Main Axis Of Advance Feint | Movement and Maneuver | | Penetration | Movement and Maneuver | | Supporting Axis Of Advance | Movement and Maneuver | | Turning Movement | Movement and Maneuver | | Ambush | Offense Operations Planning | | Cordon And Search | Offense Operations Planning | | Counterattack | Offense Operations Planning | | Exploitation | Offense Operations Planning | | Movement To Contact | Offense Operations Planning | | Pursuit | Offense Operations Planning | | Block | Tactical Mission Tasks | | Breach | Tactical Mission Tasks | | Bypass | Tactical Mission Tasks | | Canalize | Tactical Mission Tasks | | Clear | Tactical Mission Tasks | | Contain | Tactical Mission Tasks | | Control | Tactical Mission Tasks | | Disengage | Tactical Mission Tasks | | Disrupt | Tactical Mission Tasks | | Fix | Tactical Mission Tasks | | Isolate | Tactical Mission Tasks | | Artillery Target Intelligence Zone, Circular | Target Acquisition Control Measures | | Artillery Target Intelligence Zone, Irregular | Target Acquisition Control Measures | | Artillery Target Intelligence Zone, Rectangular | Target Acquisition Control Measures | | Blue Kill Box, Circular | Target Acquisition Control Measures | | Blue Kill Box, Irregular | Target Acquisition Control Measures | | Blue Kill Box, Rectangular | Target Acquisition Control Measures | | Call For Fire Zone, Circular | Target Acquisition Control Measures | | Call For Fire Zone, Irregular | Target Acquisition Control Measures | | Call For Fire Zone, Rectangular | Target Acquisition Control Measures | | Censor Zone, Circular | Target Acquisition Control Measures | | Censor Zone, Irregular | Target Acquisition Control Measures | | Censor Zone, Rectangular | Target Acquisition Control Measures | | Critical Friendly Zone, Circular | Target Acquisition Control Measures | | Critical Friendly Zone, Irregular | Target Acquisition Control Measures | | Critical Friendly Zone, Rectangular | Target Acquisition Control Measures | | Dead Space Area, Circular | Target Acquisition Control Measures | | Dead Space Area, Irregular | Target Acquisition Control Measures | | Dead Space Area, Rectangular | Target Acquisition Control Measures | | Purple Kill Box, Circular | Target Acquisition Control Measures | | Purple Kill Box, Irregular | Target Acquisition Control Measures | | Purple Kill Box, Rectangular | Target Acquisition Control Measures | | Weapon Or Sensor Range Fan | Target Acquisition Control Measures | | Weapon Or Sensor Range Fan, Circular | Target Acquisition Control Measures | | Final Protective Fire | Target Control Measures | | Fire Support Area, Circular | Target Control Measures | | Fire Support Area, Irregular | Target Control Measures | | Fire Support Area, Rectangular | Target Control Measures | | Group/Series Of Targets | Target Control Measures | | Linear Smoke Target | Target Control Measures | | Linear Target | Target Control Measures | | Smoke Obscurant | Target Control Measures | | Target Area, Circular | Target Control Measures | | Target Area, Irregular | Target Control Measures | | Target Area, Rectangular | Target Control Measures |


Project layout

src/tacticalgraphics/          # The library. Pure GeoJSON, map-agnostic.
  index.ts                     #   public entry point
  core/render.ts               #   renderTacticalGraphic()
  core/type.ts                 #   TacticalGraphicName + the properties schema
  core/GeometryService.ts      #   all geographic math (turf + custom)
  core/TacticalGraphicsRegistry.ts
  graphics/                    #   one generator class per graphic family

src/components/                # Demo app — not published.
  openlayers/                  #   the renderer: styling, draw/edit, dialog

The demo application is built on OpenLayers — it shows drawing, editing, rotating, resizing, modifying, and a Feature Properties dialog, on a keyless OpenStreetMap basemap (no API key needed). Start it with npm start.

The library itself is renderer-agnostic — it emits GeoJSON, so any renderer that reads GeoJSON can draw it (see Rendering). The demo standardises on OpenLayers because that is where the full MIL-STD-2525E styling lives; matching that styling pixel-for-pixel on another renderer is a per-renderer effort left to consumers.


Development

npm start            # run the demo app
npm test             # run the test suite
npx tsc --noEmit     # typecheck (the main correctness gate)
npm run lint         # eslint --fix

The generators in src/tacticalgraphics/graphics/ are the reference for new shapes, and the OpenLayers demo under src/components/openlayers/ shows how a renderer consumes them. See Adding a graphic below for the steps.


Adding a graphic

  1. Add the name to TacticalGraphicName in core/type.ts.
  2. Write a generator in graphics/, extending TacticalGraphicsBase.
  3. Register it in core/TacticalGraphicsRegistry.ts.
  4. Add it to GRAPHIC_CATEGORIES in core/categories.ts.

Steps 1 and 4 are enforced by the compiler — GRAPHIC_CATEGORIES is an exhaustive Record<TacticalGraphicName, …>, so TypeScript tells you what's missing. To wire the graphic into the demo app you also need entries in controllerRegistry.ts and graphicFieldRegistry.ts.

A graphic is "done" when a user can draw it, label it, and rotate, resize, reposition, and modify it.


Roadmap

  • Complete the remaining graphics from FM 1-02.2.
  • A Cesium 2D/3D view is planned once the OpenLayers graphics are complete. The OpenLayers style functions already read their amplifiers (label, hostility, status, DTGs) from properties.tacticalGraphic, but the styling logic is still OpenLayers-specific code — a second renderer would first need that logic expressed as portable, renderer-agnostic data.

References

License

MIT