use-rng
v0.1.25
Published
A deterministic random number generator library with React hook and standalone implementations
Downloads
7
Maintainers
Readme
use-rng
A deterministic random number generator library with both React hook and standalone implementations. Built with TypeScript and powered by cryptographically secure SHA-512 hashing.
Features
- Deterministic - Same seed always produces same results
- Cryptographically Secure - Uses SHA-512 for seed hashing
- React Hook - Easy integration with React applications
- Standalone - Works in any JavaScript environment
- TypeScript - Full type safety and IntelliSense support
- Flexible - Custom ranges, precision control, and seed management
- Well Tested - 90+ comprehensive tests
Installation
npm install use-rng
# or
yarn add use-rng
# or
bun add use-rngQuick Start
React Hook
import { useRNG } from "use-rng";
function DiceRoller() {
const { result, nonce, rollDice, generateSeeds, getCurrentSeedPair } =
useRNG();
const handleRoll = async () => {
await rollDice({
seed: getCurrentSeedPair(),
range: [1, 6], // Roll a 6-sided die
});
};
return (
<div>
<button onClick={generateSeeds}>Generate New Seeds</button>
<button onClick={handleRoll}>Roll Dice</button>
<p>Result: {result}</p>
<p>Roll #{nonce}</p>
</div>
);
}Standalone Library
import { RNGManager } from "use-rng/standalone";
// Create an RNG instance
const rng = new RNGManager();
// Roll a 6-sided die
const diceRoll = await rng.roll(1, 6, 0); // min, max, decimalPlaces
console.log(`Rolled: ${diceRoll}`);
// Generate percentage with 2 decimal places
const percentage = await rng.roll(0, 100, 2);
console.log(`Percentage: ${percentage}%`);
// Peek at next value without incrementing nonce
const nextValue = await rng.peek(0, 100);
console.log(`Next value would be: ${nextValue}`);API Reference
React Hook: useRNG()
Returns an object with the following properties and methods:
State
clientSeed: string- Current client seedserverSeed: string- Current server seednonce: number- Current nonce (increments with each roll)result: number | null- Last generated random numberseedPairNumber: number | null- Last seed pair result
Methods
generateSeeds()- Generate new random seeds and reset noncerollDice(params)- Generate random number and increment noncesetSeedPair()- Generate number from current seed pairgetCurrentSeedPair()- Get current seed pair objectsetClientSeed(seed)- Manually set client seedsetServerSeed(seed)- Manually set server seedsetNonce(nonce)- Manually set nonce
rollDice Parameters
interface RandomWithPrecise {
seed: SeedPair;
range?: [number, number]; // [min, max], defaults to [0, 99.99]
}Standalone: RNGManager
Constructor
new RNGManager(clientSeed?, serverSeed?, nonce?)Methods
roll(min?, max?, decimalPlaces?)- Generate random number and increment noncepeek(min?, max?, decimalPlaces?)- Generate random number without incrementing noncegenerateSeeds()- Generate new random seeds and reset noncegetSeedPair()- Get current seed pairsetSeeds(clientSeed, serverSeed, nonce?)- Set seeds manuallyincrementNonce()- Increment nonce by 1resetNonce()- Reset nonce to 0
Direct Functions
import {
getRandomSeedPair,
getRandomWithPrecision,
getRandomInRange,
} from "use-rng/standalone";
const seedPair = {
clientSeed: "client-seed",
serverSeed: "server-seed",
nonce: 0,
};
// Generate random number between 0-1
const random = await getRandomSeedPair(seedPair);
// Generate with custom range and precision
const customRandom = await getRandomWithPrecision(seedPair, 10, 20, 2);Use Cases
Gaming
const rng = new RNGManager("player123", "game456", 1);
// Dice rolls
const d6 = await rng.roll(1, 6, 0);
const d20 = await rng.roll(1, 20, 0);
// Damage calculation
const damage = await rng.roll(10, 50, 1);Lottery/Random Selection
const rng = new RNGManager();
const lotteryNumbers = [];
// Generate 6 unique numbers between 1-49
const usedNumbers = new Set();
while (lotteryNumbers.length < 6) {
const number = await rng.roll(1, 49, 0);
if (!usedNumbers.has(number)) {
lotteryNumbers.push(number);
usedNumbers.add(number);
}
}A/B Testing
const rng = new RNGManager(userId, experimentId, 0);
const assignment = await rng.roll(0, 100, 2);
const variant = assignment < 50 ? "A" : "B";Reproducible Simulations
// Same seeds = same results every time
const rng1 = new RNGManager("seed1", "seed2", 0);
const rng2 = new RNGManager("seed1", "seed2", 0);
const sequence1 = [];
const sequence2 = [];
for (let i = 0; i < 10; i++) {
sequence1.push(await rng1.roll());
sequence2.push(await rng2.roll());
}
// sequence1 === sequence2 ✅How It Works
The library uses a deterministic approach based on cryptographic hashing:
- Seed Combination: Client seed + Server seed + Nonce are combined into a single string
- Hashing: The string is hashed using SHA-512
- Normalization: Hash bytes are converted to a normalized float (0-1)
- Scaling: The float is scaled to your desired range with precision control
This ensures that:
- Same inputs always produce same outputs (deterministic)
- Results are cryptographically unpredictable without knowing the seeds
- Sequence can be reproduced or verified independently
TypeScript Support
Full TypeScript support with comprehensive type definitions:
import { SeedPair, RandomWithPrecise } from "use-rng";
const seedPair: SeedPair = {
clientSeed: "client",
serverSeed: "server",
nonce: 0,
};
const params: RandomWithPrecise = {
seed: seedPair,
range: [1, 100],
};Potential Improvements for v1.0
- Performance optimizations for bulk generation
- Web Workers support for heavy computations
- Streaming API for continuous random generation
- More hash algorithms (SHA-256, Blake3)
- React Native compatibility
- Deno/Bun runtime optimizations
Long-term Roadmap
- Plugin system for custom distributions
- Statistical analysis tools
- Visualization components
- CLI tool for testing/validation
- Browser extension for developers
Testing
This library has comprehensive test coverage with 90 tests across multiple categories:
Test Categories
- Core RNG Functions (27 tests) - Hash generation, byte conversion, seed processing
- Standalone Library (30 tests) - RNGManager class, edge cases, deterministic behavior
- React Hook (22 tests) - State management, lifecycle, async operations
- Integration Tests (11 tests) - Cross-implementation consistency, real-world scenarios
Test Coverage Areas
- ✅ Deterministic behavior - Same seeds produce identical sequences
- ✅ Edge cases - Empty strings, unicode, negative numbers, large values
- ✅ Performance - Bulk generation (1000+ numbers), concurrent operations
- ✅ Cryptographic properties - Unpredictability, distribution quality
- ✅ Real-world scenarios - Gaming, lottery, A/B testing, simulations
- ✅ Error handling - Invalid inputs, boundary conditions
- ✅ React integration - Hook lifecycle, state updates, async operations
Running Tests
# Run all tests
bun test
# Watch mode for development
bun test --watch
# Coverage report (if configured)
bun test --coverageBundle Size
The library is optimized for minimal bundle impact:
- Main entry: ~4KB (minified + gzipped)
- Standalone entry: ~4KB (minified + gzipped)
- Zero dependencies (React is peer dependency)
- Tree-shakeable - Import only what you need
Browser Compatibility
- Modern browsers with Web Crypto API support
- Node.js 16+
- React 16.8+ (for hook usage)
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT © [phtn]
Development
# Install dependencies
bun install
# Run tests
bun test
# Build library
bun run build
# Development mode
bun run devThis project was created using bun init and is built with Bun.
