Why this matters
If players can't audit your shuffle, they have to trust your server. With one batched API call and a few lines of Fisher-Yates, the same shuffle becomes reproducible — anyone with the seed can recompute the deck.
Step 1: build the deck
const SUITS = ["♠", "♥", "♦", "♣"];
const RANKS = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];
function freshDeck() {
const deck = [];
for (const s of SUITS) for (const r of RANKS) deck.push(r + s);
return deck; // 52 cards
}
Step 2: pull all the swap indices in one request
Fisher-Yates needs 51 random integers — one per swap. Grab them in a single call with count=51; each index i needs a number in [0, i], so request the widest range and modulo down.
async function getSwapIndices(clientSeed, n = 51) {
const url = new URL("https://api.provable.io/api/ints");
url.searchParams.set("clientSeed", clientSeed);
url.searchParams.set("count", String(n));
url.searchParams.set("min", "0");
url.searchParams.set("max", "1000000");
const res = await fetch(url, {
headers: { "x-api-key": process.env.PROVABLE_KEY }
});
return (await res.json()).outcome;
}
Step 3: Fisher-Yates with the API's numbers
async function shuffleDeck(clientSeed) {
const deck = freshDeck();
const rands = await getSwapIndices(clientSeed, deck.length - 1);
for (let i = deck.length - 1; i > 0; i--) {
const j = rands[deck.length - 1 - i] % (i + 1);
[deck[i], deck[j]] = [deck[j], deck[i]];
}
return deck;
}
const hand = (await shuffleDeck("hand_2026_05_24_table_7")).slice(0, 5);
console.log(hand); // e.g. ["Q♦","7♠","2♣","K♥","9♦"]
Make it verifiable
- Publish the
serverHashfor the seed before the hand starts. - Reveal the
clientSeed(or let the player pick it). - Anyone can re-run the same Fisher-Yates code with the same numbers and confirm the deck.
Tips for production
- Use a different
clientSeedper hand (e.g. a hand ID) so each shuffle is independent. - For multi-deck games, request
count = decks * 52 - 1swap indices in one go. - The modulo bias from
% (i + 1)is negligible because the source range (1,000,001 values) is many orders of magnitude larger than 52.