open-dice-dnd
v1.1.2
Published
A 3D physics-based dice rolling engine built with Three.js and Cannon.js
Downloads
29
Maintainers
Readme
🎲 Open Dice DnD
A beautiful 3D physics-based dice rolling engine built with Three.js and Cannon.js. Perfect for adding realistic dice rolling to your web applications, games, or tabletop RPG tools!
✨ Features
- 🎯 Physics-based dice rolling with realistic behavior
- 🎨 Support for multiple dice types: d4, d6, d8, d10, d12, d20, d100
- 🎬 Smooth animations and shadows
- 📱 Responsive and works on any container size
- 🔧 Easy-to-use API
- 📦 Lightweight and modular
- 🎭 Customizable throw speed and spin
- 🌈 Customizable dice colors (dice body, text, and background)
- 🔒 Secret roll mode (hides numbers with "?")
📦 Installation
Via npm
npm install open-dice-dndLocal Development
git clone <repository-url>
cd open-dice-dnd
npm install🚀 Quick Start
Basic Usage
import { DiceRoller } from 'open-dice-dnd';
// Get your container element
const container = document.getElementById('dice-container');
// Create a new dice roller instance
const diceRoller = new DiceRoller({
container: container,
throwSpeed: 15,
throwSpin: 20,
onRollComplete: (total) => {
console.log('Roll total:', total);
}
});
// Roll some dice!
const diceConfig = [
{ dice: 'd20', rolled: 15 },
{ dice: 'd6', rolled: 4 }
];
diceRoller.roll(diceConfig).then(total => {
console.log('Dice settled! Total:', total);
});HTML Setup
<!DOCTYPE html>
<html>
<head>
<style>
#dice-container {
width: 100vw;
height: 100vh;
position: relative;
}
</style>
</head>
<body>
<div id="dice-container"></div>
<script type="module" src="main.js"></script>
</body>
</html>📖 API Reference
new DiceRoller(options)
Creates a new dice roller instance.
Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| container | HTMLElement | Required | The DOM element to render the canvas in |
| width | number | Container width | Canvas width in pixels |
| height | number | Container height | Canvas height in pixels |
| throwSpeed | number | 15 | Initial throw speed (5-30) |
| throwSpin | number | 20 | Initial throw spin (5-40) |
| onRollComplete | function | null | Callback function when dice settle |
Methods
roll(diceConfig)
Roll dice with the given configuration.
Parameters:
diceConfig(Array): Array of dice configurationsdice(string): Type of die -'d4','d6','d8','d10','d12','d20', or'd100'rolled(number, optional): Target number for the rolldiceColor(number, optional): Dice body color as numeric hex (e.g.,0xf0f0f0)textColor(string, optional): Text color as hex string (e.g.,'#FFFFFF')backgroundColor(string, optional): Background color as hex string (e.g.,'#e74c3c')isSecret(boolean, optional): Hide numbers with "?" for secret rolls (default:false)
Returns: Promise<number> - Promise that resolves with the total roll result
Example:
const result = await diceRoller.roll([
{ dice: 'd20', rolled: 18 },
{ dice: 'd6' },
{ dice: 'd8', rolled: 5 }
]);
console.log('Total:', result);reset()
Reset and clear all dice from the scene with a fade animation.
Returns: Promise<void>
Example:
await diceRoller.reset();setThrowSpeed(speed)
Update the throw speed.
Parameters:
speed(number): New throw speed (recommended: 5-30)
Example:
diceRoller.setThrowSpeed(20);setThrowSpin(spin)
Update the throw spin.
Parameters:
spin(number): New throw spin (recommended: 5-40)
Example:
diceRoller.setThrowSpin(25);destroy()
Destroy the dice roller instance and clean up all resources.
Example:
diceRoller.destroy();🎮 Examples
Rolling Multiple Dice Types
const diceRoller = new DiceRoller({
container: document.getElementById('dice-container')
});
// Roll a variety of dice
await diceRoller.roll([
{ dice: 'd20' },
{ dice: 'd12' },
{ dice: 'd10' },
{ dice: 'd8' },
{ dice: 'd6' },
{ dice: 'd4' }
]);D100 (Percentile) Dice
// D100 automatically rolls two d10s
await diceRoller.roll([
{ dice: 'd100', rolled: 96 }
]);Custom Dice Colors
// Customize dice appearance with custom colors
await diceRoller.roll([
{
dice: 'd20',
diceColor: 0xff6b6b, // Red dice body
textColor: '#FFFFFF', // White text
backgroundColor: '#4ECDC4' // Teal background
},
{
dice: 'd6',
diceColor: 0x95e1d3, // Mint green dice body
textColor: '#2C3E50', // Dark blue text
backgroundColor: '#F38BA8' // Pink background
}
]);Secret Roll Mode
You can enable secret roll mode to hide all dice numbers with "?" characters. This is useful for GM rolls or surprise mechanics where you don't want players to see the actual result until revealed.
// Roll dice with secret mode enabled
await diceRoller.roll([
{ dice: 'd20', isSecret: true },
{ dice: 'd6', isSecret: true }
]);
// Mix secret and non-secret dice
await diceRoller.roll([
{ dice: 'd20', isSecret: true }, // Hidden
{ dice: 'd6', isSecret: false } // Visible
]);Note: The demo application includes a "Secret Roll" checkbox in the UI for easy toggling.
With Custom UI Controls
const diceRoller = new DiceRoller({
container: document.getElementById('dice-container'),
onRollComplete: (total) => {
document.getElementById('result').textContent = `Total: ${total}`;
}
});
// Button click handler
document.getElementById('roll-btn').addEventListener('click', () => {
diceRoller.roll([
{ dice: 'd20' },
{ dice: 'd6' }
]);
});
// Reset button handler
document.getElementById('reset-btn').addEventListener('click', () => {
diceRoller.reset();
});React Integration
import { useEffect, useRef, useState } from 'react';
import { DiceRoller } from 'open-dice-dnd';
function DiceComponent() {
const containerRef = useRef(null);
const diceRollerRef = useRef(null);
const [result, setResult] = useState(null);
useEffect(() => {
if (containerRef.current && !diceRollerRef.current) {
diceRollerRef.current = new DiceRoller({
container: containerRef.current,
onRollComplete: (total) => {
setResult(total);
}
});
}
return () => {
if (diceRollerRef.current) {
diceRollerRef.current.destroy();
}
};
}, []);
const handleRoll = () => {
diceRollerRef.current?.roll([
{ dice: 'd20' },
{ dice: 'd6' }
]);
};
return (
<div>
<div ref={containerRef} style={{ width: '100%', height: '500px' }} />
<button onClick={handleRoll}>Roll Dice</button>
{result && <p>Total: {result}</p>}
</div>
);
}Vue Integration
<template>
<div>
<div ref="containerRef" style="width: 100%; height: 500px;"></div>
<button @click="handleRoll">Roll Dice</button>
<p v-if="result">Total: {{ result }}</p>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { DiceRoller } from 'open-dice-dnd';
const containerRef = ref(null);
const result = ref(null);
let diceRoller = null;
onMounted(() => {
if (containerRef.value) {
diceRoller = new DiceRoller({
container: containerRef.value,
onRollComplete: (total) => {
result.value = total;
}
});
}
});
onUnmounted(() => {
if (diceRoller) {
diceRoller.destroy();
}
});
const handleRoll = () => {
if (diceRoller) {
diceRoller.roll([
{ dice: 'd20' },
{ dice: 'd6' }
]);
}
};
</script>🛠️ Development
Running the Demo
npm run devThen open your browser to http://localhost:5173
Building the Library
npm run build:libThis creates the distributable files in the dist/ directory:
open-dice-dnd.es.js- ES module formatopen-dice-dnd.umd.js- UMD format (for browsers and Node.js)
Building the Demo
npm run build📝 Dice Types
| Type | Description | Range |
|------|-------------|-------|
| d4 | 4-sided die | 1-4 |
| d6 | 6-sided die (standard cube) | 1-6 |
| d8 | 8-sided die | 1-8 |
| d10 | 10-sided die | 0-9 or 1-10 |
| d12 | 12-sided die | 1-12 |
| d20 | 20-sided die | 1-20 |
| d100 | Percentile die (two d10s) | 00-99 or 1-100 |
📝 Changelog
[1.1.0] - 2025-10-19
✨ New Features
Customization:
- 🌈 Added dice color customization support
diceColor: Customize dice body color (numeric hex format)textColor: Customize text color (hex string format)backgroundColor: Customize face background color (hex string format)
- 🔒 Added secret roll mode
- All dice numbers replaced with "?" characters
- Perfect for GM rolls or surprise mechanics
- Available via UI checkbox in demo
Demo UI Improvements:
- 🎨 Added color picker controls for easy color customization
- 🎯 Quick apply colors to all dice in configuration
- 📝 Multiple color preset examples
- ✨ Real-time color synchronization between pickers and hex inputs
[1.0.0] - 2025-10-03
🎉 Initial Release
Core Features:
- ✨ 3D physics-based dice rolling engine
- 🎲 Support for all standard RPG dice types (d4, d6, d8, d10, d12, d20, d100)
- 🎯 Realistic physics simulation using Cannon.js
- 🎨 Beautiful 3D rendering with Three.js
- 📱 Responsive design that works on any container size
API:
- 🔧 Class-based
DiceRollerAPI for easy integration - ⚡ Promise-based roll method for async/await support
- 🎪 Event callbacks for roll completion
- 🎛️ Customizable throw speed and spin
- 🧹 Automatic resource cleanup and memory management
Developer Experience:
- 📦 Available as npm package:
open-dice-dnd - 📚 Comprehensive documentation with examples
- ⚛️ React integration example
- 💚 Vue integration example
- 🎮 Live demo included
Build & Distribution:
- 📦 ES module format (7.83 kB gzipped)
- 🌐 UMD format for browser compatibility
- 🌲 Tree-shakeable exports
- 🔗 Peer dependencies for optimal bundle size
License:
- 📄 MIT License
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT License - see LICENSE file for details
🙏 Credits
Built with:
📮 Support
If you encounter any issues or have questions, please file an issue on the GitHub repository.
Made with ❤️ for tabletop gaming enthusiasts and web developers
