RIFFLE
How it was made

Seven shuffles to forget the order.

RIFFLE is a fictional teaching piece for anyone who has ever wondered how many shuffles a deck really needs. It deals fifty-two cards in perfect sequence, then riffle-shuffles them in real time — cut, interleave, settle — while a single readout tracks how much order is left.

Its one job: to make the Bayer–Diaconis theorem physical. Seven riffle shuffles are enough to randomise a deck, and no fewer will do. You watch a clean colour gradient come apart into noise, and a rising-sequences count climb its doubling curve up to the flat line of pure chance.

React Three Fiberdrei Instances Gilbert–Shannon–ReedsRising sequences OrbitControls

01The palette

Every colour is argued from a card table under low light. The cards themselves carry the whole story: each of the fifty-two is tinted along a ramp from ivory at rank one to suit-red at rank fifty-two, passing through the tan of a worn card edge. Sorted, the deck is a smooth sweep of that ramp; shuffled, it is speckled noise. Order and chaos are literally a colour gradient breaking up.

#132018
Card table
Deep baize green, the felt every card falls onto.
#EDE6D6
Ivory · body ink
Rank-one card face and the readable body text — high contrast on the felt.
#C9B79A
Card edge · line/mark
The worn tan of a card's edge. Reserved for rules, dividers and marks — never small text.
#B5402E
Suit accent
Heart-and-diamond red at the far end of the rank ramp; the randomness figure.

Following the collection's ink/line rule, the bright edge tone #C9B79A is used only for lines and marks. Body copy takes the ivory #EDE6D6, which clears 4.5:1 on the dark baize, with a muted #C4BBA6 for secondary lines of text.

02The type

Fraunces
Display · headings
A warm, high-contrast serif with an old-style, almost hand-cut feel — the voice of a lecture-hall demonstration. Set at large optical sizes so the flourish reads. The italic carries the word forget.
Space Mono
Mono · readouts
A monospace with character for the counts, percentages and the sortedness panel. Fixed advance keeps the rising-sequence figure from jittering as it climbs, shuffle to shuffle.

03The signature

The scene is built with React Three Fiber — the declarative React renderer for three.js — loaded through an ES-module importmap from esm.sh, with no build step. The fifty-two cards are a single instanced mesh via drei's <Instances> / <Instance>, each card holding a fixed colour from the rank ramp; only positions animate. Markup is written with htm tagged templates bound to React.createElement, so there is no JSX transform to compile.

Each shuffle runs the true Gilbert–Shannon–Reeds riffle model. The deck is cut binomially — every card is assigned to the top or bottom packet by a fair coin — then the two packets are interleaved by dropping the next card from each with probability proportional to how many it still holds. Cards lift, split into two depth planes, and cascade left-to-right into their new slots.

The meter counts rising sequences: maximal runs of cards still in ascending order. A sorted deck has exactly one; a uniformly random deck has about twenty-six, i.e. (n+1)/2. Each riffle roughly doubles the count, and the sparkline plots that doubling curve saturating against the uniform plateau near the seventh shuffle — the theorem, drawn live. After seven, the deck re-deals into its clean gradient and the demonstration begins again.

Everything is guarded to the collection's quality floor: device-pixel-ratio capped at two, automatic resize, the render logic paused when the tab is hidden, a WebGL context-loss and no-WebGL fallback, and a settled static frame — the deck parked mid-third-shuffle — when the visitor prefers reduced motion.

04The iteration log

  1. Craft

    Verified the R3F importmap first: it needed explicit react/jsx-runtime and react/jsx-dev-runtime mappings before drei would resolve — added, and the stack then loaded with zero console errors, so RIFFLE ships as true React Three Fiber, not the vanilla fallback. Collapsed a duplicate <h1> to one, fixed a subject–verb slip in the hero copy, and rebuilt the sparkline labels so the plateau line and the 0–7 axis stopped colliding.

  2. Depth

    Stabilised the composition — the auto-orbiting camera was dragging the deck across the headline, so it was pinned to a fixed three-quarter angle with a left-hand scrim protecting the copy. Gave the shuffle a left-to-right cascade stagger so cards settle in sequence like a real riffle instead of moving in lockstep, and thickened the cards for more body under the key light. Second-read reward: the reset visibly re-deals the noise back into a clean colour gradient.

  3. Hardening

    Confirmed a clean 375px layout with no overflow, the panel reflowing full-width; verified the reduced-motion path renders a genuinely static settled frame (two screenshots hash-identical); checked focus-visible states and the auto-fit that scales the deck to any viewport. Chanel cut: removed the redundant masthead sub-tag so the wordmark and eyebrow carry the header alone.

← Back to RIFFLE