npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

open-dice-dnd

v1.1.2

Published

A 3D physics-based dice rolling engine built with Three.js and Cannon.js

Downloads

29

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-dnd

Local 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 configurations
    • dice (string): Type of die - 'd4', 'd6', 'd8', 'd10', 'd12', 'd20', or 'd100'
    • rolled (number, optional): Target number for the roll
    • diceColor (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 dev

Then open your browser to http://localhost:5173

Building the Library

npm run build:lib

This creates the distributable files in the dist/ directory:

  • open-dice-dnd.es.js - ES module format
  • open-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 DiceRoller API 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