Warhammer D6 Faction Behavior Roller
Build an animated D6 roller web app that maps dice results to faction actions.
Introduction
30 Second Summary
Mid-game, you don't want to pause the action to scroll through a spreadsheet looking up what your faction does next. You want one click and the answer.
In this project, you will build a single-page web app that rolls a D6 and displays the matching faction behavior action from your custom Warhammer behavior table.
What You'll Build
A browser-based D6 roller with a dark, Warhammer-inspired theme that reads from a JavaScript data structure you populate with your Excel data.
By the end of this project, you'll have:
- A working web app that rolls a D6, animates the dice, and displays the matching behavior action from your custom table.
- A faction selector dropdown that filters actions by faction, powered by a JavaScript object you build from your Excel data.
- A dark themed design with gold accents and a CSS dice roll animation that feels like a real tabletop session.
- Secret Mission: a roll history log that tracks your last 10 rolls with faction, result number, and action.
Are there any prerequisites?
No prior coding experience is needed. This guide walks you through installing everything from scratch. You just need VS Code installed on your computer.
Set Up Your Project
Every web app starts with a simple file structure. Your Warhammer Behavior Roller needs three files working together: HTML for the page structure, CSS for the dark themed styling, and JavaScript for the dice logic.
In this step, you will create a project folder on your Desktop and set up the three starter files. Then you will launch Live Server to preview your app in the browser as you build it.
In this step, get ready to:
- Create a warhammer-roller project folder on your Desktop.
- Set up index.html, style.css, and script.js inside the folder.
- Launch Live Server to preview a blank page in your browser.
Create your project folder
You need a dedicated folder on your Desktop to keep all three project files together. Creating it on the Desktop makes it easy to find later.
- In VS Code, click Terminal in the top menu bar.
- Click New Terminal to open the integrated terminal.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder by running this command:
mkdir warhammer-roller
- Confirm the folder was created by running:
ls
- You should see warhammer-roller in the output.
Don't see the folder?
Make sure you ran cd ~/Desktop first. If you get a "No such file or directory" error, your Desktop folder might be in a different location. Try cd ~/OneDrive/Desktop on Windows if you use OneDrive.
help me find my Desktop folder in the terminal
Open the folder and create your files
Now you will open the project folder in VS Code so it becomes your workspace. This means all files you create will live inside warhammer-roller.
- In VS Code, click File in the top menu bar.
- Click Open Folder.
- Navigate to your Desktop, select the warhammer-roller folder, and click Open.
What just happened?
VS Code reloaded with warhammer-roller as the workspace root. The Explorer panel on the left now shows this folder as the top-level directory. Everything you create will go inside it.
- Open a new terminal in your fresh workspace by clicking Terminal in the menu bar, then New Terminal.
- Create your three project files by running this command:
macOS
touch index.html style.css script.js
Windows
New-Item -ItemType File -Name "index.html", "style.css", "script.js"
- Confirm the files were created by running:
ls
- You should see index.html, style.css, and script.js listed in the output.
Files not showing up?
Check that your terminal is inside the warhammer-roller folder. The terminal prompt should show warhammer-roller as the current directory. If you see a different path, run cd ~/Desktop/warhammer-roller and try the file creation command again.
help me create files in my VS Code project folder
Launch Live Server to preview your app
Live Server watches your files and automatically refreshes the browser whenever you save a change. This gives you instant feedback as you build.
- In the VS Code Explorer panel on the left, right-click index.html.
- Select Open with Live Server.
Your browser should open showing a blank page. This is expected because the file is empty.
- Look at the VS Code status bar at the bottom. You should see Port: 5500 (or a similar number) confirming the server is running.
What is Live Server doing?
Live Server starts a local web server on your machine and opens your file in the browser through it. Every time you save a file, it tells the browser to reload automatically. No manual refreshing needed.
Don't see Open with Live Server?
Make sure you are right-clicking index.html in the Explorer panel (left sidebar), not in the editor tab. If the option still does not appear, check that the Live Server extension by Ritwick Dey is installed by pressing Ctrl+Shift+X and searching for it.
help me get Live Server working in VS Code
Your project scaffold is ready. Next up, you will build the HTML structure that gives your roller its page layout and interactive elements.
Build the HTML Structure
Your project folder is ready and Live Server is running. Now it's time to build the actual page your players will interact with during Warhammer sessions.
Every web app starts with HTML, which defines the structure and content of the page. You'll lay out a faction selector, a dice display, a roll button, and a result area.
In this step, get ready to:
- Build the HTML skeleton for the roller app.
- Link the CSS and JavaScript files to the page.
Create the page structure in index.html
The page needs a few key areas: a heading, a dropdown to select a faction, a dice display, a button to trigger the roll, and a section to show the result. The faction dropdown starts with just a placeholder option because JavaScript will fill it with real faction names later.
- In VS Code, click on index.html in the Explorer sidebar to open it.
- Paste the following HTML into the empty file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Warhammer Behavior Roller</title>
<!-- Link to our stylesheet for dark Warhammer theme -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Warhammer Behavior Roller</h1>
<!-- Faction selector dropdown -->
<div class="controls">
<label for="faction-select">Select Faction:</label>
<select id="faction-select">
<option value="">-- Choose Faction --</option>
</select>
</div>
<!-- Dice display and roll button -->
<div class="dice-area">
<div id="dice" class="dice">?</div>
<button id="roll-btn">Roll D6</button>
</div>
<!-- Result display area -->
<div id="result" class="result">
<p id="result-text">Select a faction and roll the dice!</p>
</div>
</div>
<!-- Link to our JavaScript logic -->
<script src="script.js"></script>
</body>
</html>
What does this code do?
The <head> section sets up the page title and links to style.css so your styles will apply when you write them later.
The <body> contains a container div that wraps three areas: the faction dropdown (starting with one placeholder option), the dice display (showing ? until you roll), and the result section for displaying the action text.
The <script> tag at the bottom links to script.js. Placing it at the end of the body ensures the HTML elements exist before JavaScript tries to interact with them.
- Save index.html by pressing Cmd+S (macOS) or Ctrl+S (Windows).
- Check your browser. Live Server auto-refreshes, so you should now see the page title "Warhammer Behavior Roller", an empty dropdown showing "-- Choose Faction --", a question mark where the dice will go, and a "Roll D6" button.
Still seeing a blank page?
- Make sure you saved the file. An unsaved file shows a dot on its tab in VS Code.
- Check that Live Server is still running. The VS Code status bar should show a port number (like Port: 5500). If it says Go Live instead, right-click index.html and select Open with Live Server again.
- Confirm the file is named exactly index.html (all lowercase, no extra spaces).
Help me figure out why my HTML page isn't loading in Live Server.
Why is the dropdown empty?
The <select> element only has a single placeholder option right now. In a later step, your JavaScript will read faction names from a data object and dynamically create <option> elements for each one. This keeps the HTML clean and the data in one place.
✔️ Awesome, I've got everything!
Great. Double check you've saved your file before moving on.
ⓧ I'd like to double check the full code
Here's the complete index.html file. Compare it to what you have:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Warhammer Behavior Roller</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h1>Warhammer Behavior Roller</h1>
<div class="controls">
<label for="faction-select">Select Faction:</label>
<select id="faction-select">
<option value="">-- Choose Faction --</option>
</select>
</div>
<div class="dice-area">
<div id="dice" class="dice">?</div>
<button id="roll-btn">Roll D6</button>
</div>
<div id="result" class="result">
<p id="result-text">Select a faction and roll the dice!</p>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
Your page structure is in place. Next up, you'll transform this plain HTML into a dark, Warhammer-themed interface with CSS styling and a dice animation.
Style with a Warhammer Dark Theme
Your HTML structure is in place, but right now it looks like a plain, unstyled document. To make this feel like a Warhammer tabletop tool, you need a dark color scheme with gold accents that evokes the grim aesthetic of the game.
In this step, you will write all the CSS that transforms your bare HTML into a polished, themed app. You will also prepare a dice roll animation that will fire when the JavaScript logic is wired up in the next step.
In this step, get ready to:
- Create a dark background with a centered gold-bordered card layout.
- Style the dice square and define a CSS keyframe roll animation.
- Style the result display area so rolled actions stand out clearly.
Set up the dark theme and card layout
The foundation of the Warhammer look is a deep navy background, off-white text, and a card container with a gold border. You will also style the dropdown and label so they fit the theme from the start.
- Open style.css in VS Code and add the page foundation styles by pasting this code:
/* Reset default browser spacing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* Dark page background with centered content */
body {
font-family: 'Georgia', serif;
background-color: #1a1a2e;
color: #e0e0e0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* Main card container with gold border */
.container {
background-color: #16213e;
border: 2px solid #d4af37;
border-radius: 12px;
padding: 40px;
text-align: center;
max-width: 500px;
width: 90%;
}
/* Page title in gold */
h1 {
color: #d4af37;
margin-bottom: 24px;
font-size: 1.8rem;
}
/* Spacing below the faction selector */
.controls {
margin-bottom: 24px;
}
/* Label above the dropdown */
label {
display: block;
margin-bottom: 8px;
color: #a0a0a0;
}
/* Faction dropdown styled for the dark theme */
select {
width: 100%;
padding: 10px;
border-radius: 6px;
border: 1px solid #d4af37;
background-color: #0f3460;
color: #e0e0e0;
font-size: 1rem;
}
What does this code do?
The * reset removes default browser margins and padding so every element starts from a clean slate.
The body uses flexbox to center the .container both vertically and horizontally on the page. The dark navy background (#1a1a2e) and off-white text (#e0e0e0) set the overall Warhammer mood.
The .container acts as a card with a gold (#d4af37) border that draws the eye. The dropdown picks up the same gold border and dark background to stay consistent.
- Save style.css.
- Check your browser. You should see a dark navy page with a centered card outlined in gold, the title in gold text, and the dropdown styled with a dark blue background.
Still seeing an unstyled page?
- Confirm you saved the file. Unsaved changes show a white dot on the file tab in VS Code.
- Check that your index.html has <link rel="stylesheet" href="style.css"> in the <head>. If this line is missing, the browser cannot find your stylesheet.
- Make sure style.css is in the same folder as index.html.
Help me figure out why my CSS isn't showing up in the browser.
Style the dice and add the roll animation
The dice is the centerpiece of the app. You want it to look like a bold square token on the table, and you want it to spin when the player clicks Roll.
- Add the dice and animation styles below your existing CSS in style.css:
/* Spacing for the dice section */
.dice-area {
margin-bottom: 24px;
}
/* The dice square with gold border */
.dice {
width: 80px;
height: 80px;
border: 3px solid #d4af37;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2.5rem;
font-weight: bold;
margin: 0 auto 16px auto;
background-color: #0f3460;
color: #d4af37;
transition: transform 0.1s;
}
/* Trigger the roll animation */
.dice.rolling {
animation: roll 0.6s ease-out;
}
/* Keyframes that spin and pulse the dice */
@keyframes roll {
0% { transform: rotateZ(0deg) scale(1); }
25% { transform: rotateZ(90deg) scale(1.1); }
50% { transform: rotateZ(180deg) scale(1); }
75% { transform: rotateZ(270deg) scale(1.1); }
100% { transform: rotateZ(360deg) scale(1); }
}
What does this code do?
The .dice class creates an 80x80 pixel square with rounded corners and a thick gold border. Flexbox centers the number (or question mark) inside.
The .dice.rolling class will be added by JavaScript when the player clicks Roll. It triggers the @keyframes roll animation, which spins the dice 360 degrees while pulsing its size up and down over 0.6 seconds.
- Save style.css.
- Check your browser. You should see a gold-bordered square with a ? displayed in large gold text, centered above where the button will appear.
Dice square not visible?
- Make sure your HTML has class="dice" on the dice div. The CSS targets this class name exactly.
- Check for missing semicolons or unclosed curly braces in the CSS above this section. A single missing character can break every rule that follows.
Help me debug why my dice square isn't showing up.
- Now add the button styles below your dice animation in style.css:
/* Roll button with gold background */
button {
padding: 12px 32px;
font-size: 1.1rem;
background-color: #d4af37;
color: #1a1a2e;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: background-color 0.2s;
}
/* Brighter gold on hover */
button:hover {
background-color: #e6c94a;
}
/* Grayed out while the dice is rolling */
button:disabled {
background-color: #666;
cursor: not-allowed;
}
What does this code do?
The button gets a solid gold background with dark text for strong contrast. The :hover state brightens the gold when the player moves their cursor over it.
The :disabled state grays out the button and changes the cursor. This will prevent double-clicks while the dice is mid-animation.
- Save style.css.
- Check your browser. The Roll D6 button should now be a bold gold rectangle with dark text, centered below the dice square.
Button still looks plain?
- Verify you pasted the button styles after the @keyframes roll block, not inside it. Each CSS rule set must have its own pair of curly braces.
- Hover your mouse over the button. If it changes color, the styles are applied but might be hard to see. Try resizing your browser window if the card is off-screen.
Help me debug why my button styles are not showing.
Style the result display
The result area is where the rolled action will appear after each dice roll. It needs a distinct background so the action text pops against the card.
- Add the result styles below your button rules in style.css:
/* Result display box */
.result {
background-color: #0f3460;
border: 1px solid #333;
border-radius: 8px;
padding: 16px;
min-height: 60px;
display: flex;
align-items: center;
justify-content: center;
}
/* Action text styling */
#result-text {
font-size: 1.1rem;
line-height: 1.4;
}
What does this code do?
The .result box gets a slightly different shade of dark blue (#0f3460) to visually separate it from the card background. The min-height ensures it does not collapse when empty, keeping the layout stable between rolls.
- Save style.css.
- Check your browser. The placeholder text "Select a faction and roll the dice!" should now sit inside a rounded dark-blue box at the bottom of the card.
Result area not showing a distinct background?
- Confirm your HTML has class="result" on the result div. The CSS uses this class name to apply the darker background.
- The colors are similar shades of dark blue. Look closely for the subtle border and slightly different shade. If you cannot tell, temporarily change background-color to red to confirm the rule is applying, then change it back.
Help me check why my result area styling isn't working.
✔️ Awesome, I've got everything!
Great. Double check you have saved style.css and your browser is showing the full dark theme with gold accents.
ⓧ I'd like to double check the full code
Here is the complete style.css file. Compare yours against this:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Georgia', serif;
background-color: #1a1a2e;
color: #e0e0e0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background-color: #16213e;
border: 2px solid #d4af37;
border-radius: 12px;
padding: 40px;
text-align: center;
max-width: 500px;
width: 90%;
}
h1 {
color: #d4af37;
margin-bottom: 24px;
font-size: 1.8rem;
}
.controls {
margin-bottom: 24px;
}
label {
display: block;
margin-bottom: 8px;
color: #a0a0a0;
}
select {
width: 100%;
padding: 10px;
border-radius: 6px;
border: 1px solid #d4af37;
background-color: #0f3460;
color: #e0e0e0;
font-size: 1rem;
}
.dice-area {
margin-bottom: 24px;
}
.dice {
width: 80px;
height: 80px;
border: 3px solid #d4af37;
border-radius: 12px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2.5rem;
font-weight: bold;
margin: 0 auto 16px auto;
background-color: #0f3460;
color: #d4af37;
transition: transform 0.1s;
}
.dice.rolling {
animation: roll 0.6s ease-out;
}
@keyframes roll {
0% { transform: rotateZ(0deg) scale(1); }
25% { transform: rotateZ(90deg) scale(1.1); }
50% { transform: rotateZ(180deg) scale(1); }
75% { transform: rotateZ(270deg) scale(1.1); }
100% { transform: rotateZ(360deg) scale(1); }
}
button {
padding: 12px 32px;
font-size: 1.1rem;
background-color: #d4af37;
color: #1a1a2e;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: bold;
transition: background-color 0.2s;
}
button:hover {
background-color: #e6c94a;
}
button:disabled {
background-color: #666;
cursor: not-allowed;
}
.result {
background-color: #0f3460;
border: 1px solid #333;
border-radius: 8px;
padding: 16px;
min-height: 60px;
display: flex;
align-items: center;
justify-content: center;
}
#result-text {
font-size: 1.1rem;
line-height: 1.4;
}
Your app now looks the part. Next up, you will write the JavaScript that powers the faction dropdown, generates a random D6 result, and triggers that roll animation you just defined.
Add Your Faction Data and Dice Logic
Your page looks great with the dark Warhammer theme, but it doesn't actually do anything yet.
The dropdown is empty, the dice is frozen on a question mark, and clicking the button has no effect. In this step, you'll write all the JavaScript that brings this app to life.
In this step, get ready to:
- Create a faction data object with behavior actions for each dice result.
- Write a function that populates the dropdown from your data.
- Build the dice roll logic with animation and result display.
Create your faction data object
Your app needs a structured way to look up which action belongs to which dice number for each faction. A JavaScript object is perfect for this because you can use the faction name as a key to instantly find the matching array of actions.
- In VS Code, click on script.js in the Explorer sidebar to open it.
- Add the following faction data object:
const factionData = {
"Faction Alpha": [
{ number: 1, action: "Advance cautiously toward nearest cover" },
{ number: 2, action: "Hold position and fire at closest enemy" },
{ number: 3, action: "Charge nearest enemy unit" },
{ number: 4, action: "Fall back toward deployment zone" },
{ number: 5, action: "Move to flank the nearest enemy" },
{ number: 6, action: "Call for reinforcements - add reserve unit" }
],
"Faction Beta": [
{ number: 1, action: "Dig in and fortify current position" },
{ number: 2, action: "Open suppressive fire on nearest target" },
{ number: 3, action: "Send scouts ahead to recon" },
{ number: 4, action: "Regroup with nearest friendly unit" },
{ number: 5, action: "Launch aggressive assault on weakest enemy" },
{ number: 6, action: "Deploy special weapon - heavy bombardment" }
]
};
What does this code do?
This object uses faction names as keys. Each key maps to an array of 6 action objects, where index 0 corresponds to dice result 1 and index 5 corresponds to dice result 6.
Each action object has a number property (the dice face) and an action property (the behavior text). This mirrors how your Excel table is structured with factions, dice numbers, and actions.
Replace with your own data
The faction names and actions here are placeholders. Once your app is working, swap these out with the real factions and behaviors from your own Excel table.
You won't see a change in the browser yet. The next chunk uses this data to populate the dropdown.
Populate the faction dropdown
The HTML dropdown is currently empty because you want JavaScript to fill it dynamically from your data object. This way, adding a new faction to your data automatically adds it to the dropdown without touching the HTML.
- Below the factionData object in script.js, add the DOM references and the populateFactions() function:
const factionSelect = document.getElementById("faction-select");
const dice = document.getElementById("dice");
const rollBtn = document.getElementById("roll-btn");
const resultText = document.getElementById("result-text");
function populateFactions() {
// Read all faction names from the data object
const factions = Object.keys(factionData);
// Create a dropdown option for each faction
factions.forEach(function(faction) {
const option = document.createElement("option");
option.value = faction;
option.textContent = faction;
factionSelect.appendChild(option);
});
}
What does this code do?
The first four lines grab references to the HTML elements your script needs to interact with. Storing them in variables means you don't have to look them up every time you use them.
The populateFactions() function uses Object.keys() to get an array of faction names from your data. It then loops through each name, creates a new <option> element, and appends it to the dropdown.
You still won't see a change yet because the function is defined but not called. The next chunk handles that.
Build the dice roll function
This is the core of your app. When the learner clicks Roll D6, the function needs to validate a faction is selected, trigger the spin animation, generate a random number, then display the matching action.
- Below the populateFactions() function in script.js, add the rollDice() function, the event listener, and the initialization call:
function rollDice() {
const selectedFaction = factionSelect.value;
// Stop if no faction is selected
if (!selectedFaction) {
resultText.textContent = "Please select a faction first!";
return;
}
// Disable button and reset display while rolling
rollBtn.disabled = true;
dice.textContent = "?";
resultText.textContent = "Rolling...";
// Trigger the CSS spin animation
dice.classList.add("rolling");
// Generate a random number 1-6
const rollResult = Math.floor(Math.random() * 6) + 1;
// Wait for animation to finish, then show result
setTimeout(function() {
dice.classList.remove("rolling");
dice.textContent = rollResult;
// Look up the matching action from faction data
const actions = factionData[selectedFaction];
const action = actions[rollResult - 1];
resultText.textContent = "[" + rollResult + "] " + action.action;
rollBtn.disabled = false;
}, 600);
}
rollBtn.addEventListener("click", rollDice);
populateFactions();
What does this code do?
The rollDice() function first checks if a faction is selected. If not, it shows a warning message and stops.
When a faction is selected, it disables the button (preventing spam clicks), adds the rolling CSS class to trigger the spin animation, and generates a random number with Math.floor(Math.random() * 6) + 1.
The setTimeout waits 600 milliseconds (matching the animation duration) before revealing the result. It removes the animation class, shows the rolled number on the dice, looks up the matching action from your data, and re-enables the button.
The last two lines wire the button click to rollDice() and call populateFactions() to fill the dropdown when the page loads.
- Save script.js.
- Switch to your browser. The page should auto-refresh thanks to Live Server.
- Check the dropdown. It should now show Faction Alpha and Faction Beta as options.
- Select a faction, then click Roll D6. The dice should spin, land on a number 1-6, and display the corresponding action text below.
Dropdown still empty or button not working?
- Open the browser console (press Cmd+Option+J on macOS or Ctrl+Shift+J on Windows) and look for red error messages. A typo in an element ID like faction-select will cause a silent failure.
- Make sure populateFactions(); appears at the very bottom of your script. If it runs before the function is defined, nothing happens.
- Confirm your index.html has <script src="script.js"></script> just before </body>. If the script loads in the <head>, the HTML elements won't exist yet when the script runs.
Why isn't my dice roller working after adding the JavaScript?
✔️ Awesome, I've got everything!
Great. Double check you've saved script.js and your browser is showing the populated dropdown.
ⓧ I'd like to double check the full code
Here is the complete script.js file. Compare yours against this:
const factionData = {
"Faction Alpha": [
{ number: 1, action: "Advance cautiously toward nearest cover" },
{ number: 2, action: "Hold position and fire at closest enemy" },
{ number: 3, action: "Charge nearest enemy unit" },
{ number: 4, action: "Fall back toward deployment zone" },
{ number: 5, action: "Move to flank the nearest enemy" },
{ number: 6, action: "Call for reinforcements - add reserve unit" }
],
"Faction Beta": [
{ number: 1, action: "Dig in and fortify current position" },
{ number: 2, action: "Open suppressive fire on nearest target" },
{ number: 3, action: "Send scouts ahead to recon" },
{ number: 4, action: "Regroup with nearest friendly unit" },
{ number: 5, action: "Launch aggressive assault on weakest enemy" },
{ number: 6, action: "Deploy special weapon - heavy bombardment" }
]
};
const factionSelect = document.getElementById("faction-select");
const dice = document.getElementById("dice");
const rollBtn = document.getElementById("roll-btn");
const resultText = document.getElementById("result-text");
function populateFactions() {
const factions = Object.keys(factionData);
factions.forEach(function(faction) {
const option = document.createElement("option");
option.value = faction;
option.textContent = faction;
factionSelect.appendChild(option);
});
}
function rollDice() {
const selectedFaction = factionSelect.value;
if (!selectedFaction) {
resultText.textContent = "Please select a faction first!";
return;
}
rollBtn.disabled = true;
dice.textContent = "?";
resultText.textContent = "Rolling...";
dice.classList.add("rolling");
const rollResult = Math.floor(Math.random() * 6) + 1;
setTimeout(function() {
dice.classList.remove("rolling");
dice.textContent = rollResult;
const actions = factionData[selectedFaction];
const action = actions[rollResult - 1];
resultText.textContent = "[" + rollResult + "] " + action.action;
rollBtn.disabled = false;
}, 600);
}
rollBtn.addEventListener("click", rollDice);
populateFactions();
Secret mission
Add a Roll History Log
Your roller works great for single rolls, but during a real game you want to see what happened in previous turns. In this secret mission, you will add a roll history tracker that remembers your last 10 rolls and displays them in reverse chronological order.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs. Your files sit on your desktop and use no cloud services or servers.
Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- The warhammer-roller folder on your Desktop (contains index.html, style.css, script.js).
- The Live Server extension in VS Code.
Keep everything running
No action needed. Choose this if you plan to use the roller during your next Warhammer session.
- Your warhammer-roller folder stays on your Desktop. You can open index.html directly in any browser by double-clicking it.
- Live Server stays installed in VS Code for future development.
- You can move the warhammer-roller folder anywhere on your computer and it will still work.
Pause - I'll come back to this later
Shut down Live Server to free up the port, but keep all your files for later.
- In VS Code, click the Port: 5500 indicator in the bottom status bar to stop Live Server.
- Your project files remain untouched on your Desktop. Open the folder in VS Code again whenever you want to continue.
Delete - I don't want to use this again
Remove all project files and optionally uninstall the Live Server extension.
- Stop Live Server by clicking the Port: 5500 indicator in the VS Code status bar.
- Delete the project folder by running this command in your terminal:
macOS
rm -rf ~/Desktop/warhammer-roller
Windows
rmdir /s /q %USERPROFILE%\Desktop\warhammer-roller
- To uninstall Live Server, press Ctrl+Shift+X in VS Code to open the Extensions panel.
- Find Live Server in your installed extensions list and click Uninstall.
Nice Work!
Nice Work!
Nice work! You just built a fully functional D6 behavior roller web app from scratch using only HTML, CSS, and JavaScript.
You've learned how to:
- Structure real game data into a JavaScript object that drives the UI dynamically through data-driven rendering.
- Implement a CSS keyframe animation triggered by JavaScript event handling to create an interactive dice roll experience.
- Build a faction-based filtering system using dropdown selection and object key lookup to display matching actions.
- Secret Mission: Added a roll history tracker that maintains state across rolls and renders a dynamic list of the last 10 entries.
Ready to quiz yourself?