Utility

Random Generator

True randomness via crypto.getRandomValues(). Numbers, dice, coins, lists.

History
Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

// ── Utilities ──────────────────────────────────
  function cryptoRandInt(min, max) {
    // Returns integer in [min, max] inclusive
    const range = max - min + 1;
    const bytes = new Uint32Array(1);
    const maxUnbiased = Math.floor(0xFFFFFFFF / range) * range;
    do {
      crypto.getRandomValues(bytes);
    } while (bytes[0] > maxUnbiased);
    return min + (bytes[0] % range);
  }

  function cryptoShuffle(arr) {
    const a = [...arr];
    for (let i = a.length - 1; i > 0; i--) {
      const j = cryptoRandInt(0, i);
      [a[i], a[j]] = [a[j], a[i]];
    }
    return a;
  }

  // ── Tabs ──────────────────────────────────────
  document.querySelectorAll('.tab').forEach(t => {
    t.addEventListener('click', () => {
      document.querySelectorAll('.tab').forEach(x => x.classList.remove('active'));
      ['number','dice','coin','list'].forEach(id => document.getElementById(`tab-${id}`).classList.add('hidden'));
      t.classList.add('active');
      document.getElementById(`tab-${t.dataset.tab}`).classList.remove('hidden');
    });
  });

  // ── NUMBER ────────────────────────────────────
  let numHistory = [];

  document.getElementById('numGenBtn').addEventListener('click', generateNumbers);
  document.addEventListener('keydown', e => { if (e.key === 'Enter' && !document.getElementById('tab-number').classList.contains('hidden')) generateNumbers(); });

  function generateNumbers() {
    const min = parseInt(document.getElementById('numMin').value) || 0;
    const max = parseInt(document.getElementById('numMax').value) || 100;
    const count = Math.min(Math.max(parseInt(document.getElementById('numCount').value) || 1, 1), 1000);
    const noDupes = document.getElementById('noDupes').checked;

    if (min > max) {
      document.getElementById('numBigResult').textContent = 'Min > Max';
      return;
    }

    let nums = [];
    if (noDupes) {
      const range = max - min + 1;
      if (count > range) {
        document.getElementById('numBigResult').textContent = 'Not enough unique values';
        return;
      }
      const pool = Array.from({length: range}, (_, i) => min + i);
      const shuffled = cryptoShuffle(pool);
      nums = shuffled.slice(0, count);
    } else {
      for (let i = 0; i < count; i++) nums.push(cryptoRandInt(min, max));
    }

    const bigResult = document.getElementById('numBigResult');
    const multiGrid = document.getElementById('numMultiGrid');

    if (count === 1) {
      bigResult.textContent = nums[0];
      bigResult.classList.remove('hidden');
      multiGrid.classList.add('hidden');
    } else {
      bigResult.classList.add('hidden');
      multiGrid.classList.remove('hidden');
      multiGrid.innerHTML = nums.map(n => `<div class="multi-num">${n}</div>`).join('');
    }

    const histEntry = count === 1 ? nums[0] : `[${nums.slice(0,5).join(', ')}${nums.length > 5 ? '…' : ''}]`;
    numHistory.unshift(histEntry);
    if (numHistory.length > 10) numHistory.pop();
    renderNumHistory();
  }

  function renderNumHistory() {
    const el = document.getElementById('numHistory');
    if (!numHistory.length) { el.innerHTML = '<span style="color:var(--muted);font-size:12px;">No history yet</span>'; return; }
    el.innerHTML = numHistory.map(h => `<span class="history-item">${h}</span>`).join('');
  }
  renderNumHistory();

  // ── DICE ──────────────────────────────────────
  let selectedDie = 6;
  const D6_FACES = ['⚀','⚁','⚂','⚃','⚄','⚅'];

  document.querySelectorAll('.dice-btn').forEach(b => {
    b.addEventListener('click', () => {
      document.querySelectorAll('.dice-btn').forEach(x => x.classList.remove('active'));
      b.classList.add('active');
      selectedDie = parseInt(b.dataset.d);
    });
  });

  document.getElementById('rollBtn').addEventListener('click', rollDice);

  function rollDice() {
    const count = Math.min(Math.max(parseInt(document.getElementById('diceCount').value) || 1, 1), 10);
    const results = Array.from({length: count}, () => cryptoRandInt(1, selectedDie));
    const container = document.getElementById('diceResults');
    const totalWrap = document.getElementById('diceTotalWrap');
    const total = results.reduce((a, b) => a + b, 0);

    container.innerHTML = results.map((r, i) => {
      let face = r;
      if (selectedDie === 6) face = D6_FACES[r - 1];
      return `<div class="die-face rolling" id="die${i}">${face}</div>`;
    }).join('');

    document.getElementById('diceTotal').textContent = total;
    totalWrap.classList.remove('hidden');
  }

  // ── COIN ──────────────────────────────────────
  let coinFlips = [];
  let streak = 0;
  let lastSide = null;

  document.getElementById('coinBtn').addEventListener('click', flipCoin);

  function flipCoin() {
    const coin = document.getElementById('coinEl');
    coin.classList.remove('flip-anim');
    void coin.offsetWidth;
    coin.classList.add('flip-anim');

    setTimeout(() => {
      const isHeads = cryptoRandInt(0, 1) === 1;
      const side = isHeads ? 'H' : 'T';

      if (side === lastSide) { streak++; } else { streak = 1; }
      lastSide = side;

      document.getElementById('coinResult').textContent = isHeads ? 'HEADS' : 'TAILS';
      document.getElementById('coinResult').className = 'coin-result' + (isHeads ? ' heads' : '');
      coin.textContent = isHeads ? '🌕' : '🌑';

      const streakEl = document.getElementById('coinStreak');
      streakEl.textContent = `Streak: ${streak} × ${side === 'H' ? 'HEADS' : 'TAILS'}`;

      coinFlips.unshift(side);
      if (coinFlips.length > 20) coinFlips.pop();
      renderCoinHistory();
    }, 250);
  }

  function renderCoinHistory() {
    const el = document.getElementById('coinHistory');
    el.innerHTML = coinFlips.map(f => `<div class="coin-hist-item ${f === 'H' ? 'h' : ''}">${f}</div>`).join('');
  }

  // ── LIST ──────────────────────────────────────
  document.getElementById('listPickBtn').addEventListener('click', pickFromList);
  document.getElementById('listShuffleBtn').addEventListener('click', shuffleList);

  function getListItems() {
    return document.getElementById('listInput').value.split('\n').map(s => s.trim()).filter(Boolean);
  }

  function pickFromList() {
    const items = getListItems();
    if (!items.length) return;
    const n = Math.min(Math.max(parseInt(document.getElementById('listPickN').value) || 1, 1), items.length);
    const picked = cryptoShuffle(items).slice(0, n);
    renderListResults(picked, true);
  }

  function shuffleList() {
    const items = getListItems();
    if (!items.length) return;
    renderListResults(cryptoShuffle(items), false);
  }

  function renderListResults(items, highlight) {
    document.getElementById('listResults').innerHTML = items.map((item, i) =>
      `<div class="list-result-item"><span class="idx">${i + 1}</span>${escHtml(item)}</div>`
    ).join('');
  }

  function escHtml(s) {
    return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  }