npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

fast-prng-wasm

v3.2.0

Published

High-performance, SIMD-enabled WebAssembly PRNGs with a seamless TypeScript interface. Includes PCG, xoroshiro128+, and xoshiro256+

Readme

fast-prng-wasm

MIT License npm package version CI/CD Pipeline codecov

High-performance, SIMD-enabled, WebAssembly pseudo random number generators (PRNGs) with a seamless TypeScript interface. Faster and better statistical quality than Math.random().

Perfect for: Simulations, Monte Carlo methods, games, procedural generation, parallel computations

Quick Start

npm install fast-prng-wasm
import { RandomGenerator } from 'fast-prng-wasm';

const gen = new RandomGenerator();  // Xoroshiro128+ SIMD is default
console.log(gen.float());           // random 53-bit float (number) in [0, 1)
console.log(gen.int53());           // random 53-bit int (number)
console.log(gen.int64());           // random 64-bit int (bigint)

Features

  • 🚀 High Performance - Optimized for speed and SIMD-accelerated
  • 📊 Better Statistical Quality - Superior uniformity and randomness vs. Math.random()
  • ⚡ Bulk Generation - Single values or bulk array fills
  • 🎯 Simple API - Clean TypeScript interface, no memory-management required
  • 🔢 Multiple Formats - 64-bit bigint, 53-bit int, 32-bit int, and 53-bit float
  • 🌱 Seedable - Full control over initialization (or automatic seeding)
  • 🧵 Parallel-Ready - Unique stream selection for multi-threaded applications
  • ✨ Zero Config - Synchronous WASM loading, no fs or fetch required
  • 🌐 Universal - Works in Node.js 18+ and all modern browsers
  • 📦 AssemblyScript Library - Can be imported to larger WASM project builds

PRNG Algorithms

| Algorithm | Description | Native Output | State Size | Period | SIMD | |-----------|-------------|---------------|------------|--------|------| | Xoshiro256+ | Very fast, large state, very long period - best for applications needing maximum randomness guarantees | 64-bit | 256 bits | 2256 | ✅ | | Xoroshiro128+ | Very fast, smaller state - excellent balance for most applications, fastest provided here | 64-bit | 128 bits | 2128 | ✅ | | PCG (XSH RR) | Small state, fast, possibly best randomness (read Learn More links) | 32-bit | 64 bits | 264 | ❌ |

The included algorithms were chosen for their high speed, parallelization support, and statistical quality. They pass rigorous statistical tests (BigCrush, PractRand) and provide excellent uniformity, making them suitable for Monte Carlo simulations and other applications requiring high-quality pseudo-randomness. They offer a significant improvement over Math.random(), which varies by JavaScript engine and may exhibit statistical flaws.

SIMD (Single Instruction, Multiple Data) generates 2 random numbers simultaneously, theoretically doubling throughput when using array output methods.

⚠️ Security Note: These PRNGs are NOT cryptographically secure. Do not use for cryptography or security-sensitive applications, as they are not resilient against attacks that could reveal sequence history.

Learn More

Usage Guide

Importing

ES Module (bundler / modern browser / modern Node)

import { RandomGenerator, PRNGType, seed64Array } from 'fast-prng-wasm';

CommonJS (legacy Node)

const { RandomGenerator, PRNGType, seed64Array } = require('fast-prng-wasm');

UMD (browser script tag)

<script src="https://unpkg.com/fast-prng-wasm"></script>
<script>
  const { RandomGenerator, PRNGType, seed64Array } = fastPRNGWasm;
</script>

The Basics

const gen = new RandomGenerator();      // Xoroshiro128Plus_SIMD, auto-seeded
console.log(gen.int64());               // unsigned 64-bit int (bigint)
console.log(gen.int53());               // unsigned 53-bit int (number)
console.log(gen.int32());               // unsigned 32-bit int (number)
console.log(gen.float());               // 53-bit float (number) in [0, 1)
console.log(gen.coord());               // 53-bit float (number) in (-1, 1)
console.log(gen.coordSquared());        // 53-bit float (number) in (-1, 1) squared

const pcgGen = new RandomGenerator(PRNGType.PCG);
console.log(pcgGen.int64());
// ... etc - all PRNG types expose the same JS/TS interface

The internal WASM binary is instantiated automatically when a RandomGenerator instance is created.

Array Output (Bulk Array Fill)

The fastest way to get random numbers in bulk is to use the *Array() methods of RandomGenerator. Each call fills a WASM memory buffer with the next 1000 (by default) random numbers, and returns a view of the buffer as an appropriate TypedArray: either BigUint64Array for int64Array(), or Float64Array for all methods.

💡 SIMD Performance: Array methods MUST be used to realize the additional throughput offered by SIMD-enabled PRNG algorithms. These have higher throughput because they produce 2 random numbers at the same time with WASM's 128-bit SIMD support) .

Bulk Fill Example

const gen = new RandomGenerator();

// `bigint`s in BigUint64Array
const bigintArray = gen.int64Array();     // 1000 64-bit integers

// `number`s in Float64Array
let numberArray = gen.int53Array();       // 1000 53-bit integers
numberArray = gen.int32Array();           // 1000 32-bit integers
numberArray = gen.floatArray();           // 1000 floats in [0, 1)

WASM Array Memory Buffer

⚠️ Reused Buffer Warning: The array returned by these methods is actually a DataView looking at a portion of WebAssembly memory. For performance, this memory buffer is reused between calls to the *Array() methods by default (to minimize WASM-JS boundary crossing time), so you must actually consume (e.g. read/copy) the output between each call (unless using the copy param).

const gen = new RandomGenerator();

// ⚠️ Warning: Consume before making another call to any method that returns a Float64Array
const array1 = gen.floatArray();          // 1000 floats in [0, 1)
console.log(array1);                      // consume (extract random results)

// Values originally in array1 have been replaced! (despite different local variable)
const array2 = gen.floatArray();          // 1000 new floats in [0, 1)
console.log(array2);                      // consume again (extract more random results)

console.log(array1 === array2);           // true (same array in memory)
console.log(array1[42] === array2[42]);   // true (second call refilled the same array)

Copying Arrays: If you need to store multiple arrays, use the optional copy parameter:

// Get independent copies
const array1 = gen.floatArray(true);      // Pass true to copy
const array2 = gen.floatArray(true);      // Each call returns a new array

console.log(array1 !== array2);           // true (different arrays)
console.log(array1[0] !== array2[0]);     // true (different values preserved)

Performance Note: Using copy=true is 30-50% slower than the default buffer reuse, but provides safety when storing multiple arrays.

Set Array Output Size

If you don't need 1000 numbers with each method call, you can specify your preferred size for the output array via the constructor. Note that an array larger than the default of 1000 does not increase performance further in test scenarios. For a detailed explanation, see: Understanding Performance: Why Array Methods Are Faster.

// Set size of output buffer to 200
//  - `null` for `seeds` param will auto-seed
//  - `null` for `uniqueStreamId` param will use default stream
const gen = new RandomGenerator(PRNGType.PCG, null, null, 200);
let randomArray = gen.floatArray();       // 200 floats in [0, 1)

// To use a different size, create a new generator instance
const gen2 = new RandomGenerator(PRNGType.PCG, null, null, 42);
randomArray = gen2.floatArray();          // 42 floats in [0, 1)

⚙ Memory Constraint Note: The outputArraySize parameter is immutable after construction due to intentional memory constraints. We use AssemblyScript's stub runtime for performance, but it employs a simple bump allocator that never frees memory. asconfig.release.json specifies a fixed WASM memory size of 1 page (64KB) - intentionally kept small to limit resources, but enough space for the default of 1000 numbers. This allows a maximum array size of ~3000 elements, considering that we allocate 2 types for each generator.

Arrays exceeding memory limits will fail at construction:

// exceeds the configured memory limits of WASM instances
const gen = new RandomGenerator(PRNGType.PCG, null, null, 5000);  // Runtime Error ⚠️

Manual Seeding

Manual seeding is optional. When no seeds are provided, a RandomGenerator will seed itself automatically.

Manual seeding is done by providing a collection of bigint values to initialize the internal generator state. Each generator type requires a different number of seeds (between 1 and 8). The required count for a specific PRNG is exposed via RandomGenerator's seedCount property, as well as in the SEED_COUNT variable and setSeed() function signature in the AssemblyScript API.

const customSeeds = [7n, 9876543210818181n];    // Xoroshiro128+ takes 2 bigint seeds
const customSeededGen = new RandomGenerator(PRNGType.Xoroshiro128Plus, customSeeds);

const anotherGen = new RandomGenerator(PRNGType.Xoshiro256Plus);
console.log(anotherGen.seedCount);              // 4

Using high quality seeds is important, as summarized on Vigna's Xoshiro page:

We suggest to use SplitMix64 to initialize the state of our generators starting from a 64-bit seed, as research has shown that initialization must be performed with a generator radically different in nature from the one initialized to avoid correlation on similar seeds.

Per this guidance, automatic seeding using seed64Array() internally is done with SplitMix64.

Parallel Generators & Sharing Seeds

Some PRNG applications may require several (or very many) instances of a PRNG running in parallel - for example, multithreaded or distributed computing processes. In this case it is recommended to use the same set of seeds across all parallel generator instances in combination with a unique jump count or stream increment. This approach essentially ensures that randomness quality is maximized across all parallel instances.

See the pmc demo for an example that follows this approach, with each generator instance running in a different Node worker thread.

Generate a Seed Collection

If you don't have custom seeds already, the seed64Array() function is provided. It returns a bigint[8] containing seeds generated with SplitMix64. The initial SplitMix64 seed uses crypto.getRandomValues() when available (all modern browsers and Node.js 15+) for strong entropy, falling back to combining multiple entropy sources (Date.now(), performance.now(), and Math.random()) in older environments. This collection can be provided as the seeds argument for any PRNG in this package.

Choose a Unique Stream for Each Parallel Generator

Sharing seeds between generators assumes you will also provide a unique uniqueStreamId argument:

  • For the PCG PRNG, this will set the internal increment value within the generator, which selects a unique random stream given a specific starting state (seed).
  • For Xoshiro family PRNGs, this will advance the initial state (aka jump()) to a unique point within the generator period, allowing for effectively the same behavior - choosing a non-overlapping random stream given a specific starting state

In both cases, this value is simply a unique positive integer (the examples below provide this as bigint literals).

Examples

const sharedSeeds = seed64Array();    // bigint[8]

// Two PCG generators, using the same seeds but choosing unique stream increments (5n vs 4001n)
const pcgGen1 = new RandomGenerator(PRNGType.PCG, sharedSeeds, 5n);
const pcgNum1 = pcgGen1.float();

const pcgGen2 = new RandomGenerator(PRNGType.PCG, sharedSeeds, 4001n);
const pcgNum2 = pcgGen2.float();

console.log(pcgNum1 === pcgNum2);     // false

// Two Xoshiro256+ generators using the same seeds, but with unique jump counts (1n vs 13n)
const seededGen1 = new RandomGenerator(PRNGType.Xoshiro256Plus_SIMD, sharedSeeds, 1n);
const num1 = seededGen1.float();

const seededGen2 = new RandomGenerator(PRNGType.Xoshiro256Plus_SIMD, sharedSeeds, 13n);
const num2 = seededGen2.float();

console.log(num1 === num2);           // false

// Another Xoshiro256+ generator using the same seeds, and same jump count (13n) as seededGen2.
// ⚠️ seededGen2 and seededGen3 are effectively identical and will return the same random stream.
const seededGen3 = new RandomGenerator(PRNGType.Xoshiro256Plus_SIMD, sharedSeeds, 13n);
const num3 = seededGen3.float();

console.log(num2 === num3);           // true: using same seeds and same uniqueStreamId!!

Using from AssemblyScript Projects

// import the namespace(es) you want to use
import { PCG, Xoroshiro128Plus } from 'fast-prng-wasm/assembly';

Xoroshiro128Plus.setSeeds(57n, 1000123n);             // manually seeded - seed64Array() only in JS

const rand: u64 = Xoroshiro128Plus.uint64();          // using the AS interface
const rand2: f64 = Xoroshiro128Plus.uint53AsFloat();  // return types are cast for JS runtime usage

const arr = new Uint64Array(1000);                    // create array in WASM memory
Xoroshiro128Plus.uint64Array(arr);                    // generate & fill

⚠️ Thread Safety Warning ⚠️: WASM PRNG implemetations use top-level internal state and functions to prevent the accumulation of small overhead that comes with using classes.

While they are encapsulted within namespaces so as not to interfere with your own AssemblyScript project's global namespace, this also means that they are NOT THREAD SAFE WITHIN WASM DIRECTLY.

To acheive thread safety from the JS runtime calling your AssemvblyScript WASM project binary, it must be structured in such a way as to create separate WASM instances from JS. This is the approach used by the included JavaScript/TypeScript wrapper API.

API Documentation

Examples & Demos

See the examples/ folder for all available examples and demos.

basic-usage - Getting Started

A simple walkthrough of core features

  • Quick start for new users
  • Covers all major API methods
  • Basic performance comparisons and tips
  • Practical examples (dice simulator, Monte Carlo basics)

pmc - Pi Monte Carlo

A Monte Carlo statistical estimation of π (pi) using a large quantity of random numbers

  • Node CLI app for advanced users
  • Uses parallel generator instances in worker_threads
  • Shares seeds across instances, using a unique jump count / stream increment for each

Testing & Verification

This library employs a dual-layer testing strategy to ensure algorithm correctness and statistical quality:

AssemblyScript Unit Tests validate core algorithm implementations:

  • Determinism: 10K-sample sequences match exactly with same seeds (chance coincidence effectively zero)
  • Uniqueness: 10K consecutive values confirmed unique (collision probability ~10⁻¹²)
  • Range validation: 10K samples verify correct boundaries (high/low bit coverage >99.99%)
  • Uniformity smoke tests: Basic quartile distribution checks across 100K samples
  • Monte Carlo smoke tests: π estimation within expected tolerance across 100K samples

JavaScript Integration Tests provide rigorous statistical validation:

  • Chi-square uniformity: 1M samples detect deviations as small as 0.3% (>99.9% confidence)
  • Serial correlation: 100K samples verify independence with standard error ~0.003 (>99.9% confidence)
  • Monte Carlo π estimation: 1M samples with tolerance ±0.01 (>99.9% confidence)
  • Randomized edge case testing: 10 iterations per test with freshly generated random seeds on each run to catch edge cases fixed seeds might miss

All algorithms are tested for uniqueness, full-range output, array method consistency, and parallel stream independence. The test suite maintains >90% code coverage across both AssemblyScript and JavaScript layers.

| Test Type | Sample Size | Statistical Power | Purpose | |-----------|-------------|-------------------|---------| | AS: Deterministic | 10K | N/A (deterministic) | Algorithm correctness | | AS: Distribution | 100K | >99% confidence | Smoke testing | | JS: Chi-square | 1M | >99.9% confidence | Uniformity validation | | JS: Correlation | 100K | >99.9% confidence | Independence validation | | JS: Monte Carlo | 1M | >99.9% confidence | Comprehensive validation |

Performance

The goal is to provide random number generation in WASM that's faster and higher-quality than Math.random(), and faster than any equivalent JavaScript implementation of these PRNG algorithms.

Generator algorithms are implemented in AssemblyScript, a variant of TypeScript that compiles to WASM.

Key performance advantages:

  • PRNG algorithms chosen for speed
  • WASM is faster than JS by design
  • AssemblyScript project structure and compilation are optimized for speed
  • Bulk array generation minimizes JS/WASM boundary crossing overhead
  • Reusing WASM array memory avoids alloc delays and heap fragmentation
  • SIMD acceleration can nearly double throughput for supported algorithms
  • Monte Carlo unit square vs unit circle test included for validation

⚡ Additional performance stats coming soon! ⚡

Arrays Deep Dive

For a detailed explanation of why array methods are 3-5× faster than single-value methods, see Understanding Performance: Why Array Methods Are Faster

Compatibility

Node

| Version | Notes | |---------|-------| | 18+ | Full support | | 16.4+ | All features, but EOL (not tested) | | 15.0 | All features except SIMD (not tested) | | <15 | No SIMD, No bigint (not tested) |

Node 18+ is required. Older versions may work but are not tested or supported (Node 16 reached EOL in September 2023).

Browsers

All modern browsers are fully supported.

| Browser | Full Support | Partial (No SIMD) | Degraded (No bigint) | |---------|--------------|-------------------|------------------------| | Chrome | 91+ | 85 | 57 | | Edge | 91+ | 85 | 16 | | Safari | 16.4+ | 14.1 | 11 | | Firefox | 89+ | 78 | 52 | | Opera | 77+ | 71 | 44 |

Check caniuse.com for other browser support:

  • WASM SIMD - Indicates Full Support
  • WASM bigint - Support for everything except SIMD
  • WASM - Basic support (53-bit int and float number but no 64-bit bigint)

Contributing

This is an open source project, and contributions are welcome!

  • Bugs: Open an Issue to report a bug or request a feature
  • Features: For now, please first open an Issue to discuss any desired / planned contributions
  • Full contribution guidelines coming soon
  • See scripts in package.json for available build commands

License

MIT License