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

a7p-js

v1.2.4

Published

A7P ballistic profile format — encode/decode and validation

Readme

a7p-js

NPM Version npm downloads license

Wrapper for .a7p files

.a7p is the most common ballistic profile format for the latest Archer thermal vision devices

Table of Contents

Installation

yarn add a7p-js
# or
npm install a7p-js

Usage

In a Node.js / TypeScript project

import { readFile } from 'fs/promises';
import { decode, encode, ValidationError } from 'a7p-js';

const bytes = await readFile('./example.a7p');

try {
  // decode a .a7p file into a plain Payload object
  const payload = decode(bytes);
  console.log(payload.profile.profileName);
  console.log(payload.profile.switches);

  // encode a Payload back into .a7p bytes
  const buffer = encode(payload);
} catch (error) {
  if (error instanceof ValidationError) {
    error.errors.forEach((message) => console.log(message));
  } else {
    throw error;
  }
}

In a browser, via CDN

a7p-js ships as an ES module, so it can be imported directly from a CDN such as esm.sh or jsDelivr with no build step:

<script type="module">
  import { decode } from "https://esm.sh/[email protected]";

  const input = document.querySelector('input[type="file"]');
  input.addEventListener('change', async () => {
    const file = input.files[0];
    const buffer = await file.arrayBuffer();
    const payload = decode(buffer);
    console.log(payload.profile);
  });
</script>

See it in action in this live example, which combines a7p-js with js-ballistics to compare trajectories from .a7p profiles entirely in the browser.

Dimensions

To obtain values from an .a7p profile in the desired units, you need to divide them by the multiplier. For the reverse operation, you need to perform the inverse operation and convert to an integer.

| key | unit | multiplier | desc | |--------------------------|----------------|------------|---------------------------------------------| | scHeight | mm | 1 | sight height in mm | | rTwist | inch | 100 | positive twist value | | cZeroTemperature | C | 1 | temperature at cMuzzleVelocity | | cMuzzleVelocity | mps | 10 | muzzle velocity at cZeroTemperature | | cTCoeff | %/15C | 1000 | temperature sensitivity | | cZeroDistanceIdx | <int> | 10 | index of zero distance from distances table | | cZeroAirTemperature | C | 1 | air temperature at zero | | cZeroAirPressure | hPa | 10 | air pressure at zero | | cZeroAirHumidity | % | 1 | air humidity at zero | | cZeroPTemperature | C | 1 | powder temperature at zero | | cZeroWPitch | deg | 1 | zeroing look angle | | bDiameter | inch | 1000 | bullet diameter | | bWeight | grain | 10 | bullet weight | | bLength | inch | 1000 | bullet length | | twistDir | RIGHT|LEFT | | twist direction | | bcType | G1|G7|CUSTOM | | g-func type | | distances | m | 100 | distances table in m | | zeroX | <int> | -1000 | zeroing h-clicks for specific device | | zeroY | <int> | 1000 | zeroing v-clicks for specific device | | coefRows[].bcCd (G1/G7) | | 10000 | bc coefficient for mv | | coefRows[].mv (G1/G7) | mps | 10 | mv for bc provided | | coefRows[].bcCd (CUSTOM) | | 10000 | drag coefficient (Cd) | | coefRows[].mv (CUSTOM) | mach | 10 | speed in mach |

Build notes

yarn install
yarn build:proto   # regenerate protobuf bindings after editing ../proto/profedit.proto
yarn build:schema  # regenerate the ajv validator after editing ../schema/a7p.schema.json
yarn build         # tsc + copy the generated schema validator into dist/

build:proto/build:schema only need re-running when the .proto/schema source changes — both write generated, checked-in files under src/ (src/profedit.ts, src/generated/a7p_schema_validator.cjs), so a plain yarn build is enough day-to-day.