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

react-roll-the-dice

v0.1.1

Published

Zero-dependency 3D dice roller for React, rendered entirely in CSS.

Readme

react-roll-the-dice

npm bundle size types license demo

A 3D dice roller for React with no runtime dependencies. The die is a real CSS cube — six positioned faces under transform-style: preserve-3d — and the throw is plain CSS motion. No canvas, no WebGL, no physics engine, no animation library.

npm install react-roll-the-dice
import { useRef } from 'react'
import { Dice, type DiceHandle } from 'react-roll-the-dice'

function Board() {
  const dice = useRef<DiceHandle>(null)

  return (
    <>
      <Dice ref={dice} size={120} onRollEnd={(value) => console.log(value)} />
      <button onClick={() => dice.current?.roll()}>Roll</button>
    </>
  )
}

No stylesheet import required — the component renders its own <style> tag.

Why it has no dependencies

dependencies is empty, and react is the only peer. Even react-dom is absent, because nothing here reaches for a DOM renderer API. Installing this adds exactly one package to your tree, and about 6 kB gzipped to your bundle — component and stylesheet together.

API

<Dice />

| Prop | Type | Default | | |---|---|---|---| | size | number \| string | 80 | Layout box the die is drawn to fit. Numbers mean pixels. | | defaultValue | DiceValue | 1 | Face shown before the first roll. | | duration | number | 1400 | Roll length in ms. | | faceColor | string | #fdfdfb | Any CSS color. | | pipColor | string | #16181d | Any CSS color. | | rollOnClick | boolean | false | Makes the die clickable and keyboard-operable. | | injectStyles | boolean | true | Set false to supply the CSS yourself. | | nonce | string | — | Forwarded to the injected <style> tag for CSP. | | random | () => number | — | Custom RNG in [0, 1), for seeded or reproducible rolls. | | onRollStart | (value) => void | — | Fires with the value the roll will land on. | | onRollEnd | (value) => void | — | Fires when the die settles. |

Any other div prop (className, style, id, aria-label, …) is forwarded.

Ref handle

interface DiceHandle {
  roll(): DiceValue        // starts a roll, returns the result synchronously
  set(value: DiceValue): void  // jump to a face with no animation
  readonly value: DiceValue
  readonly rolling: boolean
}

roll() returns the result immediately, so you can update game state without waiting for the animation. Use onRollEnd when you want to reveal it only once the die has settled.

Rolling again mid-animation is fine — the die re-targets from wherever it is. onRollStart fires once per call, but onRollEnd fires once per landing, so a burst of rolls produces a single settle event carrying the final value.

rollDiceValue(random?)

The generator on its own, if you want to roll without rendering. Uses crypto.getRandomValues with rejection sampling — folding the leftover byte values in with a plain modulo would make 1–4 come up slightly more often than 5–6, which is a loaded die.

Styling

Every visual is a CSS custom property on the .rtd-scene element, so you can theme it without touching props:

.rtd-scene {
  --rtd-face-color: #1e2130;
  --rtd-pip-color: #ffd9a0;
  --rtd-view-x: -44deg;   /* camera pitch */
  --rtd-view-y: 30deg;    /* camera yaw   */
  --rtd-fit: 0.58;        /* die scaled to fit that box     */
  --rtd-ease: cubic-bezier(0.18, 0.9, 0.24, 1.04);
}

Flattening --rtd-view-x toward 0deg swings the camera round to eye level. The result still sits on the top face, so a shallow pitch makes it harder to read, not easier.

Content Security Policy

The inline <style> needs style-src. Either pass a nonce:

<Dice nonce={cspNonce} />

…or turn injection off and import the stylesheet yourself:

import 'react-roll-the-dice/styles.css'

<Dice injectStyles={false} />

Notes

  • Server rendering. The stylesheet is part of the rendered output, so there is no flash of unstyled dice. The component is marked "use client" and works as a client component in the Next.js App Router.
  • React 19. The <style> tag carries href and precedence, so React hoists and de-duplicates it — many dice on a page produce one tag in <head>. React 17 and 18 render it inline instead, which is harmless.
  • Reduced motion. Under prefers-reduced-motion: reduce the tumble is skipped and the result appears immediately. onRollEnd still fires.
  • The result is the top face. The camera looks down at the die, so you read it the way you read a die on a table — no need to work out which of the visible faces is the one that counts.
  • Fair and physical. Opposite faces sum to 7 and the die is right-handed, the Western convention. Each throw picks its own spin counts and landing angle, so no two rolls trace the same arc.

License

MIT