Returns a float in [0, 1), derived from one uint32 draw. Resolution is
2^-32, not the full 2^-53 a double can hold.
Not used by the evaluator — dice go through nextInt.
A float in [0, 1)
Returns an integer in the inclusive range [min, max], uniformly
distributed — rejection sampling removes the modulo bias a plain
% range would introduce.
Bounds handling, in order:
min > max is normalized by swapping, so nextInt(6, 1) behaves as
nextInt(1, 6). (The mock RNG throws instead; see RNG.nextInt.)min === max returns that value without consuming a draw.RangeError rather than silently skewing.Lower bound, inclusive
Upper bound, inclusive
An integer in [min, max]
Returns the current state as a format version followed by four unsigned 32-bit words. Feeding the snapshot back to the constructor resumes this exact sequence; the source instance is untouched, and the two then advance independently.
The words are RngState — opaque, restorable within the major
version that produced them, and rejected with INCOMPATIBLE_RNG_STATE
outside it.
A snapshot of the version and the four state words
import { SeededRNG, roll } from 'roll-parser';
const rng = new SeededRNG();
const snapshot = rng.state();
const first = roll('1d20', { rng });
const replay = roll('1d20', { rng: new SeededRNG(snapshot) });
first.total === replay.total; // true
Not a fork primitive. A restored generator replays the parent's stream, so children taken at different points are the same sequence at an offset, not independent substreams — derive a seed per entity instead.
Seedable pseudo-random number generator using xoshiro128**. The default randomness source —
roll(notation)builds one per call, androll(notation, { seed })builds one from your seed.Period 2^128 - 1. Every seed is stringified and hashed with cyrb128 into the full 128-bit state, so numeric seeds keep all 53 bits and unrelated strings are overwhelmingly unlikely to share a state; an omitted seed hashes
Date.now()together with twoMath.random()draws, roughly 100 bits of width rather than 32 — wide enough that concurrently created generators are very unlikely to collide, though unpredictability stays bounded by the host engine'sMath.random()seeding. The first 8 draws are discarded as a run-in.Stringifying means
42and'42'are the same seed — the two forms share one namespace, which matters when seeds arrive from a CLI flag or JSON.state snapshots the state words as a versioned RngState, and passing one to the constructor resumes that exact sequence — restore copies the words verbatim, skipping both the hash and the run-in. A snapshot from another format version throws
INCOMPATIBLE_RNG_STATE; within the current version the type is the contract, and a hand-built tuple is coerced to 32 bits per word rather than rejected.Reproducibility guarantee: the same seed and the same notation produce the same dice for the lifetime of a major version, and
RngStatecarries that binding. The one exception is a genuine distribution bug — bias, faulty rejection sampling — which may change the mapping in a minor release, never silently in a patch, and always with aBREAKINGchangelog note. The sequence is not cryptographically secure. To pin a roll beyond that, persist the RollResult rather than re-deriving it from a seed.Example