# Randomly — complete documentation

> A library of 63 random generators — numbers, words, equations, patterns, images and sound — seeded from 10 real-world entropy sources, with a free, keyless HTTP API. Every result carries a receipt naming the physical source of its randomness and linking to third-party proof, and every result replays bit-for-bit from its own URL.

This file is generated from the live registry: every generator, parameter, bound and
default below is read from the same declaration the running site and the API use, so it
cannot drift from the code. Shorter versions: [`/llms.txt`](https://randomly.cluxnei.dev/llms.txt) (index)
and [`/api.md`](https://randomly.cluxnei.dev/api.md) (the contract alone).

## What this is

Most random tools call `rand()` and move on. Randomly makes the *source* of the
randomness the product. A draw might come from vacuum field fluctuations measured by
homodyne detection in Canberra, from atmospheric radio noise sampled in Dublin, from the
NIST beacon's minute pulse, from the block hash the Bitcoin network spent ten minutes
finding, or from an earthquake the USGS recorded forty minutes ago — and the receipt says
which, in a sentence a person can read, with a link to the third party's own record of it.

Four structural facts a client should know before calling anything:

1. **No database, no accounts.** A result's token is 16 bytes in 26 Crockford base32
   characters, and that token *is* the seed. A permalink recomputes the result rather
   than looking it up. Nothing is stored, so nothing can be retrieved.
2. **One contract.** A generator declares a parameter schema, and the studio's controls,
   the API's validation, the catalogue entry and the permalink format all render from
   that one declaration. `/api/v1/generators` is that declaration, machine-readable.
3. **Specs, not pixels.** Canvas and audio generators return a *description* — algorithm,
   parameters, palette, render key — which the browser turns into pixels or samples from
   the same byte stream. An API caller who wants the artefact asks for `format=png` or
   `format=wav` and gets it, rendered by running the browser's own JavaScript under Node.
4. **Honest failure.** A replay against a changed generator returns `409` rather than
   quietly returning something different. A format a generator cannot produce returns
   `406` naming the ones it can, rather than a silent JSON fallback.

## Where the randomness comes from

All 10 of them are free, keyless and credited — and classified honestly,
because an earthquake is a wonderful story and a poor cipher.

| Key | Source | Class | Refresh | What it physically is |
|---|---|---|---|---|
| `csprng` | Operating System CSPRNG | A | on demand | The kernel entropy pool — interrupt timings, device jitter and, on this machine, the CPU hardware RNG. |
| `anu-qrng` | ANU Quantum Vacuum | A | on demand | Fluctuations of the quantum vacuum field, measured by homodyne detection at the Australian National University. |
| `random-org` | RANDOM.ORG | A | on demand | Atmospheric radio noise, largely driven by lightning discharges, captured by receivers in Dublin. |
| `nist-beacon` | NIST Randomness Beacon | B | 60s | A hardware entropy source at the US National Institute of Standards and Technology, hash-chained and signed every minute. |
| `drand` | drand · League of Entropy | B | 3s | A threshold BLS signature jointly produced every three seconds by independent operators across several continents. |
| `bitcoin` | Bitcoin Proof-of-Work | B | 60s | The block header hash the entire Bitcoin network spent roughly ten minutes of global hashrate searching for. |
| `seismic` | USGS Seismic Feed | C | 60s | Every earthquake above the detection threshold recorded anywhere on Earth in the past hour, published by the US Geological Survey. |
| `space-weather` | NOAA Space Weather | C | 60s | The planetary K-index — how much the solar wind is currently disturbing Earth's magnetic field, measured by NOAA. |
| `atmosphere` | Live Weather | C | 300s | Temperature, wind and pressure read from a weather station somewhere on Earth, chosen at random for each draw. |
| `iss` | ISS Position | C | 5s | The ground track of the International Space Station, 408 km up and moving at 27,600 km/h. |

**Class A — Cryptographic.** `csprng`, `anu-qrng`, `random-org`. Full-entropy, unpredictable bytes; safe to stand alone.

**Class B — Public beacon.** `nist-beacon`, `drand`, `bitcoin`. Published openly — anyone can look this value up after the fact.

**Class C — Observational.** `seismic`, `space-weather`, `atmosphere`, `iss`. Carries only tens of bits of genuine surprise. Always mixed with the OS CSPRNG.

**The mixing rule.** Class B and Class C material is *always* combined with fresh OS
CSPRNG bytes, a nanosecond clock reading and a monotonic counter before HKDF-SHA256
conditions it into a 16-byte seed. So the exotic source genuinely contributes and can be
pointed at, and the result is unpredictable regardless. `receipt.mixed_with_csprng` states
which happened. **If you need a secret, ask for Class A** — or do not use a public HTTP
API for it at all.

**Degradation.** Every external source has a short timeout and a circuit breaker. When
one is unreachable the kernel CSPRNG answers instead and the receipt is marked
`"degraded": true` with the substitution spelled out in the narrative. The request does
not fail; the receipt does not lie about what happened.

**No entropy at all, sometimes.** A generator that is a pure function of its input — an
identicon is the same avatar for the same string, forever, which is the entire point of an
identicon — skips the entropy draw rather than crediting a beacon that changed nothing
about the output. `uses_entropy` in the catalogue says which those are.

## The API

### Base URL

```
https://randomly.cluxnei.dev/api/v1
```

No authentication, no key, no signup, no account — matching every source this project
draws from. The site's own pages call these same endpoints; there is no private path
with different behaviour.

**Rate limits, per IP.** 60 requests a minute overall, of which at most
20 may be PNG or WAV renders. A render starts a Node process and costs
a hundred times what a JSON response costs, so it is charged against *both* buckets. A
`429` carries `retry_after_seconds` and both limits, because the caller is usually a
script or a model rather than a person reading a page. The count is per server, not
distributed — this is a showcase, and claiming otherwise would be the kind of
overstatement the rest of the project exists to avoid.

### The one-liner

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.integers?count=6&min=1&max=60&unique=1' -H 'Accept: text/plain'
# 20, 22, 26, 35, 47, 51
```

### Endpoints

| Method | Path | Returns |
|---|---|---|
| `GET` | `/api/v1/generators` | the whole catalogue with every generator's declared parameters |
| `GET` | `/api/v1/sources` | the 10 entropy sources, their class and live status |
| `GET` | `/api/v1/g/{key}?…` | generate — the shorthand, for one-liners |
| `POST` | `/api/v1/generate` | generate — `{"generator", "params", "source"}` as JSON |
| `GET` | `/api/v1/replay/{token}?g=&v=` | recompute a past result exactly |

### Discover before you call

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/generators'
```

Every entry carries `key`, `name`, `tagline`, `module`, `renderer`, `version`, the
`formats` it can be served as, the three behaviour flags below, and `params` — each with
its `type`, `default`, and `min`/`max` or `options`. **Read `params` rather than
guessing.** Numbers outside their bounds are clamped rather than rejected, so a request
always succeeds, but it may not do what you meant.

Three flags decide what a client may do with a generator:

| Flag | What it tells a caller |
|---|---|
| `sensitive` | `true` for a generator that produces secrets — a password, a passphrase, an identifier. It is given **no token and no permalink**, and `/api/v1/replay` returns `404`. A secret with a replayable URL is not a secret. |
| `reproducible` | `true` means a permalink recomputes the result exactly. `false` for a generator built on live external material that moves, so no permalink is issued — a link that quietly stops working is worse than no link. |
| `uses_entropy` | `true` for almost everything. `false` for a pure function of its input (an identicon): no source is consulted, nothing is spent waiting on a beacon, and the receipt says so rather than crediting a source that changed nothing. |

### Generating

```bash
# GET shorthand
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.dice?notation=4d6kh3&rolls=6'

# POST, for long parameter sets
curl -s -X POST 'https://randomly.cluxnei.dev/api/v1/generate' \
     -H 'Content-Type: application/json' \
     -d '{"generator":"numbers.integers","params":{"count":6,"min":1,"max":60,"unique":true},"source":"drand"}'
```

The JSON envelope is the same for every generator:

| Field | Type | What it is |
|---|---|---|
| `value` | varies | the structured result — a list of numbers, a string, a render spec |
| `display` | string | the human-readable form, and the entire body of a `text/plain` response |
| `meta` | object | instrumentation: `entropy_out_bits`, `rejections`, `duration_us`, and whatever else the generator measured |
| `receipt` | object | where the randomness came from — see below |
| `seed.token` | string\|null | 26 Crockford base32 characters. This **is** the seed. `null` for a sensitive generator. |
| `seed.permalink` | string\|null | a URL that recomputes this exact result |

### The receipt

The receipt is the product. Every generated result carries one:

| Field | What it is |
|---|---|
| `source` / `source_label` | which of the 10 sources answered |
| `class` | `A` cryptographic, `B` public beacon, `C` observational |
| `caveat` | the honest limitation of that class, in words, or `null` for Class A |
| `narrative` | one sentence a human can read: the earthquake, the pulse index, the block |
| `proof_url` | a link to the third party's own record of it, so the claim is checkable |
| `reference` | that source's own identifier — a pulse index, a drand round, a block hash |
| `observed_at` | when the material was observed, ISO 8601 |
| `mixed_with_csprng` | `true` whenever a Class B or C source was folded in with fresh local entropy |
| `degraded` | `true` if the requested source was unreachable and the kernel answered instead |

### Choosing an entropy source

`?source=` takes any key below, or `auto` (the default).

| Key | Source | Class | What it physically is |
|---|---|---|---|
| `csprng` | Operating System CSPRNG | A | The kernel entropy pool — interrupt timings, device jitter and, on this machine, the CPU hardware RNG. |
| `anu-qrng` | ANU Quantum Vacuum | A | Fluctuations of the quantum vacuum field, measured by homodyne detection at the Australian National University. |
| `random-org` | RANDOM.ORG | A | Atmospheric radio noise, largely driven by lightning discharges, captured by receivers in Dublin. |
| `nist-beacon` | NIST Randomness Beacon | B | A hardware entropy source at the US National Institute of Standards and Technology, hash-chained and signed every minute. |
| `drand` | drand · League of Entropy | B | A threshold BLS signature jointly produced every three seconds by independent operators across several continents. |
| `bitcoin` | Bitcoin Proof-of-Work | B | The block header hash the entire Bitcoin network spent roughly ten minutes of global hashrate searching for. |
| `seismic` | USGS Seismic Feed | C | Every earthquake above the detection threshold recorded anywhere on Earth in the past hour, published by the US Geological Survey. |
| `space-weather` | NOAA Space Weather | C | The planetary K-index — how much the solar wind is currently disturbing Earth's magnetic field, measured by NOAA. |
| `atmosphere` | Live Weather | C | Temperature, wind and pressure read from a weather station somewhere on Earth, chosen at random for each draw. |
| `iss` | ISS Position | C | The ground track of the International Space Station, 408 km up and moving at 27,600 km/h. |

**Class A** stands alone. **Class B** is unpredictable until published and public forever
after. **Class C** is flavour — an earthquake carries tens of bits of genuine surprise,
not the kilobytes its JSON weighs. Class B and C are therefore *always* mixed with fresh
CSPRNG bytes before anything is generated, and the receipt says so. **If you need a
secret, ask for Class A or do not use this API at all.**

An unreachable source degrades to the kernel rather than failing the request; check
`receipt.degraded`.

### Output formats

| `Accept:` / `?format=` | Returns | Available on |
|---|---|---|
| `application/json` (default) | the envelope above | every generator |
| `text/plain` | just `display` | every generator |
| `image/png` | the rendered image | the 24 canvas generators |
| `audio/wav` | 16-bit PCM, 44.1 kHz | the 8 audio generators |

```bash
curl -o noise.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.perlin?variant=ridged&palette=viridis&format=png'
curl -o beat.wav  'https://randomly.cluxnei.dev/api/v1/g/audio.rhythm?format=wav'
```

Canvas and audio generators return a **render spec** as JSON by default — the algorithm,
its parameters, the palette and a render key — rather than pixels or samples, because the
browser re-derives them from the same byte stream. That keeps a four-minute generative
piece a 2 KB response. An API caller who wants the artefact asks for `format=png` or
`format=wav`; those are rendered by running the same JavaScript the browser runs, under
Node, so the file matches what the studio draws.

Asking for a format a generator cannot produce returns **`406`** naming the ones it can,
never a silent JSON fallback. `formats` in the catalogue tells you in advance.

### Reproducing a result

There is no database. The token **is** the seed, so a permalink recomputes rather than
looks up:

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/replay/{token}?g=numbers.integers&v=1&p={base64url-params}'
```

`g` (generator key) and `v` (version) are required; `p` defaults to the generator's
defaults. `s` and `r` optionally carry the original source key and its reference, from
which the receipt is rebuilt and marked `reconstructed` — because inventing a fresh
receipt for an old result and presenting it as the original is exactly the lie this
project exists not to tell.

The response is identical to a generation, plus `"replayed": true`.

### Errors

| Status | `error` | Meaning |
|---|---|---|
| `400` | `invalid_params` | a parameter failed the generator's own schema; `fields` names it |
| `400` | `invalid_token` | the token is not 26 valid Crockford base32 characters |
| `404` | `unknown_generator` | not in the catalogue; `available` lists every key that is |
| `404` | `not_replayable` | that generator is `sensitive`, so it never had a replayable link |
| `406` | `unsupported_format` | no such representation; `available` lists the ones there are |
| `409` | `version_changed` | the generator's algorithm changed, so the old output cannot be reproduced. It says so rather than quietly returning something different. |
| `429` | `rate_limited` | includes `retry_after_seconds` and both limits |

`503` is documented as unreachable on purpose: the kernel CSPRNG always answers, so
"all sources down" cannot happen.

## The generators

63 of them, across 6 modules. Every name, bound, default and
option below is read from that generator's own `schema()` — the same declaration the
studio's controls and the API's validation are built from.

### Numbers

Integers, distributions, dice and the points on a sphere everyone gets wrong.

#### `numbers.integers` — Integers

Whole numbers in any range, drawn without the bias everyone else ships.

| | |
|---|---|
| **Key** | `numbers.integers` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/integers |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.integers` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `10` | `1` – `1000` | How many |
| `min` | int | `1` | `-1000000` – `1000000` | Minimum |
| `max` | int | `100` | `-1000000` – `1000000` | Maximum |
| `unique` | bool | `false` | `true`, `false` | No repeats — Draw without replacement, like a lottery. |
| `sort` | enum | `none` | `none`, `asc`, `desc` | Order |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.integers?count=10&min=1&max=100' -H 'Accept: text/plain'
```

#### `numbers.dice` — Dice

Full dice notation, rolled without the bias a modulo would introduce.

| | |
|---|---|
| **Key** | `numbers.dice` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/dice |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.dice` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `notation` | string | `4d6kh3` | up to 40 characters | Notation — e.g. 3d6+2, 4d6kh3, 2d20kl1, 6d6! |
| `rolls` | int | `6` | `1` – `100` | How many rolls |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.dice?notation=4d6kh3&rolls=6' -H 'Accept: text/plain'
```

#### `numbers.gaussian` — Bell Curve

The normal distribution by Box–Muller, plotted as you draw it.

| | |
|---|---|
| **Key** | `numbers.gaussian` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/gaussian |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.gaussian` |

`value` is the sampled data the studio plots; `meta` carries the summary statistics measured from that very sample.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `500` | `1` – `5000` | How many |
| `mu` | float | `0` | `-1000000` – `1000000` | Mean (μ) |
| `sigma` | float | `1` | `0.001` – `1000000` | Standard deviation (σ) |
| `clamp` | bool | `false` | `true`, `false` | Truncate the tails — Redraw anything beyond the cut instead of keeping it. This is a truncated normal, not a normal — the shape changes. |
| `clamp_sigma` | float | `3` | `1` – `6` | Cut at (σ) |
| `bins` | int | `25` | `4` – `60` | Histogram bars |
| `decimals` | int | `3` | `0` – `6` | Decimal places |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.gaussian?count=500&mu=0&sigma=1' -H 'Accept: text/plain'
```

#### `numbers.distribution` — Distribution Lab

Poisson, Pareto, Zipf, Beta, Cauchy — sampled and plotted.

| | |
|---|---|
| **Key** | `numbers.distribution` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/distribution |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.distribution` |

`value` is the sampled data the studio plots; `meta` carries the summary statistics measured from that very sample.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `distribution` | enum | `poisson` | `poisson`, `binomial`, `zipf`, `exponential`, `gamma`, `beta`, `pareto`, `cauchy` | Distribution |
| `count` | int | `1000` | `10` – `5000` | How many — Sampling noise falls as 1/√n. At a hundred draws the bars wobble visibly around the curve; at five thousand they sit on it. |
| `lambda` | float | `4` | `0.01` – `500` | Rate λ — Poisson: the mean number of events. Exponential: the arrival rate, so the mean wait is 1/λ. |
| `alpha` | float | `2` | `0.05` – `50` | Shape α — Pareto tail index, Gamma shape k, Beta’s first shape, and Zipf’s exponent s. Smaller is heavier-tailed. |
| `beta` | float | `5` | `0.05` – `50` | Shape β — Beta’s second shape. α = β = 1 is the uniform distribution. |
| `scale` | float | `1` | `0.01` – `100` | Scale — Gamma’s θ, Cauchy’s half-width γ, and Pareto’s minimum x_m — the point its tail starts from. |
| `trials` | int | `40` | `1` – `500` | Trials n — Binomial only. Capped at 500 because the sampler inverts the CDF, which costs about n·p steps a draw. |
| `p` | float | `0.3` | `0.001` – `0.999` | Probability p — Binomial only: the chance each try succeeds. |
| `support` | int | `100` | `2` – `2000` | Ranks N — Zipf only: how many ranks there are. Word frequency lists behave like this with s ≈ 1. |
| `bins` | int | `30` | `4` – `60` | Histogram bars |
| `decimals` | int | `3` | `0` – `6` | Decimal places |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.distribution?distribution=poisson&count=1000&lambda=4' -H 'Accept: text/plain'
```

#### `numbers.decimals` — Decimals

Floats in a range, at a precision you choose.

| | |
|---|---|
| **Key** | `numbers.decimals` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/decimals |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.decimals` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `10` | `1` – `1000` | How many |
| `min` | float | `0` | `-1000000` – `1000000` | Minimum |
| `max` | float | `1` | `-1000000` – `1000000` | Maximum |
| `precision` | int | `4` | `0` – `10` | Decimal places — The grid the draw lands on, not just how it is printed: two places between 0 and 1 means 101 possible values. |
| `unique` | bool | `false` | `true`, `false` | No repeats — Draw without replacement from the grid the precision defines. |
| `sort` | enum | `none` | `none`, `asc`, `desc` | Order |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.decimals?count=10&min=0&max=1' -H 'Accept: text/plain'
```

#### `numbers.coordinates` — Earth Points

Uniform on a sphere — not the latitude bug everyone ships.

| | |
|---|---|
| **Key** | `numbers.coordinates` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/coordinates |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.coordinates` |

`value` is the sampled data the studio plots; `meta` carries the summary statistics measured from that very sample.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `150` | `1` – `1000` | How many points |
| `show` | enum | `compare` | `compare`, `correct`, `naive` | Show — Both sets are always generated. This only chooses what is plotted. |
| `decimals` | int | `4` | `0` – `6` | Decimal places — Four places is about 11 metres at the equator. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.coordinates?count=150&show=compare&decimals=4' -H 'Accept: text/plain'
```

#### `numbers.lottery` — Lottery

Mega-Sena, Powerball and EuroMillions — with the odds printed on them.

| | |
|---|---|
| **Key** | `numbers.lottery` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/lottery |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.lottery` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `game` | enum | `mega-sena` | `mega-sena`, `powerball`, `euromillions`, `custom` | Game |
| `lines` | int | `5` | `1` – `20` | Lines |
| `pool` | int | `60` | `2` – `80` | Custom: pool size |
| `picks` | int | `6` | `1` – `10` | Custom: numbers drawn |
| `bonus_pool` | int | `0` | `0` – `50` | Custom: bonus pool |
| `bonus_picks` | int | `0` | `0` – `3` | Custom: bonus drawn |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.lottery?game=mega-sena&lines=5&pool=60' -H 'Accept: text/plain'
```

#### `numbers.coin` — Coin Flips

Biased or fair, showing the longest run against the expected log₂ n.

| | |
|---|---|
| **Key** | `numbers.coin` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/coin |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.coin` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `100` | `1` – `10000` | Flips |
| `bias` | float | `0.5` | `0` – `1` | P(heads) — A fair coin is 0.5. Bias it and watch the longest run of heads grow much faster than the head count does. |
| `style` | enum | `ht` | `ht`, `words`, `binary`, `circles` | Faces |
| `group` | int | `10` | `0` – `50` | Group every — Insert a space every n flips so the sequence can be read. Zero runs them together. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.coin?count=100&bias=0.5&style=ht' -H 'Accept: text/plain'
```

#### `numbers.uuid` — Identifiers

UUID v4 and v7, ULID, NanoID — and what each one gives away.

| | |
|---|---|
| **Key** | `numbers.uuid` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/uuid |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.uuid` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Sensitive.** This generator produces secrets, so it is given no token and no shareable
permalink, and `/api/v1/replay` returns `404` for it. A secret with a replayable URL is
not a secret. Nothing is logged or stored either way — there is no database.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `flavour` | enum | `v4` | `v4`, `v7`, `ulid`, `nanoid` | Flavour |
| `count` | int | `8` | `1` – `200` | How many |
| `moment` | string | `2026-01-01T00:00:00Z` | up to 32 characters | Clock (v7 and ULID) — These two carry a timestamp. It is a field rather than the real clock so the same seed keeps producing the same identifiers. |
| `spread` | int | `250` | `1` – `60000` | Milliseconds between them — Successive identifiers advance the clock by a random amount up to this, which is what makes the ordering visible. |
| `size` | int | `21` | `8` – `64` | NanoID length |
| `uppercase` | bool | `false` | `true`, `false` | Uppercase hex — RFC 9562 says to emit lowercase and to accept either. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.uuid?flavour=v4&count=8&moment=2026-01-01T00%3A00%3A00Z' -H 'Accept: text/plain'
```

#### `numbers.password` — Passwords

Random characters, with the entropy stated in bits instead of a green bar.

| | |
|---|---|
| **Key** | `numbers.password` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/password |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.password` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Sensitive.** This generator produces secrets, so it is given no token and no shareable
permalink, and `/api/v1/replay` returns `404` for it. A secret with a replayable URL is
not a secret. Nothing is logged or stored either way — there is no database.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `length` | int | `20` | `6` – `128` | Length |
| `count` | int | `5` | `1` – `50` | How many |
| `lowercase` | bool | `true` | `true`, `false` | Lowercase |
| `uppercase` | bool | `true` | `true`, `false` | Uppercase |
| `digits` | bool | `true` | `true`, `false` | Digits |
| `symbols` | bool | `true` | `true`, `false` | Symbols |
| `avoid_ambiguous` | bool | `false` | `true`, `false` | Avoid lookalikes — Drops I l 1 O 0 o, which get mistyped from a screen. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.password?length=20&count=5&lowercase=1' -H 'Accept: text/plain'
```

#### `numbers.bytes` — Raw Bytes

The entropy itself, in hex, base64 or binary.

| | |
|---|---|
| **Key** | `numbers.bytes` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/bytes |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.bytes` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Sensitive.** This generator produces secrets, so it is given no token and no shareable
permalink, and `/api/v1/replay` returns `404` for it. A secret with a replayable URL is
not a secret. Nothing is logged or stored either way — there is no database.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `32` | `1` – `1024` | How many bytes — 16 bytes is an AES-128 key, 32 an AES-256 key. Both are more randomness than anything you own needs. |
| `encoding` | enum | `hex` | `hex`, `base64`, `base64url`, `binary`, `decimal`, `c_array` | Encoding |
| `uppercase` | bool | `false` | `true`, `false` | Uppercase hex |
| `group` | int | `0` | `0` – `16` | Group every — Insert a space every n bytes. Zero is one unbroken string, which is what you want if you are about to paste it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.bytes?count=32&encoding=hex&uppercase=0' -H 'Accept: text/plain'
```

#### `numbers.prime` — Primes

Miller–Rabin, forty rounds, at the bit width you ask for.

| | |
|---|---|
| **Key** | `numbers.prime` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/prime |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.prime` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Sensitive.** This generator produces secrets, so it is given no token and no shareable
permalink, and `/api/v1/replay` returns `404` for it. A secret with a replayable URL is
not a secret. Nothing is logged or stored either way — there is no database.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `bits` | int | `64` | `8` – `256` | Bit width — A 2048-bit RSA key is two 1024-bit primes. This stops at 256 because bcmath does the modular exponentiation in software and the wait stops being interactive. |
| `count` | int | `5` | `1` – `20` | How many |
| `safe` | bool | `false` | `true`, `false` | Safe primes only — p where (p−1)/2 is also prime — what Diffie–Hellman wants. Rarer by another factor of ln(p), so the width is capped at 128 bits when this is on. |
| `twin` | bool | `false` | `true`, `false` | Prefer twins — Report whether p + 2 is also prime. Not a filter: twin primes thin out fast and searching for them at 64 bits would hang. |
| `format` | enum | `decimal` | `decimal`, `hex`, `both` | Show as |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.prime?bits=64&count=5&safe=0' -H 'Accept: text/plain'
```

#### `numbers.timestamp` — Moments

A random instant inside a window you define.

| | |
|---|---|
| **Key** | `numbers.timestamp` |
| **Module** | `numbers` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/numbers/timestamp |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/numbers.timestamp` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `5` | `1` – `500` | How many |
| `from` | string | `2000-01-01T00:00:00` | up to 32 characters | From (UTC) — YYYY-MM-DD, optionally with a time. Parsed strictly — “now” and “next friday” are rejected, because a generator that reads the clock cannot be replayed. |
| `to` | string | `2100-01-01T00:00:00` | up to 32 characters | To (UTC) |
| `granularity` | enum | `second` | `second`, `minute`, `hour`, `day` | Round to the nearest |
| `format` | enum | `iso8601` | `iso8601`, `unix`, `rfc2822`, `date`, `human` | Format |
| `sort` | enum | `none` | `none`, `asc`, `desc` | Order |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/numbers.timestamp?count=5&from=2000-01-01T00%3A00%3A00&to=2100-01-01T00%3A00%3A00' -H 'Accept: text/plain'
```

### Words

Passphrases with real entropy, and words that never existed.

#### `words.passphrase` — Passphrase

12.9 bits per word, from a list of 7,776 — and zero for the capital letters.

| | |
|---|---|
| **Key** | `words.passphrase` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/passphrase |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.passphrase` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Sensitive.** This generator produces secrets, so it is given no token and no shareable
permalink, and `/api/v1/replay` returns `404` for it. A secret with a replayable URL is
not a secret. Nothing is logged or stored either way — there is no database.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `words` | int | `6` | `4` – `12` | Words — Six words is 77.5 bits. Four is 51.7 — fine for a laptop login, not for a password manager. |
| `list` | enum | `large` | `large`, `short` | Wordlist |
| `separator` | enum | `dash` | `dash`, `space`, `dot`, `underscore`, `none` | Separator |
| `capitalise` | bool | `false` | `true`, `false` | Capitalise each word — Adds zero bits. It is a rule, and the attacker has the rule too. |
| `append_number` | bool | `false` | `true`, `false` | Append a number — Adds 6.6 bits, because this one is actually drawn at random. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.passphrase?words=6&list=large&separator=dash' -H 'Accept: text/plain'
```

#### `words.pseudo` — Invented Words

Order-n Markov chains over real vocabulary — noise at 2, plagiarism at 4.

| | |
|---|---|
| **Key** | `words.pseudo` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/pseudo |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.pseudo` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `12` | `1` – `60` | How many |
| `order` | int | `3` | `2` – `4` | Chain order — 2 is soup, 3 is pronounceable, 4 mostly regurgitates real words. |
| `min_length` | int | `5` | `3` – `12` | Shortest |
| `max_length` | int | `10` | `4` – `16` | Longest |
| `corpus` | enum | `large` | `large`, `short` | Trained on |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.pseudo?count=12&order=3&min_length=5' -H 'Accept: text/plain'
```

#### `words.syllabic` — Name Forge

Syllable grammars rather than a list lookup — elvish, nordic, latin, brand.

| | |
|---|---|
| **Key** | `words.syllabic` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/syllabic |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.syllabic` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `10` | `1` – `60` | How many |
| `flavour` | enum | `elvish` | `elvish`, `nordic`, `brand`, `latin` | Flavour |
| `syllables` | int | `3` | `2` – `4` | Syllables |
| `capitalise` | bool | `true` | `true`, `false` | Capitalise — These are names, so they start with a capital by default. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.syllabic?count=10&flavour=elvish&syllables=3' -H 'Accept: text/plain'
```

#### `words.brand` — Brand Names

Two open syllables and a plausible domain — no registrar was consulted.

| | |
|---|---|
| **Key** | `words.brand` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/brand |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.brand` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `12` | `1` – `60` | How many |
| `style` | enum | `brand` | `elvish`, `nordic`, `brand`, `latin` | Style |
| `tld` | enum | `com` | `com`, `io`, `ai`, `co`, `app` | Domain hint — A pattern hint only. Nothing here checks whether it is registered. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.brand?count=12&style=brand&tld=com' -H 'Accept: text/plain'
```

#### `words.lorem` — Lorem

Sentence lengths drawn log-normally, so it reads like prose and not like a list.

| | |
|---|---|
| **Key** | `words.lorem` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/lorem |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.lorem` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `paragraphs` | int | `3` | `1` – `12` | Paragraphs |
| `sentences` | int | `5` | `1` – `12` | Sentences each — Give or take one — paragraphs of identical length are the other tell of generated text. |
| `flavour` | enum | `latin` | `latin`, `tech`, `markov` | Flavour |
| `start_with_lorem` | bool | `true` | `true`, `false` | Open with "Lorem ipsum" — Latin only. The opening everyone recognises as placeholder text. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.lorem?paragraphs=3&sentences=5&flavour=latin' -H 'Accept: text/plain'
```

#### `words.article` — Random Knowledge

A Wikipedia summary you would never have gone looking for.

| | |
|---|---|
| **Key** | `words.article` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/article |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.article` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Not reproducible.** Built on live external material that moves, so the same seed
against tomorrow's data would pick something else. No permalink is issued, because a link
that quietly stops working is worse than no link.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `3` | `1` – `10` | How many |
| `with_extract` | bool | `true` | `true`, `false` | Include the summary |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.article?count=3&with_extract=1' -H 'Accept: text/plain'
```

#### `words.species` — Random Life

A real species drawn from GBIF — twenty million names, one of them yours.

| | |
|---|---|
| **Key** | `words.species` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/species |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.species` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Not reproducible.** Built on live external material that moves, so the same seed
against tomorrow's data would pick something else. No permalink is issued, because a link
that quietly stops working is worse than no link.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `5` | `1` – `12` | How many |
| `with_lineage` | bool | `true` | `true`, `false` | Show the lineage — Kingdom down to family, which is usually more surprising than the name. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.species?count=5&with_lineage=1' -H 'Accept: text/plain'
```

#### `words.related` — Word Web

Means-like, rhymes-with and sounds-like, via Datamuse.

| | |
|---|---|
| **Key** | `words.related` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/related |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.related` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Not reproducible.** Built on live external material that moves, so the same seed
against tomorrow's data would pick something else. No permalink is issued, because a link
that quietly stops working is worse than no link.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `word` | string | `ocean` | up to 40 characters | Seed word — One word works best. The relation is computed against this, so changing it fetches a new pool. |
| `relation` | enum | `ml` | `ml`, `rel_rhy`, `sl`, `rel_bga` | Relation |
| `count` | int | `8` | `1` – `25` | How many |
| `with_score` | bool | `true` | `true`, `false` | Show Datamuse’s relevance score — Their ranking, not ours — printed so you can see that the ordering came from them and the choice came from the seed. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.related?word=ocean&relation=ml&count=8' -H 'Accept: text/plain'
```

#### `words.identity` — Fictional People

Names that hold together across a nationality.

| | |
|---|---|
| **Key** | `words.identity` |
| **Module** | `words` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/words/identity |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/words.identity` |

`value` is the result itself — one value, or a list of them; `display` is the same thing rendered as a single human-readable string.

**Not reproducible.** Built on live external material that moves, so the same seed
against tomorrow's data would pick something else. No permalink is issued, because a link
that quietly stops working is worse than no link.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `count` | int | `5` | `1` – `20` | How many |
| `nationality` | enum | `any` | `any`, `br`, `ca`, `de`, `dk`, `es`, `fi`, `fr`, `gb`, `ie`, `in`, `no`, `nl`, `nz`, `tr`, `us` | Nationality — Names and places come from the same locale, so the person holds together. Mixed draws each person from a random one. |
| `with_location` | bool | `true` | `true`, `false` | Include where they live |
| `with_email` | bool | `true` | `true`, `false` | Include an email address — Always on example.com, which RFC 2606 reserves precisely so that test data cannot reach a real inbox. |
| `with_age` | bool | `true` | `true`, `false` | Include an age |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/words.identity?count=5&nationality=any&with_location=1' -H 'Accept: text/plain'
```

### Equations

Problems with clean answers, built backwards from the solution.

#### `equations.arithmetic` — Mental Math

Drills at a digit count and operation set you pick, and division always comes out even.

| | |
|---|---|
| **Key** | `equations.arithmetic` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/arithmetic |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.arithmetic` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `operations` | enum | `all` | `add`, `sub`, `mul`, `div`, `add_sub`, `mul_div`, `all` | Operations |
| `digits` | int | `2` | `1` – `4` | Digits — How large the operands get. |
| `count` | int | `10` | `1` – `100` | How many |
| `negatives` | bool | `false` | `true`, `false` | Allow negatives — Lets a subtraction go below zero, and operands turn negative. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.arithmetic?operations=all&digits=2&count=10' -H 'Accept: text/plain'
```

#### `equations.expression` — Expression Tree

A probabilistic grammar grows the expression; you get the tree it grew from too.

| | |
|---|---|
| **Key** | `equations.expression` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/expression |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.expression` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `depth` | int | `3` | `1` – `6` | Maximum depth — A hard cut. Expressions usually stop short of it. |
| `functions` | enum | `trig` | `none`, `roots`, `trig`, `full` | Function set |
| `variables` | int | `1` | `0` – `3` | Variables — Zero makes every expression a closed number. |
| `constants` | bool | `false` | `true`, `false` | Allow π and e |
| `show_value` | bool | `true` | `true`, `false` | Evaluate it |
| `count` | int | `3` | `1` – `40` | How many |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.expression?depth=3&functions=trig&variables=1' -H 'Accept: text/plain'
```

#### `equations.linear` — Linear Equations

Built root-first, so the answer is always clean and never needs checking.

| | |
|---|---|
| **Key** | `equations.linear` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/linear |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.linear` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `tier` | enum | `two_step` | `one_step`, `two_step`, `two_sided`, `brackets`, `mixed` | Difficulty |
| `count` | int | `8` | `1` – `50` | How many |
| `integer_solutions` | bool | `true` | `true`, `false` | Whole-number answers |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.linear?tier=two_step&count=8&integer_solutions=1' -H 'Accept: text/plain'
```

#### `equations.quadratic` — Quadratics

Integer, rational or surd roots — built from the roots, so they factor.

| | |
|---|---|
| **Key** | `equations.quadratic` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/quadratic |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.quadratic` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `roots` | enum | `integer` | `integer`, `rational`, `surd`, `mixed` | Root type |
| `monic` | bool | `false` | `true`, `false` | Leading coefficient 1 — Off lets the x² term carry a coefficient. |
| `count` | int | `6` | `1` – `50` | How many |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.quadratic?roots=integer&monic=0&count=6' -H 'Accept: text/plain'
```

#### `equations.system` — Systems

2×2 and 3×3, guaranteed to have one solution and to reach it without fractions.

| | |
|---|---|
| **Key** | `equations.system` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/system |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.system` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `size` | enum | `2` | `2`, `3` | Size |
| `count` | int | `4` | `1` – `30` | How many |
| `solution_range` | int | `8` | `2` – `20` | Solutions within ± |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.system?size=2&count=4&solution_range=8' -H 'Accept: text/plain'
```

#### `equations.calculus` — Calculus

Derivatives and integrals per rule — the integrals exist because they were built backwards.

| | |
|---|---|
| **Key** | `equations.calculus` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/calculus |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.calculus` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `mode` | enum | `derivative` | `derivative`, `integral` | Mode |
| `rule` | enum | `mixed` | `power`, `product`, `quotient`, `chain`, `trig`, `exp_log`, `mixed` | Rule |
| `count` | int | `6` | `1` – `40` | How many |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.calculus?mode=derivative&rule=mixed&count=6' -H 'Accept: text/plain'
```

#### `equations.matrix` — Matrices

Any, invertible, symmetric or positive-definite — constructed, not rejection-sampled.

| | |
|---|---|
| **Key** | `equations.matrix` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/matrix |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.matrix` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `kind` | enum | `any` | `any`, `invertible`, `determinant`, `symmetric`, `spd` | Kind |
| `rows` | int | `3` | `2` – `5` | Rows |
| `cols` | int | `3` | `2` – `5` | Columns — Ignored by the kinds that have to be square. |
| `determinant` | int | `6` | `-12` – `12` | Determinant |
| `range` | int | `6` | `1` – `9` | Entries within ± |
| `count` | int | `1` | `1` – `12` | How many |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.matrix?kind=any&rows=3&cols=3' -H 'Accept: text/plain'
```

#### `equations.identity` — True or False?

A real identity — half of them subtly broken. You guess; the verdict is checked, not assumed.

| | |
|---|---|
| **Key** | `equations.identity` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/identity |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.identity` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `topic` | enum | `mixed` | `trig`, `log`, `mixed` | Topic |
| `count` | int | `4` | `1` – `30` | How many |
| `explain` | bool | `true` | `true`, `false` | Say what is wrong — Prints the correct form beside a false statement. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.identity?topic=mixed&count=4&explain=1' -H 'Accept: text/plain'
```

#### `equations.sequence` — Find the Pattern

Arithmetic, geometric, quadratic or Fibonacci-like — with enough terms to be unambiguous.

| | |
|---|---|
| **Key** | `equations.sequence` |
| **Module** | `equations` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain` |
| **Studio** | https://randomly.cluxnei.dev/g/equations/sequence |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/equations.sequence` |

`value.problems` is a list of problems with their answers; `meta.latex` carries the same in LaTeX.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `kind` | enum | `mixed` | `arithmetic`, `geometric`, `quadratic`, `fibonacci`, `mixed` | Pattern |
| `terms` | int | `5` | `4` – `9` | Terms shown |
| `count` | int | `5` | `1` – `40` | How many |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/equations.sequence?kind=mixed&terms=5&count=5' -H 'Accept: text/plain'
```

### Patterns

Noise, growth and decay — Perlin, Gray-Scott, cellular automata.

#### `patterns.perlin` — Perlin Noise

Gradient noise, stacked into fractals and folded through itself.

| | |
|---|---|
| **Key** | `patterns.perlin` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/perlin |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.perlin` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `scale` | float | `3` | `0.5` – `16` | Zoom — How many noise cells fit across the canvas. |
| `octaves` | int | `5` | `1` – `9` | Detail (octaves) — One octave is plain Perlin. Each one adds finer detail at half the strength. |
| `persistence` | float | `0.5` | `0.2` – `0.85` | Roughness — How much each finer octave contributes. |
| `lacunarity` | float | `2` | `1.4` – `3.2` | Frequency step |
| `variant` | enum | `fbm` | `fbm`, `turbulence`, `ridged`, `billow` | Shape |
| `warp` | float | `0` | `0` – `1.2` | Domain warp — Folds the noise through a copy of itself. The single most dramatic control here. |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `contours` | bool | `false` | `true`, `false` | Banding — Quantise into flat bands instead of a smooth gradient. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.perlin?width=900&height=600&scale=3' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.perlin?width=900&height=600&scale=3&format=png'
```

#### `patterns.simplex` — Simplex Noise

Fewer directional artefacts, cheaper in higher dimensions.

| | |
|---|---|
| **Key** | `patterns.simplex` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/simplex |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.simplex` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `scale` | float | `3` | `0.5` – `16` | Zoom — How many lattice cells fit across the canvas. |
| `octaves` | int | `5` | `1` – `9` | Detail (octaves) — One octave is plain OpenSimplex2. Each one adds finer detail at half the strength. |
| `persistence` | float | `0.5` | `0.2` – `0.85` | Roughness |
| `lacunarity` | float | `2` | `1.4` – `3.2` | Frequency step |
| `variant` | enum | `fbm` | `fbm`, `turbulence`, `ridged`, `billow` | Shape |
| `warp` | float | `0` | `0` – `1.2` | Domain warp — Folds the noise through a copy of itself. |
| `compare` | bool | `false` | `true`, `false` | Compare with Perlin — Splits the canvas: OpenSimplex2 left, Perlin right, same seed and same settings. Perlin's square lattice shows as a faint grain along the axes. |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `contours` | bool | `false` | `true`, `false` | Banding — Quantise into flat bands instead of a smooth gradient. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.simplex?width=900&height=600&scale=3' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.simplex?width=900&height=600&scale=3&format=png'
```

#### `patterns.worley` — Worley Cells

Distance to the nth-nearest feature point.

| | |
|---|---|
| **Key** | `patterns.worley` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/worley |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.worley` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `density` | float | `9` | `2` – `48` | Cells across — Feature points are scattered one per grid cell, so this is both the cell count and the point count. |
| `feature` | enum | `f2f1` | `f1`, `f2`, `f2f1`, `f1f2` | Distance kept |
| `metric` | enum | `euclidean` | `euclidean`, `manhattan`, `chebyshev`, `minkowski` | Distance metric |
| `p` | float | `3` | `0.4` – `8` | Minkowski p — Only used by the Minkowski metric. p=1 is Manhattan, p=2 is Euclidean, and large p approaches Chebyshev. |
| `jitter` | float | `1` | `0` – `1` | Scatter — How far a point may stray from its cell centre. At 0 the grid is perfectly regular and you get a tiling. |
| `invert` | bool | `false` | `true`, `false` | Invert |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `contours` | bool | `false` | `true`, `false` | Banding — Quantise into flat bands instead of a smooth gradient. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.worley?width=900&height=600&density=9' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.worley?width=900&height=600&density=9&format=png'
```

#### `patterns.spectral` — Spectral Noise

1/f^β synthesised in the frequency domain.

| | |
|---|---|
| **Key** | `patterns.spectral` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/spectral |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.spectral` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `preset` | enum | `brown` | `custom`, `white`, `pink`, `brown`, `black`, `blue`, `violet` | Colour of noise |
| `beta` | float | `1` | `-2.5` – `4` | β — The exponent itself. 0 is white, 1 pink, 2 brown, −1 blue. Only read when the preset is Custom. |
| `contrast` | float | `2.5` | `0.6` – `4` | Contrast — Where the palette's ends are pinned, in standard deviations. A spectral field is Gaussian, so it has tails rather than bounds — stretching to the extremes would leave the whole picture in the middle third of the ramp. |
| `zoom` | float | `1` | `1` – `12` | Zoom — Magnifies the same field. At 1 you see every octave the raster can hold, which for pink noise is mostly grain; wind it up and the low frequencies take over. A 1/f field is scale-free, so this is a real zoom and not a blur. |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `contours` | bool | `false` | `true`, `false` | Banding — Quantise into flat bands. On a brown field this draws something very close to a contour map, because that is what a brown field is. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.spectral?width=900&height=600&preset=brown' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.spectral?width=900&height=600&preset=brown&format=png'
```

#### `patterns.automaton` — Elementary Automata

All 256 rules, including the one that is a PRNG.

| | |
|---|---|
| **Key** | `patterns.automaton` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/automaton |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.automaton` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `preset` | enum | `r30` | `custom`, `r30`, `r110`, `r90`, `r150`, `r184` | Rule |
| `rule` | int | `30` | `0` – `255` | Rule number — Every rule is one byte: bit i is what the neighbourhood with binary value i becomes. Only used when the preset is Custom. |
| `start` | enum | `centre` | `centre`, `random` | First row — One cell shows the rule's own geometry; a random row shows what it does to noise. |
| `density` | float | `0.5` | `0.02` – `0.98` | Start density — Only used by the random first row. |
| `cell` | int | `3` | `1` – `16` | Cell size — Pixels per cell. Smaller means more generations on screen. |
| `wrap` | bool | `true` | `true`, `false` | Wrap edges — Off, the world has walls and the pattern reflects off them. |
| `palette` | enum | `mono` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.automaton?width=900&height=600&preset=r30' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.automaton?width=900&height=600&preset=r30&format=png'
```

#### `patterns.life` — Life

Conway from a random soup, with a density control.

| | |
|---|---|
| **Key** | `patterns.life` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/life |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.life` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `preset` | enum | `conway` | `conway`, `highlife`, `replicator`, `serviettes`, `daynight`, `maze`, `coral`, `custom` | Rule |
| `rule` | string | `B3/S23` | up to 24 characters | Custom rule — B/S notation: the neighbour counts that cause a birth, then the counts a live cell survives. Only read when the preset is Custom. |
| `cell` | int | `4` | `1` – `16` | Cell size — Pixels per cell. Small cells mean a large world and more room for structure to travel. |
| `density` | float | `0.38` | `0.02` – `0.98` | Soup density — The fraction of cells alive at generation zero. Conway is liveliest around a third; the edges of this slider are where a rule shows what it does when starved or flooded. |
| `generations` | int | `240` | `1` – `900` | Generations |
| `mode` | enum | `exposure` | `exposure`, `state` | Draw |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.life?width=900&height=600&preset=conway' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.life?width=900&height=600&preset=conway&format=png'
```

#### `patterns.reaction` — Reaction–Diffusion

Gray–Scott, run until the pattern stops moving.

| | |
|---|---|
| **Key** | `patterns.reaction` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/reaction |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.reaction` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `preset` | enum | `coral` | `mitosis`, `coral`, `solitons`, `labyrinth`, `spots`, `custom` | Pattern |
| `feed` | float | `0.035` | `0.005` – `0.09` | Feed rate F — Only used when the preset is Custom. Most of this range is a field that dies within a few hundred steps — that is the honest shape of the parameter space. |
| `kill` | float | `0.065` | `0.03` – `0.075` | Kill rate k — Only used when the preset is Custom. |
| `grid` | int | `192` | `96` – `288` | Grid — The simulation runs on a square grid and is sampled up to the canvas, so this is detail, not size. |
| `steps` | int | `3200` | `200` – `12000` | Steps — How long the reaction runs. Capped against the grid size so a slider drag cannot lock the tab. |
| `du` | float | `1` | `0.2` – `1.2` | Diffusion of u |
| `dv` | float | `0.5` | `0.1` – `0.7` | Diffusion of v |
| `seeds` | int | `14` | `1` – `60` | Seed patches — The initial disturbance. Everything on screen grows out of these. |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `contours` | bool | `false` | `true`, `false` | Banding |
| `invert` | bool | `false` | `true`, `false` | Invert |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.reaction?width=900&height=600&preset=coral' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.reaction?width=900&height=600&preset=coral&format=png'
```

#### `patterns.truchet` — Truchet Tiles

Random tile orientation. Instant beauty, ten lines of code.

| | |
|---|---|
| **Key** | `patterns.truchet` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/truchet |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.truchet` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `tiles` | int | `14` | `3` – `72` | Tiles across |
| `set` | enum | `arcs` | `arcs`, `diagonals`, `triangles`, `mixed` | Tile set |
| `weight` | float | `0.2` | `0.02` – `0.7` | Line weight — As a fraction of a tile. Past about 0.5 the lines meet and the negative space becomes the pattern — worth pushing. |
| `colouring` | enum | `diagonal` | `flat`, `diagonal`, `tile` | Ink |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.truchet?width=900&height=600&tiles=14' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.truchet?width=900&height=600&tiles=14&format=png'
```

#### `patterns.poisson` — Blue Noise

Poisson-disk beside uniform random — the difference is the lesson.

| | |
|---|---|
| **Key** | `patterns.poisson` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/poisson |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.poisson` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `mode` | enum | `compare` | `compare`, `blue`, `uniform` | Show |
| `radius` | float | `17` | `5` – `90` | Minimum separation — In pixels. No two blue-noise points are ever closer than this; the uniform panel gets the same number of points and no such promise. |
| `candidates` | int | `30` | `4` – `60` | Candidates per point — Bridson's k. Each accepted point gets this many attempts at a neighbour before it is retired. Low values leave gaps. |
| `dot` | float | `3` | `0.6` – `12` | Dot size |
| `colouring` | enum | `nearest` | `nearest`, `flat` | Colour dots by — The measurement that separates the two panels: blue noise has almost none of it, uniform random has all of it. |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.poisson?width=900&height=600&mode=compare' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.poisson?width=900&height=600&mode=compare&format=png'
```

#### `patterns.voronoi` — Voronoi

Cells from random sites, coloured so no two neighbours match.

| | |
|---|---|
| **Key** | `patterns.voronoi` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/voronoi |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.voronoi` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `sites` | int | `90` | `4` – `220` | Cells |
| `colouring` | enum | `cell` | `cell`, `area` | Colour cells by |
| `edges` | float | `1.6` | `0` – `8` | Border thickness — A border is where the nearest and second-nearest sites are equally far away. Zero draws none. |
| `dots` | bool | `false` | `true`, `false` | Mark the sites — The point each cell grew from. |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `8` | `3` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.voronoi?width=900&height=600&sites=90' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.voronoi?width=900&height=600&sites=90&format=png'
```

#### `patterns.maze` — Mazes

DFS, Kruskal and Wilson side by side — algorithm as bias.

| | |
|---|---|
| **Key** | `patterns.maze` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/maze |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.maze` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `algorithm` | enum | `compare` | `compare`, `dfs`, `kruskal`, `wilson` | Algorithm |
| `cell` | int | `18` | `8` – `64` | Cell size — In pixels. Grown automatically if the grid would otherwise be too large to carve. |
| `wall` | float | `0.18` | `0.04` – `0.5` | Wall thickness — As a fraction of a cell. |
| `colouring` | enum | `depth` | `depth`, `plain` | Colour the floor by — Distance is where the bias becomes visible: DFS stretches one long gradient, the other two spread outwards. |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `8` | `2` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.maze?width=900&height=600&algorithm=compare' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.maze?width=900&height=600&algorithm=compare&format=png'
```

#### `patterns.lsystem` — L-Systems

Stochastic rewrite rules: plants, snowflakes, dragon curves.

| | |
|---|---|
| **Key** | `patterns.lsystem` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/lsystem |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.lsystem` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `200` – `2048` | Width |
| `height` | int | `600` | `200` – `2048` | Height |
| `preset` | enum | `plant` | `plant`, `koch`, `dragon`, `sierpinski` | System |
| `iterations` | int | `0` | `0` – `14` | Iterations — Zero uses the preset's own depth. Each iteration rewrites every symbol at once, so the string grows geometrically. |
| `angle` | float | `0` | `0` – `180` | Turn angle — Zero uses the preset's own angle. The single most dramatic control here — a plant at 90° is a lattice. |
| `stochastic` | float | `1` | `0` – `1` | Randomness — How freely the branching rules choose between their alternatives, and how much the turns and internodes wander. Only the plant has alternatives; the other three are textbook figures and ignore this. |
| `thickness` | float | `2` | `0.4` – `6` | Line weight |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.lsystem?width=900&height=600&preset=plant' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.lsystem?width=900&height=600&preset=plant&format=png'
```

#### `patterns.wfc` — Wave Function Collapse

Overlapping model, min-entropy heuristic, backtracking.

| | |
|---|---|
| **Key** | `patterns.wfc` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/wfc |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.wfc` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `960` | `200` – `2048` | Width |
| `height` | int | `640` | `200` – `2048` | Height |
| `sample` | enum | `knot` | `knot`, `maze`, `rooms`, `circuit`, `weave`, `blossoms` | Sample |
| `n` | int | `3` | `2` – `3` | Window size (N) — How much context a pattern carries. N = 2 knows only which pairs of cells may touch and produces something loose; N = 3 knows whole corners, and is where the output starts looking authored. |
| `symmetry` | enum | `8` | `1`, `2`, `4`, `8` | Symmetry — Which transforms of each pattern are also admitted. More symmetry means a richer output from the same sample, and a larger pattern set to propagate through. |
| `tiles` | int | `74` | `8` – `140` | Cells across — Measured across the long side. The solve is cells × patterns × adjacency, so this is the control that decides whether the render is instant or merely fast. |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `grain` | float | `0.01` | `0` – `0.06` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.wfc?width=960&height=640&sample=knot' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.wfc?width=960&height=640&sample=knot&format=png'
```

#### `patterns.walk` — Random Walks

Brownian, self-avoiding and Lévy — the fat tail is visible.

| | |
|---|---|
| **Key** | `patterns.walk` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/walk |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.walk` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1100` | `200` – `2048` | Width |
| `height` | int | `620` | `200` – `2048` | Height |
| `mode` | enum | `compare` | `compare`, `brownian`, `levy`, `saw` | Walk |
| `walkers` | int | `22` | `1` – `160` | Walkers — Each one is an independent walk and is never reused. |
| `steps` | int | `2600` | `20` – `20000` | Steps each |
| `tail` | float | `1.35` | `1.05` – `3` | Lévy tail α — The Pareto exponent. Below 2 the variance is infinite and the walk is dominated by its rare huge jumps; above 2 the central limit theorem takes back over and it becomes Brownian again. |
| `spread` | float | `0.85` | `0.2` – `1.6` | Coverage — How much of the frame a typical walk should reach. Step length is solved backwards from this and each mode's own scaling exponent, so all three fill the frame the same amount however many steps you ask for. |
| `start` | enum | `centre` | `centre`, `scattered` | Start from |
| `alpha` | float | `0.11` | `0.01` – `0.9` | Line alpha — Per-segment opacity. A walk that crosses its own path a thousand times is drawn out of the overlap, so this wants to stay low. |
| `line` | float | `1.2` | `0.4` – `4` | Line width |
| `glow` | bool | `true` | `true`, `false` | Additive blending |
| `background` | enum | `ink` | `ink`, `paper`, `palette` | Ground |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `grain` | float | `0.016` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.walk?width=1100&height=620&mode=compare' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.walk?width=1100&height=620&mode=compare&format=png'
```

#### `patterns.dla` — Diffusion-Limited Aggregation

Dendritic crystals, grown one sticky particle at a time.

| | |
|---|---|
| **Key** | `patterns.dla` |
| **Module** | `patterns` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/patterns/dla |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/patterns.dla` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `880` | `200` – `2048` | Width |
| `height` | int | `800` | `200` – `2048` | Height |
| `seed_shape` | enum | `point` | `point`, `line` | Grow from |
| `particles` | int | `7000` | `200` – `40000` | Particles — Every one of them is walked until it touches, which is the entire cost of the render. The run ends at this count or when the cluster reaches the edge of its lattice, whichever comes first — and the finished cluster is then fitted to the frame, so fewer particles means a chunkier crystal rather than a smaller one. |
| `cell` | int | `2` | `1` – `10` | Lattice — The lattice the crystal grows on, as a divisor of the canvas. A finer lattice grows a cluster with finer branches, and costs a great deal more walking: halving this roughly triples the render. |
| `stickiness` | float | `1` | `0.02` – `1` | Stickiness — The chance a particle freezes when it touches. Below 1 it can work its way into the crevices before committing, which thickens the branches and pushes the fractal dimension towards 2 — frost at one end of this slider, sponge at the other. |
| `glow` | float | `0.05` | `0` – `0.3` | Glow — A wide, faint halo under every particle, added rather than painted. Haloes overlap where the cluster is dense, so the trunk lights up and a lone tip does not. |
| `background` | enum | `ink` | `ink`, `paper`, `palette` | Ground |
| `palette` | enum | `viridis` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `grain` | float | `0.014` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/patterns.dla?width=880&height=800&seed_shape=point' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/patterns.dla?width=880&height=800&seed_shape=point&format=png'
```

### Images

Flow fields, superformula blobs, perceptual palettes, real art.

#### `images.flowfield` — Flow Field

Thousands of particles advected through fractal noise.

| | |
|---|---|
| **Key** | `images.flowfield` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/flowfield |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.flowfield` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1200` | `256` – `2048` | Width |
| `height` | int | `750` | `256` – `2048` | Height |
| `particles` | int | `1500` | `100` – `2500` | Particles — Each one traces a single trail and is never reused. |
| `trail` | int | `190` | `10` – `420` | Trail length — Steps before a particle runs out. Long trails cross the whole canvas; short ones read as brushwork. |
| `step` | float | `1.6` | `0.4` – `6` | Step length — Pixels advanced per step. Small steps hug the field, large ones cut across it. |
| `scale` | float | `2.2` | `0.4` – `9` | Field zoom — How many noise cells fit across the canvas. |
| `octaves` | int | `4` | `1` – `7` | Detail (octaves) |
| `turns` | float | `1` | `0.2` – `3` | Angular range — How many full turns the noise maps onto. Below 1 the flow stays combed in one direction; above 2 it knots. |
| `alpha` | float | `0.2` | `0.01` – `0.8` | Line alpha — Per-segment opacity. The picture is the overlap, so this wants to stay low. |
| `line` | float | `1.1` | `0.4` – `4` | Line width |
| `glow` | bool | `true` | `true`, `false` | Additive blending — Trails add their light together instead of painting over each other. On a dark ground this is the whole look. |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `grain` | float | `0.018` | `0` – `0.08` | Grain — Per-pixel noise over the finished render. A little of it is the difference between generative and computer-made. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.flowfield?width=1200&height=750&particles=1500' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.flowfield?width=1200&height=750&particles=1500&format=png'
```

#### `images.blob` — Superformula

One equation: starfish, gears, leaves, sea urchins.

| | |
|---|---|
| **Key** | `images.blob` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/blob |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.blob` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `256` – `2048` | Width |
| `height` | int | `900` | `256` – `2048` | Height |
| `clusters` | int | `5` | `1` – `9` | Specimens — The first one is the subject and runs off the edges of the frame; the rest are companions settled around it, each an independent draw of m, n₁, n₂ and n₃. |
| `rings` | int | `5` | `1` – `14` | Bands — Concentric copies of the same shape, shrinking inwards and walking the palette as they go. Few and opaque reads as a body; many and thin reads as a scribble. |
| `symmetry` | int | `0` | `0` – `16` | Symmetry (m) — Below 3, the seed draws m per shape — the surprise-me setting. Above it, every shape is pinned to the same fold count. |
| `morph` | float | `0.3` | `0` – `1.5` | Morph — How far n₁, n₂ and n₃ drift between the outer band and the innermost one. At zero the bands are concentric copies. |
| `twist` | float | `0` | `0` – `2` | Twist — Rotation accumulated from band to band, in turns. A little offsets the lobes; past a tenth or so the bands stop lining up and the shape turns into interference. |
| `spread` | float | `0.5` | `0` – `1` | Scatter — How far the companions sit from the subject. At zero they crowd into it; at one they stand clear of it. |
| `fill` | float | `0.92` | `0` – `1` | Fill opacity — Zero leaves pure outlines. Near one, each band covers the one outside it and the specimen reads as a solid. |
| `line` | float | `1` | `0` – `8` | Outline width — Zero leaves pure fills. |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `grain` | float | `0.016` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.blob?width=900&height=900&clusters=5' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.blob?width=900&height=900&clusters=5&format=png'
```

#### `images.identicon` — Identicon

A deterministic avatar from a hash. Same input, same face.

| | |
|---|---|
| **Key** | `images.identicon` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/identicon |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.identicon` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

**Draws no entropy.** The output is a pure function of what you pass in, so no source is
consulted, nothing is spent waiting on a beacon, and the receipt says exactly that
instead of crediting a beacon that changed nothing.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `input` | string | `randomly` | up to 96 characters | Input — Anything at all — a username, an email, a commit hash. This, and nothing else, decides what you get. |
| `size` | int | `512` | `128` – `1024` | Size |
| `cells` | int | `5` | `3` – `9` | Grid — A 5×5 grid mirrored down the middle needs only 15 bits, which is why identicons were 5×5 long before anyone had bits to spare. |
| `shape` | enum | `auto` | `auto`, `square`, `circle`, `triangle`, `diamond` | Cell shape |
| `two_tone` | bool | `true` | `true`, `false` | Two tone — A second hue, 50° along, for roughly half the live cells. |
| `padding` | float | `0.14` | `0` – `0.35` | Padding |
| `gap` | float | `0.06` | `0` – `0.4` | Cell gap |
| `background` | enum | `tint` | `tint`, `paper`, `ink` | Ground |
| `grain` | float | `0.012` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.identicon?input=randomly&size=512&cells=5' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.identicon?input=randomly&size=512&cells=5&format=png'
```

#### `images.circles` — Circle Packing

Grow until collision, keep what fits.

| | |
|---|---|
| **Key** | `images.circles` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/circles |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.circles` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1100` | `256` – `2048` | Width |
| `height` | int | `760` | `256` – `2048` | Height |
| `attempts` | int | `26000` | `500` – `90000` | Darts thrown — Candidate points tried. Most of the late ones land inside a circle that already exists and are thrown away; the ones that survive are what fills the gaps. |
| `min_radius` | float | `3` | `1` – `40` | Smallest circle — Candidates that cannot grow this large are discarded. Raise it and the gaps between the big circles stay open. |
| `max_radius` | float | `95` | `8` – `320` | Largest circle |
| `gap` | float | `2.5` | `0` – `24` | Gap — Clear space kept between circles. At zero they touch exactly, which is the true packing and reads as denser than it is. |
| `style` | enum | `mixed` | `filled`, `rings`, `nested`, `mixed` | Draw as |
| `weight` | float | `0.14` | `0.03` – `0.5` | Stroke weight — As a fraction of each circle's own radius, so a large circle is drawn more boldly than a small one rather than the same. |
| `colouring` | enum | `field` | `radius`, `field`, `order` | Colour by |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `golden` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `grain` | float | `0.014` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.circles?width=1100&height=760&attempts=26000' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.circles?width=1100&height=760&attempts=26000&format=png'
```

#### `images.mondrian` — Mondrian

Recursive subdivision, split at U(0.3, 0.7).

| | |
|---|---|
| **Key** | `images.mondrian` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/mondrian |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.mondrian` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `900` | `256` – `2048` | Width |
| `height` | int | `900` | `256` – `2048` | Height |
| `cut_min` | float | `0.3` | `0.02` – `0.5` | Cut range, low — Where along a rectangle a cut may fall. Push this to 0.02 and the composition shreds into slivers; push it to 0.5 and every cut lands in the middle, which is a grid. |
| `threshold` | float | `0.035` | `0.002` – `0.25` | Stop below — A rectangle smaller than this fraction of the canvas is left whole. The single strongest control over how busy the result is. |
| `squareness` | float | `0.78` | `0` – `1` | Cut the long side — How often a cut crosses the longer side. At 1 every rectangle is pushed towards square; at 0 the composition drifts into long bands. |
| `fill` | float | `0.34` | `0` – `1` | Painted cells — The fraction that get a colour rather than staying paper. Mondrian used very few, and a canvas that is mostly colour stops reading as a composition and starts reading as a quilt. |
| `stroke` | float | `9` | `0` – `30` | Line weight — The gutter between cells, in pixels. The lines are not drawn — they are the ground showing through. |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Lines |
| `paper` | bool | `true` | `true`, `false` | Unpainted cells are white — Off, the unpainted cells take the palette's lightest stop instead, which keeps the whole composition inside one colour scheme. |
| `palette` | enum | `triadic` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `5` | `2` – `10` | Palette size |
| `grain` | float | `0.012` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.mondrian?width=900&height=900&cut_min=0.3' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.mondrian?width=900&height=900&cut_min=0.3&format=png'
```

#### `images.gradient` — Mesh Gradient

Random control points, dithered to kill the banding.

| | |
|---|---|
| **Key** | `images.gradient` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/gradient |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.gradient` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1200` | `256` – `2048` | Width |
| `height` | int | `800` | `256` – `2048` | Height |
| `stops` | int | `10` | `2` – `18` | Control points — Each one holds a colour and pulls the field towards it. |
| `blend` | enum | `soft` | `soft`, `sharp` | Blend |
| `falloff` | float | `0.42` | `0.18` – `1.8` | Softness — The Gaussian width, measured in the typical spacing between control points rather than in pixels — so adding points does not also change how soft the blend is. |
| `power` | float | `2.6` | `1` – `8` | Shepard exponent — Only used by the stained-glass blend. Higher values flatten the cell interiors and tighten the boundaries between them. |
| `warp` | float | `0.18` | `0` – `0.6` | Domain warp — Displaces each pixel through a noise field before the blend is evaluated. The isolines stop being circles and start folding around each other, which is what makes a gradient look poured rather than computed. |
| `warp_scale` | float | `2.2` | `0.4` – `8` | Warp zoom |
| `dither` | float | `1` | `0` – `4` | Dither — Ordered dither amplitude, in output levels. One level is the right answer; zero is there so you can see the banding it prevents. |
| `palette` | enum | `split` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `grain` | float | `0.006` | `0` – `0.06` | Grain — Film grain over the finished render, on top of the dither. The two do different jobs: the dither hides quantisation, the grain gives the surface a texture. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.gradient?width=1200&height=800&stops=10' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.gradient?width=1200&height=800&stops=10&format=png'
```

#### `images.spray` — Particle Spray

A Gaussian mixture with k random components.

| | |
|---|---|
| **Key** | `images.spray` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/spray |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.spray` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1200` | `256` – `2048` | Width |
| `height` | int | `800` | `256` – `2048` | Height |
| `components` | int | `5` | `1` – `10` | Components — How many Gaussians the mixture is made of. One is a fuzzy dot; the interest is entirely in how several overlap. |
| `particles` | int | `450000` | `5000` – `900000` | Particles — Samples drawn from the mixture. The image is their density, so this is a grain control as much as a quantity one. |
| `spread` | float | `0.12` | `0.02` – `0.6` | Component size — The typical standard deviation, as a fraction of the short side. |
| `anisotropy` | float | `3.4` | `1` – `9` | Elongation — The most a component's two axes may differ. At 1 every component is a circular blur; above 3 they become strokes with a direction, which is what stops the result looking like spilt milk. |
| `alpha` | float | `0.11` | `0.004` – `0.3` | Particle alpha — Per-particle opacity. The picture is the accumulation, so this wants to stay low. |
| `radius` | float | `1` | `0.3` – `4` | Particle size |
| `glow` | bool | `true` | `true`, `false` | Additive blending — Particles add their light together instead of painting over each other. On a dark ground this is the whole look. |
| `drift` | float | `0.16` | `0` – `0.5` | Halo drift — How far along the palette a particle travels as it lands further from its component's centre — so a core is one colour and its halo another. |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `7` | `2` – `12` | Palette size |
| `grain` | float | `0.012` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.spray?width=1200&height=800&components=5' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.spray?width=1200&height=800&components=5&format=png'
```

#### `images.tiles` — Glyph Grid

A random glyph and rotation per cell.

| | |
|---|---|
| **Key** | `images.tiles` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/tiles |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.tiles` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1000` | `256` – `2048` | Width |
| `height` | int | `1000` | `256` – `2048` | Height |
| `tiles` | int | `12` | `2` – `64` | Tiles across — Measured across the long side, so a landscape canvas gets square cells rather than stretched ones. |
| `set` | enum | `all` | `all`, `curves`, `lines`, `solids` | Glyphs — Curves alone read as plumbing, lines alone as a circuit diagram, solids alone as a quilt. All three together is the busiest and usually the best. |
| `weight` | float | `0.17` | `0.03` – `0.5` | Stroke weight — As a fraction of a cell. Past about 0.35 the strokes meet their neighbours and the negative space becomes the pattern. |
| `density` | float | `0.82` | `0.05` – `1` | Filled cells — How often a cell gets a glyph at all. The empty ones are what give the grid somewhere to breathe. |
| `panel` | float | `0.22` | `0` – `1` | Coloured panels — How often a cell gets a filled ground under its glyph. These clump into fields and give the composition a scale larger than one tile. |
| `panel_alpha` | float | `0.5` | `0.05` – `1` | Panel opacity |
| `background` | enum | `paper` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `split` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `6` | `2` – `12` | Palette size |
| `grain` | float | `0.012` | `0` – `0.08` | Grain |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.tiles?width=1000&height=1000&tiles=12' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.tiles?width=1000&height=1000&tiles=12&format=png'
```

#### `images.strata` — Strata

Band heights from a Dirichlet draw, colours walking a palette.

| | |
|---|---|
| **Key** | `images.strata` |
| **Module** | `images` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `image/png` |
| **Studio** | https://randomly.cluxnei.dev/g/images/strata |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/images.strata` |

`value` is a **render spec** — algorithm, parameters, palette and a render key — not pixels. Ask for `format=png` to get the image.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `width` | int | `1000` | `256` – `2048` | Width |
| `height` | int | `1300` | `256` – `2048` | Height |
| `bands` | int | `22` | `2` – `70` | Bands |
| `concentration` | float | `0.85` | `0.15` – `6` | Dirichlet α — Below 1, a few bands take almost everything and the rest are hairlines. At 1 the heights are as unstructured as heights can be. Above 3 they all converge on the same thickness, which is a colour chart rather than a cliff. |
| `roughness` | float | `0.05` | `0` – `0.3` | Boundary wander — How far a boundary strays from its nominal height, as a fraction of the canvas. Zero draws a bar chart; this is the single control that makes it rock. |
| `frequency` | float | `2.6` | `0.3` – `12` | Wander scale — How many undulations fit across the canvas. |
| `octaves` | int | `4` | `1` – `7` | Boundary detail — Octaves in the noise displacing each boundary. One is a smooth wave; more adds the fine crumbling of a real edge. |
| `tilt` | float | `0.05` | `0` – `0.35` | Tilt — A linear slope added to each boundary, drawn independently per band — so the stack shears the way tilted bedding does. |
| `shade` | float | `0.07` | `-0.25` – `0.25` | Within-band shading — How far along the palette a band travels between its own top and bottom. Flat fills read as coloured strips; a gradient reads as a surface with light on it. |
| `walk` | float | `0.11` | `0.01` – `0.5` | Colour step — How far the colour moves between one band and the next. Small steps keep neighbouring layers related, which is what makes the stack read as one formation. |
| `background` | enum | `ink` | `ink`, `ground`, `paper`, `palette` | Ground |
| `palette` | enum | `magma` | `golden`, `analogous`, `complementary`, `triadic`, `split`, `viridis`, `magma`, `mono` | Colour |
| `colours` | int | `8` | `2` – `12` | Palette size |
| `grain` | float | `0.02` | `0` – `0.1` | Grain — Film grain over the finished render. Strata want more of it than most things here — flat coloured areas are exactly where 8-bit output shows its seams. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/images.strata?width=1000&height=1300&bands=22' -H 'Accept: text/plain'
curl -o out.png 'https://randomly.cluxnei.dev/api/v1/g/images.strata?width=1000&height=1300&bands=22&format=png'
```

### Audio

Noise colours, Euclidean rhythms and strings plucked out of static.

#### `audio.noise` — Noise Colours

White, pink, brown, blue, violet — and perceptually flat grey.

| | |
|---|---|
| **Key** | `audio.noise` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/noise |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.noise` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `colour` | enum | `pink` | `white`, `pink`, `brown`, `blue`, `violet`, `grey` | Colour — A colour is a spectral slope. The measured slope is printed under the waveform. |
| `duration` | float | `10` | `2` – `30` | Length (seconds) — Kept short on purpose — with Loop on, the buffer is crossfaded into itself and plays forever. |
| `loop` | bool | `true` | `true`, `false` | Loop — Seamless: the tail is crossfaded onto the head, so there is no click at the seam. |
| `filter` | enum | `none` | `none`, `lowpass`, `highpass`, `bandpass` | Filter |
| `cutoff` | float | `1200` | `60` – `16000` | Cutoff (Hz) |
| `resonance` | float | `0.7` | `0.4` – `8` | Resonance (Q) — Above about 4 the filter starts to ring, which turns noise into a pitch. |
| `movement` | float | `0.3` | `0` – `1` | Movement — How far the cutoff drifts over the loop. A little of this is the difference between a hiss and something that sounds like weather. |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.noise?colour=pink&duration=10&loop=1' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.noise?colour=pink&duration=10&loop=1&format=wav'
```

#### `audio.rhythm` — Euclidean Rhythm

k onsets spread as evenly as possible across n steps — which is most of the world’s rhythms.

| | |
|---|---|
| **Key** | `audio.rhythm` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/rhythm |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.rhythm` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `k` | int | `3` | `1` – `16` | Onsets (k) — How many hits. k=3, n=8 is the tresillo; the panel names the pattern whenever it recognises one. |
| `n` | int | `8` | `2` – `16` | Steps (n) |
| `rotation` | int | `0` | `0` – `15` | Rotation — Which step becomes the downbeat. Same onsets, different rhythm — this is what separates the cinquillo from the son clave. |
| `layers` | int | `3` | `1` – `4` | Layers — Layer one is yours. The rest draw their own k and n, which is where the polyrhythm comes from. |
| `tempo` | float | `110` | `50` – `200` | Tempo (BPM) |
| `bars` | int | `4` | `1` – `16` | Bars |
| `swing` | float | `0` | `0` – `0.6` | Swing — Delays every second step. At 0.33 the steps land in triplet time, which is where swing comes from. |
| `kit` | enum | `acoustic` | `acoustic`, `electronic`, `wood` | Kit |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.rhythm?k=3&n=8&rotation=0' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.rhythm?k=3&n=8&rotation=0&format=wav'
```

#### `audio.melody` — Melody

Random walk, Markov, or the 1/f kind that sounds written — on a scale that cannot clash.

| | |
|---|---|
| **Key** | `audio.melody` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/melody |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.melody` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `scale` | enum | `pentatonic_major` | `pentatonic_major`, `pentatonic_minor`, `major`, `minor`, `dorian`, `phrygian`, `lydian`, `mixolydian`, `blues`, `whole_tone`, `hirajoshi` | Scale — The one control that decides whether random notes sound musical. Pentatonic has no semitone in it to clash with. |
| `root` | enum | `C` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Root |
| `octave` | int | `4` | `2` – `5` | Octave — Octave 4 is middle C. |
| `range` | int | `2` | `1` – `3` | Range (octaves) |
| `method` | enum | `walk` | `walk`, `uniform`, `markov`, `voss` | Method — Switch between these on the same seed. Uniform is aimless, the walk has contour, Markov has phrasing, 1/f sits where real music sits. |
| `order` | int | `2` | `1` – `2` | Markov order — Only used by the Markov method. Order 1 is a word salad of intervals; order 2 starts quoting whole phrases. |
| `bars` | int | `8` | `1` – `16` | Bars |
| `tempo` | float | `100` | `50` – `180` | Tempo (BPM) |
| `rate` | enum | `1` | `0.5`, `1`, `2`, `4` | Note length |
| `rests` | float | `0.15` | `0` – `0.5` | Rests — How often a note is left out. A melody with no silence in it has no phrases in it. |
| `engine` | enum | `fm` | `fm`, `additive`, `subtractive`, `sine` | Engine |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.melody?scale=pentatonic_major&root=C&octave=4' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.melody?scale=pentatonic_major&root=C&octave=4&format=wav'
```

#### `audio.pluck` — Plucked Strings

Karplus–Strong: fill a delay line with pure noise and a guitar comes out.

| | |
|---|---|
| **Key** | `audio.pluck` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/pluck |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.pluck` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `scale` | enum | `pentatonic_minor` | `pentatonic_major`, `pentatonic_minor`, `major`, `minor`, `dorian`, `phrygian`, `lydian`, `mixolydian`, `blues`, `whole_tone`, `hirajoshi` | Scale |
| `root` | enum | `A` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Root |
| `octave` | int | `3` | `1` – `5` | Octave |
| `range` | int | `2` | `1` – `3` | Range (octaves) |
| `density` | int | `4` | `1` – `12` | Notes per bar |
| `bars` | int | `8` | `1` – `16` | Bars |
| `tempo` | float | `92` | `50` – `180` | Tempo (BPM) |
| `sustain` | float | `0.55` | `0` – `1` | Sustain — How much of the loop survives each lap. Past about 0.9 the string stops being a string and becomes a drone. |
| `brightness` | float | `0.6` | `0` – `1` | Brightness — Where the string is plucked. Near the bridge is bright and thin; over the fretboard is round and dark. |
| `spread` | float | `0.7` | `0` – `1` | Stereo spread — How far across the image the notes are placed. Strings recorded close are never all in the same spot. |
| `chords` | float | `0.18` | `0` – `0.6` | Double stops — How often two strings are struck at once. |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.pluck?scale=pentatonic_minor&root=A&octave=3' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.pluck?scale=pentatonic_minor&root=A&octave=3&format=wav'
```

#### `audio.chord` — Chord Progressions

A functional-harmony transition matrix, not a random draw — so it sounds written.

| | |
|---|---|
| **Key** | `audio.chord` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/chord |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.chord` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `root` | enum | `C` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Key |
| `mode` | enum | `major` | `major`, `minor` | Mode |
| `octave` | int | `3` | `2` – `4` | Octave |
| `bars` | int | `8` | `4` – `16` | Bars — One chord per bar. The last two are the cadence and are not drawn from the chain. |
| `tempo` | float | `84` | `40` – `140` | Tempo (BPM) |
| `voicing` | enum | `close` | `close`, `open`, `seventh`, `spread` | Voicing |
| `instrument` | enum | `pad` | `pad`, `piano`, `organ`, `strings` | Instrument |
| `sevenths` | bool | `false` | `true`, `false` | Sevenths — Adds the fourth chord tone. Turns a hymn into something closer to jazz without changing a single root. |
| `bass` | bool | `true` | `true`, `false` | Bass note |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.chord?root=C&mode=major&octave=3' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.chord?root=C&mode=major&octave=3&format=wav'
```

#### `audio.drone` — Drone

Detuned partials, beating slowly against each other.

| | |
|---|---|
| **Key** | `audio.drone` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/drone |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.drone` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `root` | enum | `A` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Root |
| `octave` | int | `2` | `1` – `4` | Octave — Low is the point. A drone an octave up stops being a floor and starts being a note. |
| `partials` | int | `5` | `2` – `10` | Partials — Harmonics above the root: f, 2f, 3f and so on. Each one is a pair of sines, slightly apart. |
| `beating` | float | `0.4` | `0.05` – `8` | Beat rate (Hz) — How often each pair swells, in beats per second. Under 1 Hz it breathes; past 4 it turns into a rattle. |
| `movement` | float | `0.4` | `0` – `1` | Movement — How far the partials drift in level and the filter in cutoff over the piece. At zero it is completely static, which is its own kind of useful. |
| `tilt` | float | `0.45` | `0` – `1` | Brightness — How much of the upper harmonics survives. Dark is a cello section; bright is an organ with every stop out. |
| `spread` | float | `0.8` | `0` – `1` | Stereo spread — The two halves of each beating pair are placed on opposite sides, so the swell moves across the image instead of sitting in the middle. |
| `duration` | float | `30` | `8` – `90` | Length (seconds) |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.drone?root=A&octave=2&partials=5' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.drone?root=A&octave=2&partials=5&format=wav'
```

#### `audio.bleep` — UI Sounds

Success, error, notify, coin — as a downloadable pack.

| | |
|---|---|
| **Key** | `audio.bleep` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/bleep |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.bleep` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `category` | enum | `mixed` | `mixed`, `success`, `error`, `notify`, `coin` | Category |
| `count` | int | `6` | `1` – `16` | Sounds in the pack |
| `root` | enum | `C` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Key — Interface sounds share a room with each other. Pinning them to one key is why a set feels like a set. |
| `octave` | int | `5` | `3` – `6` | Octave — High is the point: small speakers roll off below about 500 Hz, so a bleep an octave down is a bleep nobody hears. |
| `brightness` | float | `0.5` | `0` – `1` | Brightness — Moves the waveform from a pure sine towards a square. Sine is soft and modern; square is a games console. |
| `length` | float | `0.5` | `0.2` – `1` | Length — Scales every sound. Short is confident — an interface sound that outlasts the action it confirms feels slow. |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.bleep?category=mixed&count=6&root=C' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.bleep?category=mixed&count=6&root=C&format=wav'
```

#### `audio.ambient` — Generative Ambient

A mood preset that evolves and never repeats.

| | |
|---|---|
| **Key** | `audio.ambient` |
| **Module** | `audio` |
| **Version** | `1` — a permalink carries this, and a replay against a different version returns `409` rather than something else |
| **Formats** | `application/json`, `text/plain`, `audio/wav` |
| **Studio** | https://randomly.cluxnei.dev/g/audio/ambient |
| **API** | `GET https://randomly.cluxnei.dev/api/v1/g/audio.ambient` |

`value` is a **score** — events, envelopes and synthesis parameters — not samples. Ask for `format=wav` to get the audio.

| Parameter | Type | Default | Accepts | What it does |
|---|---|---|---|---|
| `mood` | enum | `glacier` | `glacier`, `dusk`, `rainfall`, `orbit` | Mood |
| `root` | enum | `D` | `C`, `C#`, `D`, `D#`, `E`, `F`, `F#`, `G`, `G#`, `A`, `A#`, `B` | Root |
| `duration` | float | `60` | `20` – `150` | Length (seconds) — Bounded on purpose: the browser renders every sample before it plays anything. Loop it and the fades hide the seam. |
| `density` | float | `14` | `0` – `60` | Notes per minute — How often a single note falls over the pads. Zero leaves the chords and the floor alone, which is the version to work to. |
| `bed` | float | `1` | `0` – `2` | Floor — Scales the noise layer. Past 1 the piece becomes weather with chords in it rather than the other way round. |
| `spread` | float | `0.7` | `0` – `1` | Stereo spread |
| `movement` | float | `0.5` | `0` – `1` | Movement — How far the filter over the floor drifts across the piece. It is most of what makes the thing sound alive rather than held. |
| `volume` | float | `-12` | `-36` – `0` | Volume (dBFS) — Where the mix sits before the master limiter. 0 dBFS is full scale; everything starts 12 dB below it. |

Out-of-range numbers are **clamped, not rejected**, so a request never fails for being
ambitious — but it may not do what you meant. Unknown keys are dropped and missing ones
fall back to the defaults above.

```bash
curl -s 'https://randomly.cluxnei.dev/api/v1/g/audio.ambient?mood=glacier&root=D&duration=60' -H 'Accept: text/plain'
curl -o out.wav 'https://randomly.cluxnei.dev/api/v1/g/audio.ambient?mood=glacier&root=D&duration=60&format=wav'
```

## Attribution

This project stands on work it did not pay for and could not have afforded: RANDOM.ORG,
the Australian National University, NIST, the League of Entropy, mempool.space, the USGS,
NOAA, Open-Meteo, Open Notify, Wikipedia, GBIF, and the EFF's Diceware wordlists
(CC BY 3.0 US). Not one of them charges. Not one asked for a key. Every one of them could
have. The full list, with licences, is at [https://randomly.cluxnei.dev/credits](https://randomly.cluxnei.dev/credits).

If you build on this API, crediting the entropy source named in the receipt is the thing
worth doing — it is the source, not this site, that makes the claim checkable.

- [Source code](https://github.com/Cluxnei/randomly)
- [Index](https://randomly.cluxnei.dev/llms.txt)
- [API contract alone](https://randomly.cluxnei.dev/api.md)
