← Back to Blog

How Digital Tarot Apps Shuffle Cards (And Why Most Get It Wrong)

By Michael Wylde · March 28, 2026 · 8 min read

You open a tarot app. You tap "shuffle." An animation plays -- cards swirl, flutter, rearrange themselves on screen. A moment later, your spread appears. The Tower. The Star. The Nine of Swords. It feels meaningful. It feels random. But what actually happened in the fraction of a second between your tap and the result?

The answer, for the vast majority of tarot apps, is something far less mysterious than the cards themselves. And understanding it changes how you think about digital readings entirely.

What Math.random() Actually Does

Nearly every tarot app on the market shuffles its deck using a single JavaScript function: Math.random(). This function returns a decimal number between 0 and 1 -- something like 0.7291638402 -- and the app uses it to determine card positions. Call it 78 times, sort the deck by those values, and you have a "shuffled" deck.

The problem is what Math.random() does under the hood. In Google Chrome and most Chromium-based browsers, it uses an algorithm called xorshift128+. In older engines, you might encounter the Mersenne Twister, a different algorithm with similar properties. Both are pseudo-random number generators -- PRNGs -- and both share a critical characteristic: they are entirely deterministic.

A PRNG works like this: it starts with an internal state (a seed), applies a mathematical transformation to that state, outputs a number, and updates the state for next time. The sequence of numbers it produces is fixed from the moment the seed is set. It is not random. It is a very long, very complicated pattern -- but a pattern nonetheless. Given the seed, you could predict every number the generator will ever produce, from the first to the trillionth.

A pseudo-random number generator does not generate randomness. It redistributes the randomness that was present in its seed -- and if that seed came from a clock, there was very little randomness to begin with.

For most software engineering tasks, this is perfectly adequate. Games need numbers that look random to players. Simulations need statistical distributions that match theoretical models. PRNGs deliver both. But tarot is not a simulation. And the question of whether your shuffle is genuinely unpredictable is not an academic one.

The Seed Problem

Where does the seed come from? In most environments, Math.random() is seeded from the system clock or a similar low-entropy source when the JavaScript engine initializes. This means the entire sequence of "random" numbers your tarot app will ever generate is determined by what time it was when the page loaded.

Consider the implications. If two people on opposite sides of the world open the same tarot app at the same millisecond -- and the app seeds its PRNG from the system clock -- they will get the exact same sequence of numbers. The exact same shuffle. The exact same reading. Not similar readings. Identical ones.

In practice, millisecond-level collisions are rare. But the deeper issue is not about collisions. It is about the nature of the shuffle itself. Your reading was not shaped by anything about you, your question, or your moment. It was shaped by a clock. The "shuffle" was decided before you ever touched the screen.

Why "Random Enough" Is Not Random

Developers sometimes push back on this concern. "It passes all the statistical tests," they say. "The distribution is uniform. You cannot distinguish the output from true randomness without knowing the algorithm." This is true -- and it misses the point.

The output of a good PRNG is statistically indistinguishable from randomness. But it is philosophically the opposite of randomness. A deterministic sequence that looks random is still deterministic. The cards were decided before you drew them. The future was already written. The shuffle is a performance -- an animation played over a predetermined outcome.

For a card game or a data visualization, this distinction is irrelevant. For a practice built on the belief that the cards you draw are meaningful precisely because they could have been any cards -- it is everything.

Cryptographic Randomness: Better, but Not Enough

Some more technically sophisticated apps use crypto.getRandomValues(), the browser's cryptographically secure random number generator (CSPRNG). This is a significant step up. A CSPRNG draws from the operating system's entropy pool -- a reservoir of randomness collected from hardware interrupts, disk timing, network packet arrival times, and other physical events.

This is genuinely better. The numbers produced by a CSPRNG are not predictable from a seed in the way a PRNG's are. They are considered secure enough for encryption keys, session tokens, and other security-critical applications.

But there is a subtlety that matters. The OS entropy pool is finite. It collects physical randomness passively, in the background, and stores it. When an application requests random bytes, the pool is drained. If many applications request randomness simultaneously, or if the system has been running in a low-activity state, the pool can run low. At that point, the CSPRNG falls back on algorithmic stretching -- using the entropy it has to generate more numbers than the entropy strictly supports.

Moreover, the entropy that feeds the OS pool is incidental. It comes from whatever the computer happens to be doing -- handling interrupts, writing to disk, receiving packets. It is not intentionally harvested. It is not connected to the person requesting the reading. It is operating system bookkeeping, repurposed as randomness.

Cryptographic randomness is secure enough that no one can predict your reading. But it is not the same as randomness that comes from you, your device, your moment.

What Entropic Tarot Does Differently

Entropic Tarot was designed from the ground up to solve this problem. Instead of relying on system-provided randomness, it actively harvests physical entropy from three sensors on your device at the moment you request a reading.

The microphone captures electromagnetic fluctuations in ambient noise -- the raw hiss of the analog circuitry, which is driven by thermal noise at the quantum level. The camera captures thermal noise from electron excitations in the CMOS sensor's silicon -- the same phenomenon that creates grain in low-light photography. Touch timing captures the microsecond-level jitter in when your finger contacts the screen, shaped by your unique neuromuscular patterns.

These three streams of raw physical data are then combined through SHA-256, a cryptographic hash function. SHA-256 is a one-way compression function: it takes any amount of input data and produces a fixed 256-bit output. Critically, it eliminates any biases or patterns in the input. Even if one sensor produces slightly skewed data, the hash output is statistically uniform. The result is 256 bits of pure, physically-derived entropy.

But the process does not stop there. Those 256 bits feed into HMAC-DRBG -- a deterministic random bit generator standardized by NIST (the National Institute of Standards and Technology). HMAC-DRBG is the same algorithm used to generate cryptographic keys in banking and government systems. Seeded with true physical entropy, it can produce as many high-quality random bytes as the shuffle algorithm needs.

Fisher-Yates with Rejection Sampling

The shuffle itself uses the Fisher-Yates algorithm, the gold standard for producing an unbiased permutation. Fisher-Yates works by iterating through the deck from the last card to the first, swapping each card with a randomly selected card from the remaining positions. When implemented correctly with a uniform random source, it guarantees that every possible ordering of the deck is equally likely.

But "uniform random source" hides a subtle trap. When you need a random number between 0 and 77 (to pick a position in a 78-card deck), and your random source gives you a fixed number of bits, there is almost always a slight bias. If you generate a random byte (0 to 255) and take the remainder when dividing by 78, some positions will be very slightly more likely than others. This is called modulo bias.

For a single card draw, the bias is negligible. But across a full 78-card shuffle, these tiny biases compound. Certain deck orderings become slightly more probable than others. The shuffle is no longer perfectly uniform.

Entropic Tarot eliminates this with rejection sampling. When the algorithm needs a random number in a range that does not evenly divide the random source's output, it simply discards values that would introduce bias and draws again. This costs a small amount of extra entropy, but guarantees that the resulting selection is perfectly uniform -- no position in the deck is favored by even a fraction of a fraction of a percent.

Rejection sampling is the difference between a shuffle that is almost fair and one that is provably, mathematically perfect.

78 Factorial: A Number Beyond Comprehension

Why does all of this precision matter? Because the space of possible tarot shuffles is staggeringly vast.

A standard tarot deck has 78 cards. The number of possible orderings is 78! (78 factorial) -- 78 multiplied by 77 multiplied by 76, all the way down to 1. This number is approximately 1.89 x 10^115.

To put that in perspective: the estimated number of atoms in the observable universe is roughly 10^80. The number of possible tarot shuffles exceeds that by a factor of 10^35 -- a number so large it has no physical analogy. There are more ways to arrange a tarot deck than there are atoms in a trillion trillion trillion universes.

A PRNG seeded from a millisecond clock has, at most, a few billion possible seeds. That means it can only ever produce a few billion of those 10^115 possible shuffles. The overwhelming majority of deck orderings are inaccessible -- not just unlikely, but literally impossible for the algorithm to produce.

A 256-bit entropy source can address 2^256 (approximately 1.16 x 10^77) possible states. While this is still a tiny fraction of 78!, it is astronomically larger than a PRNG's state space -- and when combined with HMAC-DRBG's expansion, it provides more than enough entropy to make every shuffle genuinely unique for the lifetime of the universe.

The Difference That Matters

There is a spectrum of randomness quality in digital tarot, and most apps sit at the lowest end of it:

  1. PRNG from system clock -- deterministic, predictable, a tiny fraction of possible shuffles accessible. This is where most apps live.
  2. CSPRNG from OS entropy pool -- unpredictable but passive, not connected to the user or the moment. Better, but impersonal.
  3. Physical entropy from device sensors -- harvested in real-time from the physical world around and including the person requesting the reading. This is what Entropic Tarot provides.

The difference is not just technical. It is about what the shuffle means. When the randomness comes from your microphone picking up the electromagnetic signature of your room, your camera capturing thermal noise from the silicon in your hand, and the precise microsecond your finger touched glass -- the reading is grounded in your physical reality. It emerged from the same material world you inhabit. It is not a number a formula was always going to produce.

There is a phrase that gets used casually in software development: "random enough." Random enough for what? For a game, any PRNG will do. For encryption, you need a CSPRNG. For tarot -- for a practice that asks you to trust that the cards you drew are the cards you were meant to draw -- "random enough" is not a technical specification. It is a question about what you believe randomness is.

The difference between a shuffle that looks random and one that is random is the difference between a performance and a phenomenon. One is scripted. The other is real.

Entropic Tarot was built for people who want the real one.

Try Entropic Tarot — Free tarot readings powered by true physical entropy →