Article Body
How to Create a Dice Roller Web App with HTML, CSS & JavaScript
Introduction
Dice rollers are essential tools for tabletop gamers, developers, and decision-makers. In this tutorial, we'll build a feature-rich dice roller web application with multiple dice types, quantity selection, modifiers, and roll history.
Step 1: Set Up the HTML Structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dice Roller</title>
</head>
<body>
<!-- We'll add content here -->
</body>
</html>
Step 2: Add CSS Styling with Tailwind
Include Tailwind CSS for rapid styling:
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
Add custom CSS for dice animations:
.dice {
width: 80px;
height: 80px;
position: relative;
margin: 10px;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.shake {
animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
}
Step 3: Build the User Interface
Create the main container with two columns:
<div class="container mx-auto px-4 py-8 max-w-4xl">
<div class="bg-white rounded-xl shadow-md p-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- Controls Column -->
<div class="space-y-6">
<!-- Dice Selection -->
<!-- Quantity Controls -->
<!-- Modifiers Section -->
<!-- Roll Button -->
</div>
<!-- Results Column -->
<div>
<!-- Result Display -->
<!-- Dice Container -->
<!-- Roll History -->
</div>
</div>
</div>
</div>
Step 4: Implement JavaScript Functionality
4.1 Initialize Variables
let selectedSides = 6;
let quantity = 1;
let modifier = 0;
let advantage = 'none';
let rollHistory = [];
4.2 Dice Roll Logic
function rollDice() {
let results = [];
let total = 0;
for (let i = 0; i < quantity; i++) {
let roll1 = Math.floor(Math.random() * selectedSides) + 1;
let roll2 = null;
if (advantage === 'advantage' || advantage === 'disadvantage') {
roll2 = Math.floor(Math.random() * selectedSides) + 1;
}
let finalRoll = advantage === 'advantage' ? Math.max(roll1, roll2) :
advantage === 'disadvantage' ? Math.min(roll1, roll2) : roll1;
results.push({
value: finalRoll,
rolls: roll2 ? [roll1, roll2] : [roll1],
advantage: advantage
});
total += finalRoll;
}
total += modifier;
displayDice(results);
totalResult.textContent = total;
addToHistory(results, total);
}
4.3 Display Results
function displayDice(results) {
diceContainer.innerHTML = '';
results.forEach((result) => {
const diceEl = document.createElement('div');
diceEl.className = 'flex flex-col items-center';
const dice = document.createElement('div');
dice.className = 'dice-face shake';
dice.textContent = result.value;
diceEl.appendChild(dice);
if (result.advantage !== 'none') {
const details = document.createElement('div');
details.className = 'text-xs text-gray-500';
details.textContent = `(${result.rolls.join(', ')})`;
diceEl.appendChild(details);
}
diceContainer.appendChild(diceEl);
});
}
4.4 History Management
function addToHistory(results, total) {
const historyItem = document.createElement('div');
historyItem.className = 'history-item bg-gray-50 p-3 rounded-lg flex justify-between items-center';
const diceType = `d${selectedSides}`;
const modifierText = modifier !== 0 ? ` + ${modifier}` : '';
historyItem.innerHTML = `
<div class="font-mono">
<span class="font-bold">${diceType}</span>: ${results.map(r => r.value).join(', ')}${modifierText}
</div>
<div class="font-bold text-lg">${total}</div>
`;
historyContainer.insertBefore(historyItem, historyContainer.firstChild);
}