bclibc 2.0.0
bclibc: ^2.0.0 copied to clipboard
Ballistic calculator for Dart, Flutter and the web: the bclibc engine as native code (build hook) or wasm.
bclibc #
Dart FFI bindings for the bclibc ballistics engine.
A thin, zero-copy Dart wrapper around libbclibc_ffi — a high-performance 3-DOF + spin drift ballistic solver engine with RK4/Euler/Velocity Verlet integration. Ships the bclibc C++ source in the package; no pre-built binaries and no downloads.
One package for Dart, Flutter and the web — no companion package. Native targets get the library from a build hook that compiles the bundled sources (dart run, dart test, flutter build and flutter test all work, offline, no setup); web targets run the engine as a wasm module embedded in the package.
Table of Contents #
Quick start #
import 'package:bclibc/bclibc.dart';
final bc = BcLibC.open(); // loads the native library once
final shot = BcShot(
bc: 0.295,
weightGrain: 168.0,
diameterInch: 0.308,
lengthInch: 1.22,
muzzleVelocityFps: 2750.0,
sightHeightFt: 0.1148,
twistInch: 10.0,
tempC: 15.0,
pressureHpa: 1013.25,
altitudeFt: 0.0,
dragTable: [BcDragPoint(0.0, 0.0), /* … Mach / CD pairs … */],
lookAngleRad: 0.0,
barrelElevationRad: 0.0,
);
final hit = bc.integrateShot(
shot,
BcTrajectoryRequest(rangeLimitFt: 3000.0, rangeStepFt: 100.0),
);
for (final pt in hit.trajectory) {
print('${pt.distanceFt} ft ${pt.velocityFps} fps ${pt.heightFt} ft');
}
API #
Input types #
| Dart type | Description |
|---|---|
BcShot |
Preferred shot input (natural units). All physics conversion — atmosphere density, Coriolis trig, PCHIP drag curve, cant — is performed inside C++ via BCLIBCFFI_Shot::to_shot_props(). |
BcShotProps |
Legacy shot input (pre-computed BcAtmosphere/BcCoriolis structs). |
BcTrajectoryRequest |
Step size, range limit, and BCLIBCFFI_TrajFlag filter bitmask. |
BcConfig |
Solver knobs (step multiplier, accuracy, gravity constant, etc.). |
BcDragPoint |
One Mach / CD entry for the drag table. |
BcWind |
One wind segment (velocity, direction, distance bounds). |
Result types #
| Dart type | Description |
|---|---|
BcTrajectoryData |
One filtered trajectory record. |
BcHitResult |
Full trajectory list + BCLIBCFFI_TerminationReason. |
BcInterception |
Single interpolated point from integrateAtShot. |
BcMaxRangeResult |
Max range (ft) + angle (rad) from findMaxRangeShot. |
BcLibC methods #
| Method | Description |
|---|---|
BcLibC.open() |
Load the native library (call once at startup). |
integrateShot(BcShot, BcTrajectoryRequest) |
Full filtered trajectory. |
integrateAtShot(BcShot, key, value) |
Single interpolated point at a trajectory key. |
findZeroAngleShot(BcShot, distanceFt) |
Barrel elevation to zero at distance. |
findApexShot(BcShot) |
Highest point of the trajectory arc. |
findMaxRangeShot(BcShot) |
Maximum range and corresponding angle. |
getCorrection(distanceFt, offsetFt) |
Angular correction (rad) for a linear offset. |
calculateEnergy(grains, fps) |
Kinetic energy (ft-lb). |
calculateOgw(grains, fps) |
Optimal Game Weight. |
Legacy BcShotProps-based overloads (findApex, findMaxRange, etc.) are retained for backwards compatibility.
Enums #
| Dart enum | Description |
|---|---|
BCLIBCFFI_TrajFlag |
Trajectory filter flags (BCLIBCFFI_TRAJ_FLAG_RANGE, BCLIBCFFI_TRAJ_FLAG_APEX, …) |
BcTerminationReason |
Why integration stopped (BcHitResult.reason). |
BcBaseTrajInterpKey |
Key field selector for integrateAtShot (.posX, .time, .mach, …). |
BcIntegrationMethod |
BcIntegrationMethod.rk4 (default), .euler, .velocityVerlet (BcShot.method). |
BcTerminationReason, BcBaseTrajInterpKey, and BcIntegrationMethod (from
lib/ffi/bclibc_types.dart) are platform-agnostic — the same types work with
both BcLibC (native) and BcLibCWeb (web). They replace the raw
ffigen-generated BCLIBCFFI_* enum classes in the public API; those still
exist in bclibc_bindings.g.dart but are native-internal implementation
detail now.
Async API #
AsyncCalculator is the Future-returning counterpart to Calculator and the
one to use on the web. On native targets each call runs on a fresh isolate; on
the web the embedded wasm module is instantiated once (the only inherently async
part) and every call after that is a plain synchronous call into it.
import 'package:bclibc/bclibc.dart';
final result = await AsyncCalculator().fire(
shot: shot,
trajectoryRange: Distance.meter(1000),
);
Atmosphere and Coriolis #
When using BcShot:
- Pass
pressureHpa: 0for vacuum (zero drag). - Pass
latitudeDeg: double.nanto disable Coriolis (defaultBcShotvalue). - Pass
azimuthDeg: double.nanfor flat-fire drift only.
Unit system #
lib/unit.dart provides typed unit wrappers with an in_() / toDouble() API:
import 'package:bclibc/unit.dart';
final t = Temperature.celsius(15.0);
print(t.in_(TemperatureUnit.fahrenheit)); // 59.0
final d = Distance.meters(100.0);
print(d.in_(DistanceUnit.feet)); // 328.084...
Available types: Distance, Velocity, Temperature, Pressure, Angular, Weight, Energy.
Building #
Note
example/ is a Flutter app, and a plain dart pub get in the repository root
resolves it too. Without the Flutter SDK use dart pub get --no-example (the
Makefile and CI do).
Prerequisites #
- Dart SDK ≥ 3.11.4
- C++17 compiler (GCC / Clang on Linux/macOS, MSVC 2022 on Windows) — the build hook drives it directly, no CMake needed
- LLVM/Clang dev headers (only for regenerating FFI bindings)
- zig (via
uv run --with ziglang) — only for rebuilding the embedded wasm module
Clone #
git clone --recurse-submodules https://github.com/ballistics-lab/dart-bclibc.git
cd dart-bclibc
If you cloned without --recurse-submodules:
git submodule update --init
Native library #
There is no build step. hook/build.dart compiles libbclibc_ffi from the
bundled bclibc/ sources whenever Dart or Flutter needs it (dart run,
dart test, flutter run/build/test), and the @Native bindings in
lib/ffi/bclibc_bindings.g.dart resolve it through the resulting code asset —
the same way in every mode. A C++ toolchain (clang/gcc, MSVC or Xcode) must be
installed; nothing is downloaded.
Regenerate FFI bindings #
# Install LLVM first:
# Linux: sudo apt install libclang-dev clang
# macOS: brew install llvm
# Windows: winget install LLVM
make ffigen
The generated file is lib/ffi/bclibc_bindings.g.dart.
Run tests #
make test # native tests (the build hook compiles the library)
make web-test # web tests in Chrome, against the embedded wasm module
After bumping the bclibc submodule, rebuild the embedded wasm module with
uv run --with ziglang make build-wasm; make verify-bclibc (also run in CI,
and as a pre-commit hook after make install-hooks) checks that the submodule,
the wasm module and this package's changelog agree on one bclibc commit.
Native library #
| Platform | Library name |
|---|---|
| Linux | libbclibc_ffi.so |
| macOS | libbclibc_ffi.dylib |
| Windows | bclibc_ffi.dll |
Android and iOS are built by the same hook (the Flutter tool drives it for
those targets). WebAssembly uses the module embedded in
lib/ffi/bclibc_wasm.g.dart instead, rebuilt with make build-wasm.
Dependencies #
| Dependency | Role |
|---|---|
| bclibc | C++ ballistic solver engine (3-DOF + spin drift, RK4) — LGPL-3.0, bundled as a git submodule |
| ffi | Dart ↔ C FFI bindings |
| hooks, code_assets, native_toolchain_c | Build hook that compiles the bundled sources into a native asset |
| web | dart:js_interop bindings used by the web (wasm) backend |
License #
Copyright (C) 2026 Yaroshenko Dmytro (o-murphy)
This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License v3.0 as published by the Free Software Foundation.
See LICENSE for the full text. See CHANGELOG for release history.
Note
bclibc (the ballistic solver engine, located in bclibc/) is licensed separately under the GNU Lesser General Public License v3.0. See bclibc/LICENSE.
Warning
Risk notice. This package performs approximate simulations of complex physical processes. Calculation results must not be considered as completely or reliably reflecting actual projectile behaviour. Results may be used for educational purposes only and must not be relied upon in any context where an incorrect calculation could cause financial harm or put a human life at risk.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.