lambert-izzo
v2.0.0
Published
WASM bindings for the lambert_izzo solver
Readme
lambert-izzo (wasm)
WebAssembly bindings for lambert_izzo
— Izzo's revisited Lambert solver, callable from JavaScript and TypeScript.
The Rust core stays free of WASM concerns; this crate adds the
wasm-bindgen / tsify glue and ships as an npm package.
Install
npm install lambert-izzoWorks with bundlers (Vite, webpack, Rollup, esbuild) — the published npm
package is built with
wasm-pack's
--target bundler. For direct browser ES-module imports without a
bundler, or Node.js without the --experimental-wasm-modules flag,
build from source with --target web or --target nodejs (see the
target table under Building from source).
Usage
import init, { solveLambert, solveLambertBatch } from "lambert-izzo";
await init();
// Single solve — returns a `LambertOutcome` tagged union; never throws.
const result = solveLambert({
r1: [7000, 0, 0],
r2: [0, 7000, 0],
tof: 1457,
mu: 398600.4418,
way: "short",
maxRevs: null, // null = single-rev only; pass 1..=32 to search multi-rev branches
});
if (result.kind === "ok") {
console.log(result.response.single.v1); // velocity at r1
console.log(result.response.diagnostics.single.iters); // Householder iterations
} else {
console.error(result.error.kind, result.error);
}
// Batch — one outcome per input, ordering preserved, errors per-element.
const results = solveLambertBatch([request1, request2, request3]);
for (const r of results) {
if (r.kind === "ok") {
console.log(r.response.single.v1);
} else {
console.error(r.error.kind, r.error);
}
}Response shape
type LambertResponse = {
single: { v1: [number, number, number]; v2: [number, number, number] };
multi: Array<{
nRevs: number;
longPeriod: { v1: [...]; v2: [...] };
shortPeriod: { v1: [...]; v2: [...] };
}>;
diagnostics: {
single: { iters: number };
multi: Array<{
nRevs: number;
longPeriod: { iters: number };
shortPeriod: { iters: number };
}>;
};
};
type LambertOutcome =
| { kind: "ok"; response: LambertResponse }
| { kind: "err"; error: LambertErrorOutput };solveLambert returns one LambertOutcome; solveLambertBatch returns
LambertOutcome[] (one per input, in input order). Neither entry point
throws on solver-level failures — narrow on result.kind to access the
response or the structured error.
LambertErrorOutput is a discriminated union: switch on error.kind to
handle each failure mode. A concrete example:
{
kind: "DegeneratePositionVector",
position: "R1",
norm: 0.0,
}The discriminator values are: NonFiniteInput, NonPositiveTimeOfFlight,
NonPositiveMu, DegeneratePositionVector, CollinearGeometry,
NoConvergence, SingularDenominator, RevsOutOfRange, and Unknown.
Unknown { message } is a forward-compat fallback fired only if the
upstream Rust crate adds a new LambertError variant that this wasm
adapter does not yet mirror; message is the upstream error's Display
text. JS callers writing exhaustive switch blocks should include an
Unknown arm and report message verbatim.
Differences from the Rust crate
| Rust (core) | JS (wasm) | Why |
|-------------|-----------|-----|
| MultiRevSet (capacity 32) | Array<MultiRevPair> | JS has no fixed-size arrays. |
| RevolutionBudget enum | maxRevs: number \| null | null = single-rev only; 1..=32 searches multi-rev; out-of-range rejects with RevsOutOfRange. |
| Result<T, LambertError> | LambertOutcome tagged union | JS narrows on a discriminator field. |
| Diagnostics inside LambertSolutions | Diagnostics inside LambertResponse | Mirrors the core 1:1. |
Field names are camelCase via serde(rename_all = "camelCase"); types are
generated by tsify into the pkg/
output's .d.ts.
See also
- The Rust crate: https://crates.io/crates/lambert_izzo (canonical API,
[f64; 3]surface, no hard math-library dependency). - The single-page browser demo at
crates/lambert_izzo_wasm/examples/web/in the source repo. - The reference paper: D. Izzo, Revisiting Lambert's problem, CMDA 2014 (arXiv:1403.2705).
Building from source
wasm-pack build crates/lambert_izzo_wasm --target bundler --releaseThe generated crates/lambert_izzo_wasm/pkg/ is the npm artefact.
wasm-pack supports several target environments — pick the one that
matches how the consumer loads the module:
| Flag | When to use |
|------|-------------|
| --target bundler | npm consumers using Vite, webpack, Rollup, or any bundler that resolves import statements. This is what the published npm package ships with. |
| --target web | Direct browser ES-module imports, no bundler. Matches the examples/web/ demo. |
| --target nodejs | CommonJS consumption from Node.js. |
Publishing to npm
wasm-pack derives the npm package name from the Cargo crate name
(lambert_izzo_wasm → lambert-izzo-wasm). The published package is
lambert-izzo instead — Cargo can't reuse that name (the core crate on
crates.io already owns it), so the rename happens in the generated
pkg/package.json between build and publish:
wasm-pack build crates/lambert_izzo_wasm --target bundler --release
jq '.name = "lambert-izzo"' crates/lambert_izzo_wasm/pkg/package.json \
> crates/lambert_izzo_wasm/pkg/.package.json.tmp \
&& mv crates/lambert_izzo_wasm/pkg/.package.json.tmp \
crates/lambert_izzo_wasm/pkg/package.json
cd crates/lambert_izzo_wasm/pkg && npm publishThe version comes from the workspace Cargo.toml and stays in lockstep
with the lambert_izzo crates.io release.
License
MIT OR Apache-2.0
