Utility
Random Generator
True randomness via crypto.getRandomValues(). Numbers, dice, coins, lists.
—
History
Dice Type
Press Roll to begin
TOTAL
🪙
—
Last 20 flips
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,'&').replace(/</g,'<').replace(/>/g,'>');
}