randarium.com: a local workbench for random data

all the good domain names were taken...

idk man its like 4 dots i guess. could be a dye.

I need random data constantly. A password for a zip file, a UUID for a flow_id or a thousand fake rows as dummy data. My habit used to be a rotation of single-purpose websites or a poorly maintaned common_commands.sh I keep on my machine, none of which agreed on how "random" should behave. So I built the one I wanted: randarium, a static site with 110-plus generators, passwords, tokens, datasets, cards, distributions, lists, that runs entirely in your browser. No server, no database, no account, and nothing you generate ever leaves the page.

Random Data Generators · Randarium

Random Data Generators · Randarium

The one-stop shop for random data: UUID, password, coin flip, dice roll, random number, list picker, lorem ipsum, colors, datasets and more. Runs locally in your browser — no server, no account, nothing uploaded.

Two kinds of random

The first thing you learn building a tool like this is that "random" isn't one thing. Sometimes you want the same randomness back, a seed you can share so a teammate gets your exact fake dataset. Sometimes you want randomness nobody can predict, because it's about to become a password.

randarium keeps these strictly separate behind a single Rng interface, with two implementations underneath. Seeded output is a deterministic PRNG (cyrb128 hashing the seed into 128 bits of state, fed into sfc32) that's byte-identical forever for a given seed. Secure output skips all of that and goes straight to the browser's crypto API:

/** Secure next(): 53-bit float from crypto. */
function secureNext(): number {
  const buf = new Uint32Array(2);
  crypto.getRandomValues(buf);
  const hi = buf[0] >>> 5; // 27 bits
  const lo = buf[1] >>> 6; // 26 bits
  return (hi * 67108864 + lo) / 9007199254740992; // / 2^53
}

Every derived helper, int, pick, shuffle, gaussian, is built on top of whichever next() is plugged in, so the split is total: generator code is never allowed to call Math.random() or crypto directly, only the injected Rng. Secure output is also structurally un-shareable, it never gets serialized into a recipe, a share link, or a URL, because the engine simply has no code path that does that. And there's an entropy calculator behind the scenes labeling output Weak/Moderate/Strong/Very strong, so "make it longer" isn't a guess. Even the small honesty touches are deliberate: the random-hash generator produces hex strings the exact length of an MD5 or SHA-256 digest, but it says so directly, synthetic test hashes, not real hashes of anything.

Wrapping Faker without losing control

The dataset generator (Synthetic Data Studio) is built on Faker.js, and Faker ships its own RNG and its own seeding. Left alone, that would have meant two incompatible notions of "reproducible" living in the same app, randarium's seed control wouldn't actually control Faker's output. So the wrapper overrides Faker's randomizer entirely:

export function buildLib(locale: string, rng: Rng): DataFactory {
  const chain = [localeDef(locale), allLocales.en, allLocales.base].filter(
    (l, i, a) => a.indexOf(l) === i,
  );
  return new DataFactory({
    locale: chain,
    // `seed()` is a no-op: the Rng is already seeded upstream.
    randomizer: { next: () => rng.next(), seed: () => {} },
  });
}

Every Faker call now draws from randarium's own seeded (or secure) Rng instead of its built-in generator, and seed() becomes a deliberate no-op, the seeding already happened one layer up. That also fixes a subtler bug: Faker's date.past/date.future are relative to Date.now() by default, which would make a "reproducible" dataset drift every time you regenerate it. The wrapper pins a reference date into every date call so seeded output stays stable regardless of when it runs. The field catalog itself, hundreds of Faker methods across dozens of locales, is auto-generated by introspecting Faker's TypeScript declarations with the compiler API, and dispatched by plain property-path lookup, never eval.

The same shared engine backs the numbers side of the site: 18-plus probability distributions and a Box–Muller gaussian() live right next to the entropy math, so "how strong is this password" and "what does a normal distribution look like" are answered by the same honest arithmetic instead of two different levels of rigor.

Built by a fleet of agents

Most of randarium was written by AI agents, and not in the vague "I used Claude Code" sense, there's an actual orchestration system. AGENTS.md is a full operating manual addressed directly to whichever model picks up the work, opening with lines like "you are not trusted to make architectural decisions." docs/DELEGATION.md describes the hierarchy: an Opus-class Orchestrator plans and reviews, Sonnet-class "Builder-M" agents take the medium-complexity generators, Haiku-class "Builder-E" agents churn through the templated easy ones, around 140 generators mapped to a tier in a model-assignment matrix, builders running in background worktrees so they can't collide, the Orchestrator resumed each time one finishes.

The whole stack was chosen with that in mind, not just for taste: React because it has the largest training corpus and is "safest for weak agents," strict TypeScript because types stop a weak agent from quietly breaking a contract, one package instead of a monorepo because it's simpler for an agent to reason about. It shows up in the git log too, commit trailers naming Claude Opus 4.8 and Claude Fable 5 as co-authors, over a dozen distinct session links, commit messages like "drafted by Sonnet, reviewed." It's less "AI helped me code" and more a small assembly line, and watching it actually hold together across 110+ generators without the codebase turning to mud was the interesting part.

Shipping on Cloudflare

It's a static Astro build, deployed to Cloudflare Pages, no Workers, no wrangler.toml, just Git push to deploy. Every push to main builds and goes live; every PR gets its own preview URL for free. GitHub Actions runs typecheck, lint, test, and build on every PR as the actual gate, and a green check there means Pages will build clean too. The one Cloudflare-specific wrinkle: Astro's default output is uuid/index.html, which meant an extra redirect hop on every page load; switching to build: { format: 'file' } emits uuid.html directly, so Cloudflare serves the slash-less URL with no redirect at all. Security headers (nosniff, frame-deny, HSTS) ride along in the same deploy via a plain _headers file, no extra pipeline needed.

Have a go

It's live at randarium.com. No install, no account, pick a generator, and if you need the exact same output again later, there's a seed for that; if you need it to actually be secret, there isn't.

Try and break it or let me know what generators I should add next.