Matthew James Taylor Matthew James Taylor

Web design ›

Boggle Dice Shaker (Built With Javascript)

3 Nov 2025

Boggle dice shaker

I've always loved playing Boggle but I don't own the game myself.

The only time I was ever able to play was at my friend's house. But not any more...

That's right, I have now built a Boggle dice shaker with Javascript that works in any web browser. Now all you need to play is an internet connection!

Just click the 'Shake it' button to start.

                               

So here's how it's made:

The HTML

I'm using custom HTML tags here because it just makes sense. See these articles for more details:

<boggle-tray class="shake">
    <boggle-dice id="dice0"> </boggle-dice>
    <boggle-dice id="dice1"> </boggle-dice>
    <boggle-dice id="dice2"> </boggle-dice>
    <boggle-dice id="dice3"> </boggle-dice>
    <boggle-dice id="dice4"> </boggle-dice>
    <boggle-dice id="dice5"> </boggle-dice>
    <boggle-dice id="dice6"> </boggle-dice>
    <boggle-dice id="dice7"> </boggle-dice>
    <boggle-dice id="dice8"> </boggle-dice>
    <boggle-dice id="dice9"> </boggle-dice>
    <boggle-dice id="dice10"> </boggle-dice>
    <boggle-dice id="dice11"> </boggle-dice>
    <boggle-dice id="dice12"> </boggle-dice>
    <boggle-dice id="dice13"> </boggle-dice>
    <boggle-dice id="dice14"> </boggle-dice>
    <boggle-dice id="dice15"> </boggle-dice>
</boggle-tray>

The CSS

Notice how nice the selectors are because I'm using custom tags!

boggle-tray {
    display:block;
    width:10em;
    height:10em;
    display:flex;
    flex-wrap:wrap;
    background:#911e03;
    border:.2em solid #f96800;
    font-size:1.6em;
    border-radius:.7em;
    box-shadow:-5px 5px 5px rgb(0 0 0 / 20%);
}
boggle-tray.shake {
    animation-duration:.3s;
    animation-name:shake;
}
boggle-dice {
    display:block;
    width:2em;
    height:2em;
    margin:.2em;
    line-height:2em;
    text-align:center;
    background:#f1e9d3;
    border-top:1px solid #fff;
    border-right:1px solid #fff;
    border-left: 1px solid #cbc2aa;
    border-bottom: 1px solid #cbc2aa;
    color:#000;
    border-radius:.3em;
    box-shadow:-5px 5px 5px rgb(0 0 0 / 20%);
}

@keyframes shake {
    0% {transform: translate(1px, 1px) rotate(0deg)}
    10% {transform: translate(-1px, -2px) rotate(-1deg)}
    20% {transform: translate(-3px, 0px) rotate(1deg)}
    30% {transform: translate(3px, 2px) rotate(0deg)}
    40% {transform: translate(1px, -1px) rotate(1deg)}
    50% {transform: translate(-1px, 2px) rotate(-1deg)}
    60% {transform: translate(-3px, 1px) rotate(0deg)}
    70% {transform: translate(3px, 1px) rotate(-1deg)}
    80% {transform: translate(-1px, -1px) rotate(1deg)}
    90% {transform: translate(1px, 2px) rotate(0deg)}
    100% {transform: translate(1px, -2px) rotate(-1deg)}
}

The Javascript

This is where all the magic happens:

// Create dice face arrays
aDice0 = new Array("T", "O", "E", "S", "S", "I");
aDice1 = new Array("A", "S", "P", "F", "F", "K");
aDice2 = new Array("N", "U", "I", "H", "M", "Qu");
aDice3 = new Array("O", "B", "J", "O", "A", "B");
aDice4 = new Array("L", "N", "H", "N", "R", "Z");
aDice5 = new Array("A", "H", "S", "P", "C", "O");
aDice6 = new Array("R", "Y", "V", "D", "E", "L");
aDice7 = new Array("I", "O", "T", "M", "U", "C");
aDice8 = new Array("L", "R", "E", "I", "X", "D");
aDice9 = new Array("T", "E", "R", "W", "H", "V");
aDice10 = new Array("T", "S", "T", "I", "Y", "D");
aDice11 = new Array("W", "N", "G", "E", "E", "H");
aDice12 = new Array("E", "R", "T", "T", "Y", "L");
aDice13 = new Array("O", "W", "T", "O", "A", "T");
aDice14 = new Array("A", "E", "A", "N", "E", "G");
aDice15 = new Array("E", "I", "U", "N", "E", "S");

// Create tray face array
aFace = new Array(15);

function shakeit() {
    // Select random face for each dice
    aFace[0] = aDice0[RandNo(6)];
    aFace[1] = aDice1[RandNo(6)];
    aFace[2] = aDice2[RandNo(6)];
    aFace[3] = aDice3[RandNo(6)];
    aFace[4] = aDice4[RandNo(6)];
    aFace[5] = aDice5[RandNo(6)];
    aFace[6] = aDice6[RandNo(6)];
    aFace[7] = aDice7[RandNo(6)];
    aFace[8] = aDice8[RandNo(6)];
    aFace[9] = aDice9[RandNo(6)];
    aFace[10] = aDice10[RandNo(6)];
    aFace[11] = aDice11[RandNo(6)];
    aFace[12] = aDice12[RandNo(6)];
    aFace[13] = aDice13[RandNo(6)];
    aFace[14] = aDice14[RandNo(6)];
    aFace[15] = aDice15[RandNo(6)];
    
    // Jumble the dice
    for (d = 0; d < 16; d++) {
        // Get a random number between 0 and 15
        newnumber = (Math.random() * 16);
        newnumber = parseInt(newnumber, 10);
        temp = aFace[d];
        aFace[d] = aFace[newnumber];
        aFace[newnumber] = temp;
    }

    var tray = document.getElementsByTagName("boggle-tray")[0];
    tray.classList.remove("shake");
    void tray.offsetWidth; // trigger a DOM reflow to reset
    tray.classList.add("shake");
    
    // Update the tray
    for(t = 0; t < 16; t++) {
        if (document.getElementById('dice'+t)) {
            document.getElementById('dice'+t).innerHTML = '<strong>'+ aFace[t] +'</strong>';
        }
    }
}

function resetShake(tray) {
    tray.style.animation="shake 0.5s";
}

// Generate random integer between 0 and limit
function RandNo(iLimit) {
    var ranNum= Math.floor(Math.random() * iLimit);
    return ranNum;
}

function addshakecontrol() {
    var shakebutton = document.getElementById('shakebutton');
    if (shakebutton) {
        addEvent(shakebutton, "click", shakeit);
    }
}

function addEvent(obj, evType, fn) {
    if (obj.addEventListener) {
        obj.addEventListener(evType, fn, false);
        return true;
    } else if (obj.attachEvent) {
        var r = obj.attachEvent("on"+evType, fn);
        return r;
    } else {
        return false;
    }
}

window.onload = function() {
    shakeit();
    addshakecontrol();
}

Title image by Rich Brooks.

Matthew James Taylor

Follow me on @mattjamestaylor

A nice sharp pencil

The Art of Sharpening Pencils (Styles & Techniques)

Ogga surfing

Ogga the Cane Toad (About the Comic Strip & Characters)

An example of a printed MacBook Air

Printable MacBook Air! (4 Easy Steps)

Sepia ink life drawing

Ink Life Drawing (6 Experiments with Nibs & Brushes)

Graeme Frontbum

Graeme Frontbum (About the Comic Strip & Characters)

Columns all the same height

Equal-Height Columns (CSS Grid, Flexbox, Floated Containers, & Table Methods)

Direct-to-Brain Augmented Reality (DBAR) with Neuralink & AI

Direct-to-Brain Augmented Reality (With Neuralink & AI)

Footer at the bottom of the page diagram

Bottom Footer (CSS Grid, Flexbox, & Absolute Position Methods)

How to add CSS to HTML

How to add CSS to HTML (With Link, Embed, Import, and Inline styles)

Flowers growing in a tiny house window flowerbox

12 Small House Benefits: Why Building Tiny Makes Sense!

Small house blueprint

13 Small House Design Principles (The Illustrated Guide)

Responsive house plan

Responsive House Plan (Web Design Meets Architecture!)

Lyndal the flower girl

Art by Matthew James Taylor (Paintings, Drawings & Digital Art)

Web design Web design Architecture Architecture Life drawing Life drawing Art gallery Art gallery Synesthesia Synesthesia Comics Comics

About Contact Privacy

© 1994 — 2025 Matthew James Taylor