Create Your Own Interactive 3D Dice Roller: A Step-by-Step Guide
Learn Computer Academy

Learn Computer Academy @learncomputer

About: Website Design and Development Training Institute in Habra We provide the best hands-on training in Graphics Design, Website Design and Development.

Location:
Habra, India
Joined:
Mar 7, 2025

Create Your Own Interactive 3D Dice Roller: A Step-by-Step Guide

Publish Date: Apr 1
2 0

Hey there, fellow developers! 👋 Today I'm excited to share a fun weekend project I built: a fully interactive 3D dice roller with roll history tracking. It's a perfect blend of visual appeal and practical functionality that you can use for board games, tabletop RPGs, or just when you need a quick random number.

Let's break down how to build this project from scratch using vanilla HTML, CSS, and JavaScript. No frameworks needed! 🚀

Demo

You can check out the live demo here before we dive into the code.

Features

  • Realistic 3D dice with smooth rolling animation
  • Customizable dice color with automatic text contrast adjustment
  • Complete roll history with timestamps
  • Clean, sci-fi inspired UI
  • Fully responsive design

The HTML Structure

First, let's set up our HTML foundation. We'll need elements for the dice, controls, and history section:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3D Dice Roller</title>
    <link rel="stylesheet" href="styles.css">
    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>3D Dice Roller</h1>
        <div class="dice-wrapper">
            <div class="dice-container">
                <div id="dice" class="dice">
                    <div class="face front">1</div>
                    <div class="face back">2</div>
                    <div class="face right">3</div>
                    <div class="face left">4</div>
                    <div class="face top">5</div>
                    <div class="face bottom">6</div>
                </div>
            </div>
        </div>
        <button id="roll-btn" class="roll-btn">Roll Dice</button>
        <div class="color-picker">
            <label for="dice-color">Dice Color: </label>
            <input type="color" id="dice-color" value="#ff6f61">
        </div>
        <div id="result" class="result"></div>
        <div class="history">
            <h2>Roll History</h2>
            <div id="history-list" class="history-list"></div>
            <button id="clear-history" class="clear-btn">Clear History</button>
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

The HTML creates a structure with:

  • A container for our 3D dice with all six faces defined
  • A roll button to trigger the animation
  • A color picker for customization
  • A results display area
  • A history section that logs all rolls

Styling with CSS: Creating the 3D Effect

Now for the fun part - making our dice actually look 3D! We'll use CSS transforms to position each face of the dice in 3D space:

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Orbitron', sans-serif;
    background: linear-gradient(135deg, #1e1e2f, #2a2a4a);
    color: #fff;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.container {
    text-align: center;
    padding: 20px;
    max-width: 600px;
    width: 100%;
}

h1 {
    font-size: 2.5rem;
    margin-bottom: 20px;
    text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}

.dice-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    margin: 40px 0;
}

.dice-container {
    perspective: 1000px;
}

.dice {
    width: 150px;
    height: 150px;
    position: relative;
    transform-style: preserve-3d;
    transition: transform 1s ease-out;
}

.face {
    position: absolute;
    width: 150px;
    height: 150px;
    background: #ff6f61; /* Default color */
    border: 2px solid #fff;
    border-radius: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 2rem;
    font-weight: bold;
    color: #fff; /* Default text color */
    box-shadow: 0 0 15px rgba(255, 111, 97, 0.7);
}

/* Face positions for a true 3D cube */
.front  { transform: translateZ(75px); }
.back   { transform: translateZ(-75px) rotateY(180deg); }
.right  { transform: translateX(75px) rotateY(90deg); }
.left   { transform: translateX(-75px) rotateY(-90deg); }
.top    { transform: translateY(-75px) rotateX(90deg); }
.bottom { transform: translateY(75px) rotateX(-90deg); }

/* Stable states maintaining 3D structure */
.show-1 { transform: rotateX(0deg) rotateY(0deg); }
.show-2 { transform: rotateX(0deg) rotateY(180deg); }
.show-3 { transform: rotateX(0deg) rotateY(-90deg); }
.show-4 { transform: rotateX(0deg) rotateY(90deg); }
.show-5 { transform: rotateX(-90deg) rotateY(0deg); }
.show-6 { transform: rotateX(90deg) rotateY(0deg); }

/* Rolling animation */
@keyframes roll {
    0% { transform: rotateX(0deg) rotateY(0deg); }
    100% { transform: rotateX(720deg) rotateY(720deg); }
}

.rolling {
    animation: roll 1s ease-out forwards;
}

.roll-btn, .clear-btn {
    padding: 15px 30px;
    font-size: 1.2rem;
    border: none;
    border-radius: 10px;
    background: #4a4e69;
    color: #fff;
    cursor: pointer;
    transition: transform 0.2s, background 0.3s;
    margin: 10px;
}

.roll-btn:hover, .clear-btn:hover {
    transform: scale(1.05);
    background: #5c627d;
}

.color-picker {
    margin: 20px 0;
}

.color-picker label {
    font-size: 1.2rem;
    margin-right: 10px;
}

#dice-color {
    vertical-align: middle;
    cursor: pointer;
}

.result {
    margin: 20px 0;
    font-size: 1.5rem;
    text-shadow: 0 0 5px rgba(255, 255, 255, 0.8);
}

.history {
    margin-top: 30px;
}

h2 {
    font-size: 1.5rem;
    margin-bottom: 10px;
}

.history-list {
    max-height: 200px;
    overflow-y: auto;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 10px;
    padding: 10px;
}

.history-item {
    padding: 8px;
    margin-bottom: 5px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 5px;
    text-align: left;
    font-size: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

The CSS magic happens through:

  1. The .dice-container with perspective: 1000px that creates our 3D space
  2. The .dice element with transform-style: preserve-3d that maintains the 3D positioning
  3. Individual face positioning using translateZ() and rotations
  4. Classes like .show-1 through .show-6 that control which face is shown
  5. The rolling animation that creates the tumbling effect

I particularly love the gradient background that gives the whole application that futuristic sci-fi feel. The glow effects on the dice faces also add depth to the visualization.

Making It Interactive with JavaScript

Now let's breathe life into our dice with JavaScript:

const dice = document.getElementById('dice');
const rollBtn = document.getElementById('roll-btn');
const result = document.getElementById('result');
const historyList = document.getElementById('history-list');
const clearBtn = document.getElementById('clear-history');
const colorPicker = document.getElementById('dice-color');
const faces = document.querySelectorAll('.face');

let rollHistory = [];

function rollDice() {
    rollBtn.disabled = true;
    result.textContent = '';

    dice.classList.remove('show-1', 'show-2', 'show-3', 'show-4', 'show-5', 'show-6');
    dice.classList.add('rolling');

    const rollResult = Math.floor(Math.random() * 6) + 1;

    setTimeout(() => {
        dice.classList.remove('rolling');
        dice.classList.add(`show-${rollResult}`);
        result.textContent = `You rolled a ${rollResult}!`;
        addToHistory(rollResult);
        rollBtn.disabled = false;
    }, 1000); 
}

function addToHistory(result) {
    const timestamp = new Date().toLocaleTimeString();
    rollHistory.unshift({ result, timestamp });
    updateHistoryUI();
}

function updateHistoryUI() {
    historyList.innerHTML = rollHistory.map(item => `
        <div class="history-item">Rolled: ${item.result} at ${item.timestamp}</div>
    `).join('');
}

function clearHistory() {
    rollHistory = [];
    updateHistoryUI();
}


function adjustTextColor(bgColor) {
    const rgb = hexToRgb(bgColor);
    const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; 
    const textColor = brightness > 128 ? '#000' : '#fff'; 
    faces.forEach(face => face.style.color = textColor);
}


function hexToRgb(hex) {
    const r = parseInt(hex.slice(1, 3), 16);
    const g = parseInt(hex.slice(3, 5), 16);
    const b = parseInt(hex.slice(5, 7), 16);
    return { r, g, b };
}


function updateDiceColor(color) {
    faces.forEach(face => {
        face.style.background = color;
        face.style.boxShadow = `0 0 15px ${color}`; 
    });
    adjustTextColor(color);
}

rollBtn.addEventListener('click', rollDice);
clearBtn.addEventListener('click', clearHistory);
colorPicker.addEventListener('input', (e) => updateDiceColor(e.target.value));
Enter fullscreen mode Exit fullscreen mode

The JavaScript handles four main responsibilities:

1. The Rolling Mechanism

When the user clicks "Roll Dice," our code:

  • Applies a rolling animation class
  • Generates a random number between 1-6
  • Updates the dice position to show the correct face after animation
  • Displays the result text

2. History Tracking

Each roll is recorded with:

  • The dice value
  • A timestamp of when it occurred
  • These are stored in an array and displayed in the history list

3. Color Customization

The color picker allows users to:

  • Change the dice color in real-time
  • Automatically adjust text color for readability
  • Update the glow effect to match the selected color

4. Intelligent Contrast

One of my favorite parts is the brightness calculation that determines whether text should be black or white based on the background color:

// This is a snippet from the full code
function adjustTextColor(bgColor) {
    const rgb = hexToRgb(bgColor);
    const brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
    const textColor = brightness > 128 ? '#000' : '#fff';
    faces.forEach(face => face.style.color = textColor);
}
Enter fullscreen mode Exit fullscreen mode

This uses the perceived brightness formula to ensure text remains readable regardless of background color.

The CSS Transform Magic ✨

Let's take a closer look at how the 3D effect works. Each face is positioned using CSS transforms:

/* This is a snippet of the positioning CSS */
.front  { transform: translateZ(75px); }
.back   { transform: translateZ(-75px) rotateY(180deg); }
.right  { transform: translateX(75px) rotateY(90deg); }
.left   { transform: translateX(-75px) rotateY(-90deg); }
.top    { transform: translateY(-75px) rotateX(90deg); }
.bottom { transform: translateY(75px) rotateX(-90deg); }
Enter fullscreen mode Exit fullscreen mode

To show a specific face, we rotate the entire cube. For example:

.show-1 { transform: rotateX(0deg) rotateY(0deg); }
.show-6 { transform: rotateX(90deg) rotateY(0deg); }
Enter fullscreen mode Exit fullscreen mode

Tips for Your Implementation

When building this yourself, watch out for these common issues:

  1. 3D Perspective: If your dice doesn't look 3D, check that you've set the proper perspective value and transform-style.

  2. Animation Timing: The rolling animation should be long enough to look realistic but short enough to not frustrate users. I found 1 second to be a good balance.

  3. Mobile Responsiveness: Test on various screen sizes - the 3D effect should look good on all devices.

  4. Color Contrast: When implementing custom colors, always ensure text remains readable.

Ideas for Expansion

Want to take this project further? Here are some ideas:

  • Add sound effects for the rolling animation
  • Implement different dice types (D4, D8, D12, D20)
  • Add an option to roll multiple dice simultaneously
  • Create statistics tracking for roll distributions
  • Save color preferences using localStorage

What I Learned

Building this project taught me a lot about:

  • Advanced CSS 3D transforms and animations
  • Dynamic UI updates with JavaScript
  • Color theory and accessibility considerations
  • Creating a cohesive user experience

Conclusion

This 3D dice roller demonstrates how modern CSS and JavaScript can create interactive, visually appealing applications without relying on heavy libraries or frameworks. It's a perfect example of making something both functional and beautiful using core web technologies.

I hope you enjoyed this walkthrough! Feel free to use this code as a starting point for your own projects or as a learning resource for understanding 3D CSS transforms.

Let me know in the comments if you build your own version or have questions about any part of the implementation! 🎲


What other web-based tools would you like to see tutorials for? Let me know in the comments!

Comments 0 total

    Add comment