BLIT386BLIT386

Random

Seeded Random PRNG, coordinate hashes, and Value/Perlin/Simplex pattern noise for procedural worlds.

Seeded, deterministic pseudo-random numbers for demos and games. The Random class uses a mulberry32 core so the same seed always produces the same sequence across platforms. Stateless hash1i / hash2i / hash3i (and float forms) give per-coordinate randomness for chunked worlds without storing an RNG per cell. ValueNoise, PerlinNoise, and SimplexNoise add smooth pattern-based fields for terrain, clouds, and organic motion.

Random Since 1.5.0
import {  } from 'blit386';

const  = new (1234);

.(); // [0, 1)
.(0, 10); // [0, 10)
.(6); // [0, 6)
.(10, 20); // [10, 20)
.(1, 6); // [1, 6]
.(0.25); // true ~25% of the time
.(); // -1 or 1
.(['a', 'b', 'c']);
.([1, 2, 3, 4]);
.(); // [0, 2π) radians
.(0, 1); // Box-Muller sample
.(); // cardinal unit vector

Omit the constructor seed to time-seed from Date.now() (lower 32 bits). Call seed(n) later to restart from a known value.

Engine default (BT.random)

BT.random Since 1.5.0 BT.randomSeed Since 1.5.0

The engine keeps one shared Random instance on the BT facade. BT.random is a live reference (same instance across reads, like BT.palette). It is time-seeded when the engine singleton is created; call BT.randomSeed(seed) to make a run reproducible.

import {  } from 'blit386';

.(42);
..(150, 420);
..(['glitch', 'noise', 'static']);
..(0.3, 0.95);

Prefer BT.random for demo and game code. Construct a separate new Random(seed) when you need an independent stream (for example a local procedural subsystem that should not advance the shared engine RNG).

Generators

MethodRange / behavior
next()Float in [0, 1)
float(min, max)Float in [min, max)
int(maxExclusive)Integer in [0, maxExclusive)
int(min, maxExclusive)Integer in [min, maxExclusive)
intInclusive(min, max)Integer in [min, max]
bool(probability?)true with the given chance (default 0.5)
sign()-1 or 1
pick(arr)One element from a non-empty array
shuffle(arr)New shuffled copy (Fisher-Yates)
shuffleInPlace(arr)Shuffle the array in place and return it
weighted(items, weights)One item by relative non-negative weights
angle()Float in [0, 2π) radians
gaussian(mean?, stddev?)Approximate normal sample (Box-Muller, no spare)
insideRect(rect)Integer point in half-open rect
insideRectTo(rect, out)Same as insideRect, writes into out
pointInRange(min, max)Integer point; per-axis [min, max)
pointInRangeTo(min, max, out)Same as pointInRange, writes into out
direction4()One of four cardinal unit vectors (Y-down)
direction8()One of eight king-move unit vectors (Y-down)

Integer helpers return true integers (| 0 truncation), matching the engine's Vector2i philosophy. Half-open int ranges match the demo helpers (randInt / randFloat).

Spatial helpers

insideRect / insideRectTo sample the same half-open region as Rect2i.isContaining: x in [rect.x, rect.right), y in [rect.y, rect.bottom). pointInRange / pointInRangeTo use int per axis ([min.x, max.x) and [min.y, max.y)). Empty or inverted ranges throw the same RangeError as int. Prefer the *To(out) variants in update() / render() loops to avoid per-frame allocation.

import { , ,  } from 'blit386';

const  = new (7);
const  = new (0, 0, 320, 240);
const  = new ();

.();
.(, );
.(new (10, 10), new (20, 30));
.(); // (1,0) | (-1,0) | (0,1) | (0,-1)
.(); // cardinals plus diagonals

Coordinate hashing

Stateless spatial lookups for chunked and procedural worlds. Same coordinates and seed always return the same value - no stored RNG state, so you do not need an instance per chunk. Complements Random (a sequence generator).

hash1i Since 1.5.0 hash2i Since 1.5.0 hash3i Since 1.5.0 hash1 Since 1.5.0 hash2 Since 1.5.0 hash3 Since 1.5.0
FunctionRange
hash1i(x, seed?)Unsigned 32-bit in [0, 2^32)
hash2i(x, y, seed?)Unsigned 32-bit in [0, 2^32)
hash3i(x, y, z, seed?)Unsigned 32-bit in [0, 2^32)
hash1(x, seed?)Float in [0, 1)
hash2(x, y, seed?)Float in [0, 1)
hash3(x, y, z, seed?)Float in [0, 1)

Coordinates are truncated toward zero with | 0. Omit seed (or pass 0) for a fixed default world seed. Float forms are the matching hashNi value scaled by 1 / 2^32.

import { ,  } from 'blit386';

const  = (12, -3, 9001); // uint32, same every call
const  = (12, -3, 9001); // [0, 1)
const  =  < 0.15;

Pattern noise

Smooth, seedable spatial noise for terrain, clouds, organic motion, and procedural textures. Lattice corners use the coordinate hashes above. Every sample is in approximately [-1, 1] (the same signed range as trig helpers). These classes are distinct from the post-process Noise display effect (GPU grain).

ValueNoise Since 1.5.0 PerlinNoise Since 1.5.0 SimplexNoise Since 1.5.0
ClassMethods
ValueNoisenoise1D / noise2D / noise3D, fbm1D / fbm2D / fbm3D
PerlinNoiseSame surface as ValueNoise (gradient Perlin)
SimplexNoisenoise2D / noise3D, fbm2D / fbm3D (no 1D)

Omit the constructor seed (or pass 0) for a fixed default world seed - same convention as hash2i. Call seed(n) to switch fields. fBm defaults: octaves = 4, persistence = 0.5, lacunarity = 2. Octave amplitudes are normalized so fBm stays in approximately [-1, 1].

import { , ,  } from 'blit386';

const  = new (9001);
const  = new (9001);
const  = new (9001);

.(12.5, -3.25); // [-1, 1]
.(0.1, 0.2); // multi-octave, still ~[-1, 1]
.(1, 2, 3);

Value noise interpolates hashed corner values (smooth but can look blocky at low frequency). Perlin uses lattice gradients (Ken Perlin, SIGGRAPH 2002). Simplex reduces directional artifacts on square grids (Stefan Gustavson).

State and streams

import {  } from 'blit386';

const  = new (99);
.();
.();

const  = .();
const  = .(); // same stream from this point
const  = .(); // independent sub-stream; advances `rng` once

.(); // restore and replay
MethodBehavior
seed(n)Reseed; same n restarts the same sequence
getState()Current unsigned 32-bit state
setState(n)Restore a saved state
clone()New instance with identical state (identical subsequent draws)
fork()Advance this instance once; seed a child so the two streams diverge
seedValueLast seed passed to the constructor or seed(); undefined after setState(), or on a forked child

seedValue reads back the seed itself, not the current position in the sequence - the value getState() returns keeps changing as you draw, but seedValue stays put until the generator is genuinely reseeded. It is normalized to an unsigned 32-bit value, the same representation getState() uses, not necessarily the raw number passed in. setState() clears it, since jumping to an arbitrary saved state does not correspond to any known seed. clone() copies it verbatim (including undefined), matching the identical stream a clone produces. fork()'s child always reports undefined - a fork is a new stream and should not claim a seed its caller never chose.

API history

SymbolSinceLast changedStatus
BT.random1.5.0stable
BT.randomSeed1.5.0stable
hash11.5.0stable
hash1i1.5.0stable
hash21.5.0stable
hash2i1.5.0stable
hash31.5.0stable
hash3i1.5.0stable
PerlinNoise1.5.0stable
Random1.5.0stable
SimplexNoise1.5.0stable
ValueNoise1.5.0stable

1.5.0 - Tue Aug 11 2026

  • AddedBT.random
  • AddedBT.randomSeed
  • AddedPerlinNoise
  • AddedRandom
  • AddedSimplexNoise
  • AddedValueNoise
  • Addedhash1
  • Addedhash1i
  • Addedhash2
  • Addedhash2i
  • Addedhash3
  • Addedhash3i

See also

Last updated on September 9, 2026

On this page