---
title: "Random"
description: "Seeded random-number generators."
section: "API Reference"
slug: "api-random"
canonical: "https://origozero.ai/docs/api-random"
updated: "2026-10-20T13:15:36.899659711+00:00"
tags: ["api", "reference"]
---

# 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.

```lua
require("@builtin::modules.random") -- Random (also available as global 'Random')
```

The `Random` namespace: 4 functions.

## globals/Random/fromState {#globals-random-fromstate}

```lua
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**

- `state` `string` — The 32-character hex string `rng:state()` returned.

**Returns** `RandomGenerator` — A generator at that position.

```lua
local resumed = Random.fromState(Random.new(7):state())
```

## globals/Random/new {#globals-random-new}

```lua
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**

- `seed` `number` _(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()`.

```lua
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 {#modules-random-fromstate}

```lua
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**

- `state` `string` — The 32-character hex string `rng:state()` returned.

```lua
local resumed = Random.fromState(Random.new(7):state())
```

## modules/Random/new {#modules-random-new}

```lua
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**

- `seed` `number?` _(optional)_ — Any finite number; every distinct number is a distinct stream. Omitted, the clock seeds it.

```lua
local roll = Random.new(42):nextInteger(1, 6)
local jitter = Random.new(42):nextNumber(-0.5, 0.5)
local clockSeeded = Random.new()
```
