stable-rng
v1.0.0
Published
A deterministic pseudo-random number generator library with Mulberry32 algorithm
Maintainers
Readme
stable-rng
A lightweight, deterministic, and type-safe pseudo-random number generator (PRNG) for JavaScript and TypeScript.
stable-rng provides a reliable way to generate seeded random numbers without polluting the global scope. Unlike Math.random(), which is implementation-dependent and unpredictable, stable-rng guarantees that the same seed produces the exact same sequence of numbers across all platforms, browsers, and Node.js versions.
Features
- 🎯 Deterministic: Identical seeds always produce identical sequences.
- 🛡️ No Global Pollution: Creates isolated instances; does not monkey-patch
Math.random. - ⚡ Mulberry32 Algorithm: Fast, 32-bit PRNG with excellent statistical distribution.
- 🦕 Type-Safe: Written in TypeScript with first-class type definitions.
- 📦 Zero Dependencies: Extremely lightweight footprint.
- 🌲 Tree-Shakeable: Supports both ESM (
import) and CommonJS (require).
Installation
npm install stable-rng
# or
yarn add stable-rng
# or
pnpm add stable-rngQuick Start
import { createRng } from 'stable-rng';
// 1. Create a generator with a fixed seed
const rng = createRng(1337);
// 2. Generate numbers (range [0, 1))
console.log(rng()); // Always 0.685...
console.log(rng()); // Always 0.124...
console.log(rng()); // Always 0.953...API Reference
Core
createRng(seed: number): () => number
Creates a deterministic random number generator function.
- seed: A numeric value to initialize the generator state.
const rng = createRng(42);
const value = rng(); // Returns a float between 0 (inclusive) and 1 (exclusive)Helpers
The library provides statistically sound helper functions to avoid common implementation errors (such as modulo bias).
randomInt(min: number, max: number, rng?: () => number): number
Returns a random integer between min and max (inclusive).
// Roll a standard die
const diceRoll = randomInt(1, 6, rng);randomFloat(min: number, max: number, rng?: () => number): number
Returns a random float between min (inclusive) and max (exclusive).
// Generate a temperature between 20.0 and 25.0
const temp = randomFloat(20.0, 25.0, rng);randomChoice<T>(array: T[], rng?: () => number): T | undefined
Returns a random element from an array. Returns undefined if the array is empty.
const colors = ['red', 'green', 'blue'];
const pick = randomChoice(colors, rng);shuffle<T>(array: T[], rng?: () => number): T[]
Shuffles an array in-place using the Fisher-Yates algorithm.
const deck = [1, 2, 3, 4, 5];
shuffle(deck, rng); // The deck is now shuffledNote: All helper functions accept an optional
rngparameter. If omitted, they default to the standard (non-deterministic)Math.random().
Use Cases
🧪 Reproducible Testing
Eliminate flaky tests by using a fixed seed. Ensure your tests assert against the same generated data every time.
test('should generate consistent user data', () => {
const testRng = createRng(12345);
const user = generateRandomUser(testRng);
expect(user.age).toBe(24); // Guaranteed to be 24 every run
});🎮 Game Development
Essential for features like "Daily Challenges", procedural generation (seeds), or replay systems.
// A specific seed for "Level 1"
const levelSeed = 998877;
const levelRng = createRng(levelSeed);
const map = generateMap(levelRng);
// Every player gets the exact same map layout🔬 Scientific Simulations
Ensure Monte Carlo simulations or data samplings are peer-reviewable and replicable.
The Algorithm
This library implements Mulberry32, a 32-bit state generator chosen for:
- Speed: Optimized bitwise operations in JavaScript.
- Quality: Passes standard statistical tests (e.g., Dieharder) significantly better than simple Linear Congruential Generators (LCGs).
- Simplicity: Maintains a single 32-bit integer state.
