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

@neutrium/rand

v1.0.0

Published

High-performance random number generators for JavaScript, WebAssembly and WebGPU.

Readme

@neutrium/rand

High-performance deterministic and secure random number generators for web and node applications.

The package provides several backend options including low-overhead JavaScript generators, fast WebAssembly (WASM) via the Rust/rand crate and faster WebGPU for large workloads.

Contents

Installation

Install @neutrium/rand with npm or pnpm as shown below. Note Node.js 20 or newer is required (The package is ESM-only).

# Install using pnpm
pnpm add @neutrium/rand

# Install using npm
npm install @neutrium/rand

Quick start

import { Random } from "@neutrium/rand";

const rng = Random.fast("experiment-42");

const scalar = rng.next();
const integer = rng.next_u32();
const values = rng.float64_array(1_000_000);
const reusable = rng.fill(new Float32Array(1_000_000));
const bounded = rng.integer(100);
const normal = rng.normal(0, 1);

Use the uniform asynchronous create API when the backend may vary:

const rng = await Random.create({
	seed: "experiment-42"
});

const values = await rng.float64_array(5_000_000);
await rng.destroy_async();

Demos

Algorithms

Overview

A number of algorithms have been included in @neutrium/rand. These algorithms have been selected because they are best-in-class for specific use cases. They are summarised below:

| Algorithm | Primary use | Security | | --- | --- | --- | | Xoshiro128++ | Low-overhead JavaScript scalar calls | Non-cryptographic | | Xoshiro256++ | Sequential CPU Monte Carlo | Non-cryptographic | | Philox4x32-10 | Counter-partitioned CPU/GPU work | Non-cryptographic | | PCG32 | Explicit independent CPU streams | Non-cryptographic | | ChaCha20 | Deterministic state-inference resistance | Cryptographic primitive | | System CSPRNG | Fresh unpredictable entropy | Cryptographic | | SplitMix64 | Internal seed expansion | Non-cryptographic |

Xoshiro128++

A four-word, 128-bit-state generator designed around 32-bit rotates, XORs, and shifts. These operations map efficiently to JavaScript integer operators, making it the scalar default.

References: Blackman and Vigna, Scrambled Linear Pseudorandom Number Generators; xoshiro128++ reference implementation; rand_xoshiro

Xoshiro256++

A 256-bit-state generator for sequential Monte Carlo workloads. The JavaScript implementation represents 64-bit lanes as 32-bit words to avoid BigInt in the hot path. The WASM bridge uses the rand_xoshiro crate.

References: Blackman and Vigna, Scrambled Linear Pseudorandom Number Generators; xoshiro256++ reference implementation; rand_xoshiro

Philox4x32-10

A counter-based generator transforming a 128-bit counter with a 64-bit key over ten rounds and returning four uint32 words per block. Counter independence makes deterministic CPU workers and WebGPU dispatch straightforward. The TypeScript, Rust/WASM, and WGSL implementations are exact-parity tested.

References: Salmon et al., Parallel Random Numbers: As Easy as 1, 2, 3; Random123 Reference Implementations.

ChaCha20

The 20-round ChaCha stream cipher is used as a deterministic random word stream. SHA-256 from @noble/hashes derives the key and nonce material from the public seed API. Security depends on the entropy and secrecy of the seed.

References: Bernstein, ChaCha, a variant of Salsa20; RFC 8439.

System CSPRNG

Uses globalThis.crypto.getRandomValues backed by the platform’s secure random source. Requests are cached for scalar efficiency and chunked to the Web Crypto request limit.

Reference: Web Cryptography API.

SplitMix64

A 64-bit mixer used internally to expand seeds into the generator state. It is exported only for advanced seeding workflows and is not a security generator.

References: Steele, Lea, and Flood, Fast Splittable Pseudorandom Number Generators; SplitMix64 reference implementation.

PCG32

The XSH-RR 64/32 variant combines a 64-bit linear-congruential transition with an output permutation. The odd increment selects one of 2^63 independent streams. Numeric stream IDs must be non-negative integers below 2^63; strings and byte arrays are hashed into that stream space. The JavaScript implementation uses portable BigInt arithmetic; the WASM bridge uses rand_pcg.

References: O'Neill, PCG A Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation; PCG reference implementation; rand_pcg

Choosing an Algorithm and Backend

Choosing the best backend can be complicated, as performance depends on more than just generator throughput. Initialisation, allocation, worker coordination, GPU submission, readback, and downstream calculation all impact performance. This section provides guidance on selecting the best backend; however, for performance-critical applications, it is recommended that you benchmark on your target hardware.

CPU (Javascript & WASM) vs GPU (WebGPU)

This package includes implementations that will run on the CPU or the GPU. To reduce the core dependencies, the WebGPU implementations are maintained on a separate subpath:

import { Random } from "@neutrium/rand";
// or
import { Random } from "@neutrium/rand/webgpu";

Both paths use the same high-level type names: RandomCapabilities, RandomCreateOptions, RandomGenerator, Recommendation, and RecommendationOptions. The WebGPU subpath widens those types with its optional backend, output-location, and timestamp fields. Recommendation is asynchronous on both paths, so switching imports does not change the calling convention or require renamed types.

If you have the potential to run on the GPU and don’t mind the additional dependencies, favour importing @neutrium/rand/webgpu.

Ask the library

To receive a deterministic recommendation from the library:

import { Random } from "@neutrium/rand/webgpu";

const recommendation = await Random.recommend({
	call_pattern: "bulk",
	length: 8_000_000,
	security: "none",
	output_location: "gpu",
	workers: 1
});

console.log(recommendation);
// {
//   algorithm: "philox4x32-10",
//   backend: "webgpu",
//   confidence: "default",
//   reason: "...",
//   alternatives: [...]
// }

If confidence: "benchmark-required" is returned, the backend recommendation is highly dependent on transfer or deployment details.

Recommendation objects intentionally contain valid algorithm and backend creation options. Pass them directly to the corresponding creation API, adding only stream state, such as the seed and stream identifier:

const recommendation = await Random.recommend({ length: 100_000 });

const rng = await Random.create({
	...recommendation,
	seed: "experiment-42"
});

The default crossover values — 16,384 for WASM and 1,000,000 for WebGPU — are conservative routing hints, not performance guarantees. Calibrate them with pnpm benchmark on the deployment target to find the best crossover points.

Manual Selection

The following list is some general guidelines on selecting which algorithm and backend will be best for you.

  1. If output must be freshly unpredictable, use Random.secure().
  2. If output is deterministic but must resist state inference, use Random.secure(seed).
  3. If calls are scattered scalars, use Random.scalar(seed).
  4. If work is divided between CPU workers, assign Philox streams/counter ranges or PCG stream IDs.
  5. If a large simulation consumes values on the GPU, use Philox WebGPU and keep the buffer resident.
  6. If generated values return to the CPU, benchmark WASM against WebGPU end-to-end.
  7. Otherwise, use Xoshiro256++ JavaScript for small batches and WASM for large batches.

A general selection matrix is presented below. Note that this does not consider the requirements for cryptographically secure random numbers.

| Environment | Workload | Starting choice | Why | | --- | --- | --- | --- | | CPU only | One or scattered values | Xoshiro128++ JS | Lowest API/setup overhead | | CPU only | Small sequential batch | Xoshiro256++ JS | No WASM boundary cost | | CPU only | Large sequential batch | Xoshiro256++ WASM | Bulk transfer amortises setup | | Multiple CPU workers | Reproducible partitions | Philox | Counter and stream partitioning | | Multiple CPU workers | Long independent streams | PCG32 | Explicit odd-increment streams | | GPU available | Small batch | JavaScript/WASM | GPU submission dominates | | GPU available | Large batch returned to CPU | Benchmark Philox WebGPU and WASM | Readback is hardware-dependent | | GPU available | Large GPU-resident simulation | Philox WebGPU | Avoids the largest transfer |

API

A summary of the high level API is provided below. Detailed API documentation is available at /docs/api/.

import { Random } from "@neutrium/rand";

Random.fast(seed);                       // Xoshiro256++
Random.scalar(seed);                     // Xoshiro128++
Random.parallel(seed, stream, counter);  // Philox4x32-10
Random.stream(seed, stream);             // PCG32
Random.secure();                         // System CSPRNG
Random.secure(seed);                     // Deterministic ChaCha20

await Random.create(options);             // Uniform async generator factory
await Random.capabilities();              // Probes runtime capabilities
await Random.recommend(workload);         // Recommends a algorithm and backend

Applications that may use WebGPU replace only the import. The method names and calling conventions remain the same:

import { Random } from "@neutrium/rand/webgpu";

await Random.capabilities();              // Also reports verified WebGPU availability
await Random.recommend(workload);         // Includes WebGPU in workload recommendations
await Random.create(options);             // Uniform async API with WebGPU fallback

Seeds may be numbers, bigints, strings, or byte arrays. Equal seed bytes and options produce equal streams across supported platforms and parity-tested backends.

Synchronous generators provide:

next_u32();
next();
next_f64();
fill(target);
uint32_array(length);
float32_array(length);
float64_array(length);
bytes(length);
integer(max_exclusive);
normal(mean, standard_deviation);
exponential(rate);
destroy();

fill(target) always reuses a caller-owned buffer. The typed *_array() methods always allocate a new buffer. Synchronous generators return the array directly; Random.create() from either package path exposes the same allocation names asynchronously.

With backend: "auto", the first non-empty array request supplies the workload length used to choose JavaScript, WASM, or optional WebGPU. The selected backend is then retained so subsequent calls continue the same stream.

Passing an AbortSignal to an array method on a generator returned by Random.create() enables cooperative JavaScript and WASM generation in bounded chunks. Cancellation can consume values generated before the signal is observed, so discard or checkpoint that generator when retrying must reproduce the same stream position.

Parallel CPU Workers

Parallel reproducibility requires deterministic ownership of streams or counter ranges. A shared seed will create the same sequences of random numbers.

Philox streams

Give each worker a unique persisted stream ID:

const worker_id = 7;
const rng = Random.parallel("portfolio-2026", worker_id);
const samples = rng.fill(new Float64Array(2_000_000));

Do not derive stream IDs from transient process IDs or queue order. A job coordinator should assign them.

Philox emits four uint32 words per counter block. Allocate non-overlapping block ranges when jobs may generate different lengths:

const words_per_job = 4_000_000;
const blocks_per_job = Math.ceil(words_per_job / 4);
const starting_counter = job_id * blocks_per_job;
const rng = Random.parallel(seed, stream_id, starting_counter);

Validate that the largest job ID cannot exceed the supported counter space.

PCG streams

Use Random.stream(seed, stream_id) when the application already models long-lived independent CPU streams. Philox is generally easier for arbitrary job partitioning because a counter directly identifies work.

GPU Simulations

Philox is available through WebGPU because its counter-based blocks can be computed independently. WebGPU is useful when a large generated buffer is consumed by subsequent GPU work.

WebGPU is an optional API surface. It is not loaded or included in the root @neutrium/rand declarations. Install the WebGPU declarations and import the dedicated subpath only in projects that use it:

pnpm add @neutrium/rand
pnpm add -D @webgpu/types

Add "@webgpu/types" to compilerOptions.types, then import the subpath:

import { Random } from "@neutrium/rand/webgpu";

CPU readback

const rng = await Random.create({
	algorithm: "philox4x32-10",
	backend: "auto",
	seed,
	stream: 7
});
const values = await rng.uint32_array(length);
await rng.destroy_async();

This includes allocation, dispatch, command submission, GPU-to-CPU copying, and mapping. Compare it against WASM on the target device. A discrete GPU can have excellent compute throughput while losing the complete workload benchmark to readback latency.

GPU Resident

const rng = await Random.create({
	algorithm: "philox4x32-10",
	backend: "webgpu",
	seed,
	stream: 7
});
const generated = await rng.generate_buffer({
	length,
	usage: GPUBufferUsage.COPY_SRC
});

// Create the consumer bind group on generated.device.
// Bind generated.buffer as read-only storage.
// Submit the consumer work before destroying either object.

generated.buffer.destroy();
await rng.destroy_async();

The returned buffer length must be a positive multiple of four, and it must fit maxBufferSize, maxStorageBufferBindingSize, and dispatch limits. Typed-array requests are chunked; GPU-resident requests deliberately fail rather than returning several buffers with an ambiguous consumer contract.

Testing

Several tests are included in @neutrium/rand. These are listed below, along with any requirements in addition to running pnpm bootstrap.

| Command | Additional setup | Purpose | Notes | | --- | --- | --- | --- | | pnpm test | None after bootstrap | Deterministic, property, parity, and distribution tests | Node correctness, parity, properties, distribution smoke tests, and mocked WebGPU lifecycle tests | | pnpm test:coverage | None after bootstrap | Enforced coverage thresholds | Runs the Node suite with enforced coverage thresholds | | pnpm test:rust | None after bootstrap | Native Rust bridge tests | Uses the toolchain pinned in rust-toolchain.toml | | pnpm test:package | tar on PATH | Packed ESM, declarations, export restrictions, and file layout | Rebuilds and inspects the packed ESM-only package | | pnpm test:statistical | None after bootstrap | Deterministic distribution smoke tests | Fast deterministic distribution checks; it does not invoke PractRand | | pnpm test:browser | Playwright Chromium, Firefox, and WebKit | Tests Chromium, Firefox, and WebKit availability | Builds first, then runs the browser suite in all three engines | | pnpm statistical:practrand | PractRand RNG_test executable on PATH | Statistical testing using the PractRand battery | Streams a large battery input; PractRand is not a pnpm dependency |

Generated test artifacts are grouped under reports/: coverage output in reports/coverage, Playwright's HTML report in reports/playwright, and individual test-run artifacts and statistical reports in reports/tests.

Statistical Tests

External statistical test suites are not installed by default and require additional setup.

PractRand

PractRand is a C++ test suite and can be downloaded from the official PractRand site. Follow installation.txt to build the RNG_test command and place that executable on PATH.

Use a small local smoke run before starting the default multi-gigabyte battery:

PRACTRAND_WORDS=1048576 \
PRACTRAND_SEEDS=smoke \
pnpm statistical:practrand

For a release-scale run:

PRACTRAND_ALGORITHM=xoshiro256++ \
PRACTRAND_WORDS=268435456 \
PRACTRAND_SEEDS=run-a,run-b,run-c \
PRACTRAND_REPORT=reports/tests/practrand.json \
pnpm statistical:practrand

TestU01 and Other External Batteries

Install and build the battery separately, then generate a reproducible binary stream for the adapter or harness you use with it:

pnpm stream philox4x32-10 ./philox.bin 1000000000 test-seed

Exact backend parity means one algorithm stream can receive the expensive statistical battery while every backend receives parity tests.

Benchmarking

This library includes benchmarks to compare the performance of each algorithm on your hardware. The benchmarks measure generator speed, setup costs, memory allocation patterns, backend initialisation, and end-to-end workload behaviour with the JavaScript, WASM, worker-based, and WebGPU backends, where supported.

Benchmark Process

Running pnpm benchmark builds the package and then runs the main Node benchmark harness. The benchmark results can be used to understand:

  • Which backend is best for single values or bulk workloads
  • How allocation overhead changes with array size
  • Whether backend initialisation dominates short-lived workloads
  • How WebGPU behaves when output must be copied back to the CPU

All benchmarks run adaptively for a minimum duration of 250ms (by default). The reported values are the median and interquartile range, with raw sample rates being saved in the /reports/benchmarks/ folder.

Running the Benchmarks

There are several benchmarks you can run to understand performance with different configurations:

  • pnpm benchmark measures the generator performance on CPU using javascript and wasm
  • pnpm benchmark:scenarios measures the performance in realistic situations by determining the value of π through a Monte Carlo simulation
  • pnpm benchmark:workers measures the cost and scaling of a consistent workload across various numbers of node worker threads
  • pnpm benchmark:web-workers measures the cost and scaling of a consistent workload across various numbers of web worker threads
  • pnpm benchmark:webgpu is the dedicated browser-backed WebGPU comparison.
  • pnpm benchmark:all runs all aforementioned benchmarks

Benchmark Parameters

Several benchmark parameters can be set, as shown below:

BENCH_MIN_SAMPLE_MS=500 \
BENCH_SAMPLES=15 \
pnpm benchmark

The full list of available benchmark parameters are listed below:

| Parameter | Description | Scope | Default | | :--- | :--- | :--- | :--- | | BENCH_JSON | Sets the output file for the raw report | benchmark | reports/benchmarks/main.json | | BENCH_MIN_SAMPLE_MS | How long each sample runs in milliseconds | all | 250 | | BENCH_SIZES | The array lengths tested | all | 1,64,1024,16384,262144,1048576 | | BENCH_SAMPLES | How many samples are collected | all | 10 | | BENCH_WORKERS | Number of workers to use in each simulation | workers, web-workers | 1, 2, 4, 8 | | BENCH_WORKER_NUMBERS | Total number of samples to run for each simulation | workers, web-workers | 20_000_000 | | BENCH_WEB_WORKER_JSON | Sets output file for the raw report | web-worker | reports/benchmarks/web-workers.json | BENCH_WEB_WORKER_CHANNEL | Sets the chromium executable used by Playwright | web-worker | chromium | | BENCH_WEB_WORKER_HEADED | Sets whether benchmark is run headed | web-worker | 0 | | BENCH_WORKER_JSON | Sets the output file for the raw report | workers | reports/benchmarks/workers.json | | BENCH_SCENARIO_JSON | Sets the output file for the raw report | scenario | reports/benchmarks/scenarios.json | | BENCH_WEBGPU_JSON | Sets output file for the raw report | webgpu | reports/benchmarks/webgpu.json

WebGPU Specifics

Node cannot assume a GPU-backed navigator.gpu, so this benchmark launches Chromium and runs an isolated WebGPU workload there.

For a quick hardware check, run the smoke test:

pnpm benchmark:webgpu:smoke

If headless Chromium cannot access the GPU for webgpu tests, retry with:

BENCH_WEBGPU_HEADED=1 pnpm benchmark:webgpu

The benchmark rejects software fallbacks such as SwiftShader and llvmpipe by default. Set BENCH_WEBGPU_ALLOW_FALLBACK=1 when you intentionally want to measure software WebGPU.

Benchmark Regression Comparison

To compare two benchmark runs and check for regressions, generate separate JSON files for each benchmark:

BENCH_JSON=reports/benchmarks/baseline.json pnpm benchmark
BENCH_JSON=reports/benchmarks/candidate.json pnpm benchmark

A regression can then be run using pnpm benchmark:compare, optionally setting a regression threshold:

BENCH_REGRESSION_PERCENT=10 \
  pnpm benchmark:compare \
    reports/benchmarks/baseline.json \
    reports/benchmarks/candidate.json

If the performance percentage change for any of the benchmarks exceeds the threshold, benchmark:compare will exit with a non-zero return value.

Development

Setup

The build requires:

  • Node.js 20 or newer.
  • The pnpm version declared by packageManager in package.json.
  • rustup, which manages the Rust compiler and WebAssembly compilation target. No previous Rust experience or separate Cargo installation is required.

After cloning the repository, run:

pnpm run bootstrap

This command verifies Node and pnpm, installs the Rust toolchain, profile, and targets declared by rust-toolchain.toml, installs pnpm dependencies, and builds the library.

If rustup is not installed, pnpm run bootstrap stops with an installation link rather than failing later in the build. Restart the terminal after installing rustup so its commands are available on PATH.

For browser tests and browser-backed benchmarks, install Playwright's browsers separately because they are a large optional download:

pnpm run setup:browsers

Verification

Run the complete non-browser verification suite and browser tests with:

pnpm check
pnpm test:browser
pnpm benchmark:smoke

License

This project is licensed under the MIT License - see the LICENSE file for details. The published bundles also contain third-party software. Its attribution and license terms are recorded in THIRD_PARTY_NOTICES.md, and the machine-readable component inventory is published as sbom.cdx.json.

What this Means

You are free to:

  • Use this plugin for personal or commercial purposes
  • Modify and distribute the code
  • Include it in other projects

Under the following conditions:

  • You must include the original license and copyright notice

Disclaimer

This plugin is provided "as is", without warranty of any kind. Use at your own risk.