- JavaScript 53.9%
- C 35.2%
- CSS 3.5%
- HTML 3.5%
- Makefile 1.7%
- Other 2.2%
Add a dedicated Engagement Zone C/WASM calculator that runs a deterministic 1,000-shot Monte Carlo simulation from a fixed nominal firing solution. Model muzzle-velocity spread, rifle accuracy, range uncertainty, wind speed and direction uncertainty, selectable USPSA or rectangular targets, hit classification, and a configurable generic transonic-instability perturbation. Keep sampling, trajectory integration, fixed-hold projection, and impact classification in C while JavaScript validates, converts, and renders the returned impact population. Replace single muzzle-velocity/reference-temperature fields with a validated 1-32 row MV-temperature table across Loaded Gun and isolated Trajectory inputs. Interpolate between measured temperatures, extrapolate from nearest-row sensitivity, migrate existing stored profiles, apply modeled velocity independently per calculator temperature, and add unit handling and tests for the new inputs. Report local air-relative Mach at every trajectory sample and derive the complete Mach 1.2-to-1.0 region in browser presentation logic. Render accessible chart bands and labeled boundaries, mark covered table intervals and partial regions, retain separate energy crossings, and extend Solution and temperature-table output to expose the resulting state correctly. Refactor shared trajectory request parsing for strict native and WASM validation, wire the engagement target through container builds and smoke tests, add native/integration/browser coverage, and update architecture, calculator, unit, development, and user documentation for the new model contracts. |
||
|---|---|---|
| bct | ||
| bcv | ||
| build | ||
| container | ||
| docs | ||
| drag | ||
| engagement | ||
| gf | ||
| html | ||
| include | ||
| lib | ||
| maxdist | ||
| pbrange | ||
| scripts | ||
| sun | ||
| test | ||
| traj | ||
| web | ||
| worker | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| compose.yaml | ||
| Dockerfile | ||
| LICENSE | ||
| Makefile | ||
| Makefile.wasm | ||
| README | ||
| README.md | ||
| wrangler.jsonc | ||
Allen Ballistics Classic (ABC)
Allen Ballistics Classic—also called AB Classic or ABC—is an independently developed, modified version of the JBM Ballistics CGI v2.1 exterior-ballistics source by James B. Millard. It preserves the supplied C engines and presents every calculator through a modern Bootstrap single-page application. Emscripten compiles the original CGI entry points to WebAssembly, while a Cloudflare Worker serves the built application and adds security headers.
The UI follows the compact navigation, dark-first palette, settings treatment, responsive layout, and Bootstrap conventions demonstrated by the separate local example/ reference project. The numerical engines remain C; this is not a JavaScript rewrite of their formulas.
Quick start
Development, compilation, and testing require only Docker, Docker Compose, Make, and a running Docker engine. On macOS, Colima is the supported engine:
colima start --cpu 4 --memory 8
make test
make dev
Open http://localhost:5173. Stop the development server with Ctrl-C.
Do not run project npm, node, emcc, or native-compiler commands on the host. The supplied development commands run Node.js, Emscripten, GCC, tests, previews, and the local Worker emulator inside containers. Production deployment is a deliberate manual exception: after make build exports the release, the operator invokes an already-installed host wrangler executable directly. No project script deploys the application, installs host packages, or writes Cloudflare credentials into this repository. The first build can take a few minutes while Docker downloads the native ARM64 or AMD64 Emscripten image; subsequent builds use the Docker cache.
Calculators
The SPA exposes all calculator engines present in the supplied source:
- trajectory with focused and advanced modes
- single-target Solution with absolute bearings and a trajectory chart
- temperature-indexed range table
- point-blank range
- maximum distance
- ballistic coefficient from velocity
- ballistic coefficient from time
- bullet drag and twist
- drag-function conversion
- sunrise and sunset
Trajectory now presents one focused form with Advanced mode off by default. The former Simplified route remains a compatibility alias for bookmarks, but resolves to this same calculator and saved-input model. See Calculator mapping for legacy names, source directories, SPA routes, and renamed artifacts.
Every measurement input and calculated result supports selectable units without changing the preserved engine API. Choose Imperial, Metric, or Decimal / technical defaults from the settings menu, then click an input suffix or result-table unit selector to override one value or column. Directly related outputs inherit the selected input unit automatically: trajectory ranges and chart axes follow the range input family, velocity results follow projectile-velocity inputs, and the same rule applies to every compatible quantity family. Changing an input unit replaces older result choices for that family so the page cannot retain mixed stale units; a result can still be changed explicitly afterward. This includes bullet weight, velocity, distance, atmospheric values, angles, time, barrel twist, energy, momentum, and rotation rate. Stored inputs and submitted values remain in each CGI's original units, while result conversion remains a presentation-only operation. See Measurement units for the profile mapping and conversion boundaries.
Trajectory results include a responsive, collapsible bullet-drop chart and default to true milliradians (mrad), a 3,000 m maximum range, and one-yard trajectory calculations. Coarser table requests use a hidden one-yard chart calculation, and the SVG plots one point per ten canonical yards plus exact endpoints while boundary interpolation retains every engine sample. C/WASM reports each sample's air-relative Mach number from the modeled local atmosphere. Pure browser logic interpolates the complete transonic region from its Mach 1.2 entry through its Mach 1.0 exit: the chart shows an accessible shaded band with labeled boundaries, while the calculated table highlights covered intervals and states both boundaries. A calculation that starts inside the band or terminates before the exit reports that partial state explicitly. The first downward crossings of 500 and 350 ft·lbf of retained energy remain separate chart and table markers, with ranges and energy labels following the selected output units. Converted range grids retain exact requested bounds through 3,000 m: a 100 m interval produces rows at every 100 m and includes 3,000 m exactly when the projectile remains inside the engine's safe integration domain. If a trajectory terminates first, ABC displays the requested and last calculated ranges plus the engine's termination reason instead of presenting the partial chart as an unexplained cap. The focused form keeps inputs normally changed in a typical setup; uncommon solver, condition, angle, and Earth-rotation inputs appear when Advanced mode is enabled. Atmosphere remains available in the focused view, and altitude is shown only when standard atmospheric conditions at altitude are selected. Every visible calculator input card starts expanded; the result-side Input Data reference starts collapsed.
The Loaded Gun tab is the shared source of projectile and ammunition data, sight and zero geometry, and required barrel-twist data for Solution, Temperature Range Table, Point Blank Range, and Maximum Distance. Its MV-Temp table replaces the former single Muzzle Velocity and MV reference temperature: enter 1–32 measured ammunition-temperature/muzzle-velocity pairs. A fresh or otherwise incomplete profile starts at the ICAO reference of 15 °C (59 °F); existing profiles migrate their former MV/reference pair into one table row. Exact temperatures use the measured MV, temperatures bracketed by two rows use straight-line interpolation, and temperatures outside the measured span use MV temperature sensitivity from the nearest row. Solution applies that model at its entered Temperature. The Range Table applies it independently to every requested temperature, while Point Blank Range and Maximum Distance use the table's value at 59 °F.
Trajectory retains its own complete, isolated gun inputs and the same MV-temperature model. Selecting or editing a library gun never changes or invalidates Trajectory. Populate from gun is an explicit one-time copy of the currently loaded gun's relevant values into Trajectory; subsequent library edits do not stay linked. The working gun and folder-organized library persist in browser storage. The editor keeps Reset and Save together on its bottom bar; Save prompts for the name and destination folder and can create a folder. Open Gun handles loading and deletion, while Manage Library contains folder creation, moving guns, and every import/export action. Saving overwrites an exact trimmed-name match in the chosen folder or creates a new profile. The complete library or one gun can be exported as versioned JSON; library imports go to Imported, while single-gun imports go to the selected folder, with matching names overwritten. Imports and storage writes are transactional. Exact canonical matches identify a saved gun as loaded, and cached results from the four consumers are marked out of date after the gun changes until recalculated.
Solution runs the Trajectory engine over a dense internal path but presents one target solution instead of an iteration table. Solution, Trajectory, and Temperature Range Table share the same absolute wind entry: target and wind bearings are measured clockwise from true north, and wind direction means the direction the wind comes from. The target bearing also supplies firing azimuth. Leaving latitude blank disables Coriolis, while entering any latitude—including 0°—enables it. Target speed and direction reuse the shooter-relative lateral-lead model. Its chart carries Trajectory's same Mach 1.2-to-1.0 transonic band and 500/350 ft·lbf retained-energy crossings, and Target Solution identifies when the target itself lies inside the transonic region.
Solution also includes an Engagement Zone estimate directly beneath the target solution. One dedicated C/WASM invocation runs 1,000 deterministic Monte Carlo trajectories with a fixed nominal firing solution, using velocity extreme spread, rifle group size, range uncertainty, wind speed/direction uncertainty, and an enabled-by-default generic transonic estimate with adjustable 0–100% severity. It reports hit probability and plots modeled impacts against the default USPSA silhouette or a custom rectangular target. JavaScript performs unit conversion, response validation, and rendering only; trajectory integration, random sampling, transonic drag-direction perturbation, fixed-hold projection, and hit classification remain in C. The exact uncertainty and testing conventions are documented in Calculator mapping.
Trajectory, Solution, Temperature Range Table, Point Blank Range, and Maximum Distance share three velocity-dependent BC modes. Fixed BC (no calculation) is the default and preserves the entered coefficient throughout flight. Estimate from bullet geometry uses the explicit nose, body, and boattail dimensions to estimate how BC changes with Mach, anchored to the entered BC at the standard-atmosphere reference muzzle velocity. Custom bands accepts up to 32 measured or published velocity -> BC thresholds and switches coefficients as the projectile slows. All three modes use the selected G1/G2/G5/G6/G7/G8/GL/GI reference function.
Trajectory-backed calculations always include spin drift and can add horizontal/vertical Coriolis corrections using the Miller stability, spin-drift, and Earth-rotation formulas from Applied Ballistics for Long Range Shooting. During every one-yard trajectory step, its two drag evaluations use an ICAO lapse/barometric atmosphere derived from the bullet's shot-inclination- and cant-aware height above or below the entered station conditions, including updated density and local Mach. The Range Table runs that same C/WASM trajectory engine across 3–12 temperatures, resolves each case from the gun's MV-Temp table with the sensitivity fallback described above, and lays out one drop column per temperature. Its absolute wind direction, speed, and target bearing are converted to axial and crosswind components for every case, so wind can affect drop, velocity, and energy; low/middle/high samples additionally present Total Windage—including environmental wind, spin drift, and horizontal Coriolis—and the lateral-lead estimate. The Range Table never exposes dedicated Spin Drift or Coriolis columns. Wind and target movement default to zero; the Total Windage and Lead groups are omitted when every returned value is zero. Lateral lead models only the transverse component of target motion; it does not alter range, time of flight, drop, or velocity for targets moving toward or away from the shooter. Each drop column independently derives and colors its full local-atmosphere Mach 1.2-to-1.0 region, reports reached or partial entry/exit state, and retains the separate 500 and 350 ft·lbf crossings.
The ballistic-coefficient-from-velocity and ballistic-coefficient-from-time calculators accept measurements through 2,500 metres. Their shared solver uses drag-region-aware adaptive quadrature and a deterministic inverse solve in place of the original fixed 200-step approximation. See Ballistic-coefficient solvers for the model, precision strategy, limits, and tests.
Commands
| Command | Purpose |
|---|---|
make test |
Compile C/WASM, lint authored JavaScript, build the production SPA, enforce coverage, and run every test in Docker |
make build |
Run the suite and export dist/, native/, and wasm/ |
make dev |
Run the Vite SPA development server on port 5173 |
make preview |
Run the production nginx image on port 8080 |
make worker-dev |
Run the built SPA through containerized Wrangler on port 8787 |
make audit |
Audit both JavaScript lockfiles in disposable containers |
make lockfiles |
Regenerate lockfiles in containers without creating host node_modules |
make shell |
Open a shell in the pinned Emscripten build image |
make clean |
Stop project containers and remove exported build artifacts |
make build exports:
dist/ production SPA, bundled dependencies, and WASM
native/ descriptively named native CGI executables
wasm/ descriptively named Emscripten .js/.wasm pairs
These folders are generated and ignored by Git.
Design and privacy
Bootstrap SPA -> Emscripten CGI adapter -> preserved C engine
^
|
Cloudflare Worker serves static assets only
The SPA recreates an application/x-www-form-urlencoded CGI request in memory, supplies it to each module through standard input and CGI environment variables, then converts the legacy result markup into escaped Bootstrap result tables. It does not submit calculator form data to the Worker. Calculator settings, Trajectory's isolated inputs, and the working/folder-organized Loaded Gun library remain in that browser's local storage; calculated values and their applicable gun provenance stay in the current tab.
The legacy directory names and numerical functions are kept to minimize behavioral drift. Public artifacts and UI routes use meaningful names such as ballistic-coefficient-velocity, point-blank-range, and drag-function-conversion.
Documentation
- Architecture and security boundaries
- Containerized development and testing
- Cloudflare and OCI deployment
- Calculator and artifact mapping
- Measurement unit profiles and conversion behavior
- Ballistic-coefficient solver model and precision
- Original package README
License and provenance
The original JBM v2.1 package is Copyright © 2000 James B. Millard and was supplied under the GNU General Public License, version 2 or (at your option) any later version (GPL-2.0-or-later). Allen Ballistics Classic is a modified work based on that source. It is not affiliated with, endorsed by, or an official release of JBM Ballistics. See the complete GNU GPLv2 license. The sunrise/sunset code retains its own public-domain notices in its source files.
Ballistic calculations are model outputs and should be independently verified for the intended application.