Random
Seeded random-number generators. Each generator holds its own stream, so any number of independent, reproducible sequences run side by side, and none of them draws from or reseeds math.random.
A generator made from a seed produces the same sequence on every
platform and every build: the same seed gives the same numbers on a
native engine and in the browser, run after run.
local rng = Random.new(1234) -- the same seed, the same stream
local roll = rng:nextInteger(1, 6) -- integer in [1, 6], both ends included
local t = rng:nextNumber() -- float in [0, 1)
local x = rng:nextNumber(-5, 5) -- float in [-5, 5)
Members every generator answers:
rng:nextNumber() float in [0, 1), 53 random bits
rng:nextNumber(min, max) float in [min, max)
rng:nextInteger(min, max) integer in [min, max], both ends included,
every value equally likely
rng:clone() an independent generator at the same position:
it draws what this one would draw next
rng:state() the position as a 32-character hex string a
save, a record or a network message can hold
Random.fromState(rng:state()) makes a generator that continues the
sequence from where rng stood, so a saved level, a replayed AI
decision or a regenerated design picks up exactly where it left off.
Random.new() with no seed takes its seed from the clock.
math.random is a different thing: one stream per Luau VM, shared by
every script in that VM and reseeded for all of them by
math.randomseed. A generator here is a value of its own; drawing from
one moves no other.
The algorithm is xoshiro128** (Blackman and Vigna) over 32-bit words.
A seed is read as the bits of its IEEE-754 double: the low word and the
high word each go through the MurmurHash3 32-bit finalizer to give the
first two state words, and the last two are mixed from those, so every
distinct number is a distinct stream. nextNumber() joins the top 27
bits of one output and the top 26 of the next into a 53-bit fraction;
nextInteger rejects the draws that would bias the range.
require("@builtin::modules.random") -- Random (also available as global 'Random')
The Random namespace: 4 functions.
globals/Random/fromState
Random.fromState(state: string) -> RandomGenerator
Make a generator that continues a sequence from a position
rng:state() recorded. It draws exactly what the recorded generator
drew next, so a save holds the string and a load picks the stream up.
Parameters
statestring— The 32-character hex stringrng:state()returned.
Returns RandomGenerator — A generator at that position.
local resumed = Random.fromState(Random.new(7):state())
globals/Random/new
Random.new(seed: number?) -> RandomGenerator
Make a generator with its own stream. The same seed gives the same
sequence on every platform and build; any number of generators run side
by side without moving one another or math.random. With no seed it
takes one from the clock, and rng:state() records where it stands.
Parameters
seednumber(optional) — Any finite number; every distinct number is a distinct stream. Omitted, the clock seeds it.
Returns RandomGenerator — A generator answering :nextNumber(), :nextNumber(min, max), :nextInteger(min, max), :clone() and :state().
local roll = Random.new(42):nextInteger(1, 6)
local jitter = Random.new(42):nextNumber(-0.5, 0.5)
local clockSeeded = Random.new()
modules/Random/fromState
fromState(state: string): RandomGenerator
Make a generator that continues a sequence from a position
rng:state() recorded. It draws exactly what the recorded generator
drew next, so a save holds the string and a load picks the stream up.
Parameters
statestring— The 32-character hex stringrng:state()returned.
local resumed = Random.fromState(Random.new(7):state())
modules/Random/new
new(seed: number?): RandomGenerator
Make a generator with its own stream. The same seed gives the same
sequence on every platform and build; any number of generators run side
by side without moving one another or math.random. With no seed it
takes one from the clock, and rng:state() records where it stands.
Parameters
seednumber?(optional) — Any finite number; every distinct number is a distinct stream. Omitted, the clock seeds it.
local roll = Random.new(42):nextInteger(1, 6)
local jitter = Random.new(42):nextNumber(-0.5, 0.5)
local clockSeeded = Random.new()