Reproducibility
import { Random, engines } from "ransu";
const r = new Random(42); // xoshiro128++ by defaultconst p = new Random(42, { engine: engines.pcg32 });
r.integer(1, 6);Same seed, same sequence — across runs, runtimes, and ESM versus CommonJS.
Numbers, bigints, strings, byte arrays and number arrays all work:
new Random(42);new Random("my-fixture");new Random(2n ** 70n);new Random(new Uint8Array([1, 2, 3]));Every seed goes through a mixing step first. Feeding a raw seed straight into a
PRNG is the classic way to get correlated streams from nearby seeds; new Random(1) and new Random(2) are unrelated here.
Saving and restoring
Section titled “Saving and restoring”const snapshot = r.getState(); // plain JSON: send it anywherer.setState(snapshot); // exactly where it wasRestoring into a different algorithm throws STATE_MISMATCH instead of
producing quiet nonsense.
Independent streams
Section titled “Independent streams”const [a, b] = r.split(2); // for workers, shards, parallel simulationsEngines with a jump polynomial give non-overlapping streams; the others derive child seeds, which is enough for practical independence.
Seeding the global
Section titled “Seeding the global”import { seed, integer } from "ransu";
seed(42);integer(1, 6); // deterministic from here onThe global starts on Math.random, which cannot be seeded, so seed() swaps in
xoshiro128++. Applications may do this; libraries should not rely on it.
The stream contract
Section titled “The stream contract”Within one major version, the same engine and seed produce the same output. That
covers engine bits, the core conversions, the order in which shuffle, sample
and weightedPick consume values, and every distribution algorithm.
A faster algorithm gets a new name rather than replacing an existing one. CI holds golden snapshots of every engine’s first outputs, so an accidental change fails the build.
Time-based identifiers (UUID v1, v6, v7 and ULID) depend on the wall clock and
are outside this contract. Pass now to make them deterministic.