Up until now, whenever I had to create a dice roll, I’d just reach for Math.random() multiply it by 6, add 1, and wrap it in Math.floor() to get a whole number between 1 and 6. Simple and done.

Something like this:

const rollDice = () => Math.floor(Math.random() * 6) + 1; 

Functional Yes,
Exciting? No.
Does it connect my target audience i.e Toddlers with the real dice? No.

A real dice is n’t a number, it has dots. so my next goal was to create a different dice with faces from 1 to 6 in TailwindCSS and to render them conditionally based on the rollDice value.

I used Tailwind built-in classes such as :

  • flexand justify-center for alignment
  • w-3 h-3 bg-black rounded-full for perfect dots
  • gap-1 and p-2 for spacing

and created 6 faces as follow:

const Face = ({ value }: { value: number }) => { switch (value) { case 1: return ( <div className="flex justify-center align-center gap-1 w-full h-full p-2"> <div className="flex items-center justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> ); case 2: return ( <div className="flex justify-between gap-1 w-full h-full p-2"> <div className="flex self-start items-center justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> ); case 3: return ( <div className="flex justify-between gap-1 w-full h-full p-2"> <div className="flex self-start items-center justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-center items-center justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end items-center justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> ); case 4: return ( <div className="flex justify-between gap-1 w-full h-full p-2"> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-start items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-start items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-end items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> </div> ); case 5: return ( <div className="flex justify-between gap-1 w-full h-full p-2"> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-start items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-start items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> <div className="flex flex-col gap-1 justify-center"> <div className="flex self-start items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-end items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> </div> ); case 6: return ( <div className="flex justify-between gap-1 w-full h-full p-2"> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-start items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-start items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-start items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> <div className="flex flex-col gap-1 justify-between"> <div className="flex self-end items-start justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> <div className="flex self-end items-end justify-center"> <div className="w-3 h-3 bg-black rounded-full"></div> </div> </div> </div> ); default: return null; } }; 

Creating the roll animation

At first, I was thinking of going fancy with Framer Motion or even something 3D like React Three Fiber.

But for this stage, I kept it simple, just used setIntervalto switch the dice face every 100ms for a second.
After that, I’d clear the interval with clearInterval, calculate the final value, and lock it in.

And to stop curious minds from rolling the dice again mid-animation, I added a local React state to track whether the dice is currently rolling.

 const [diceValue, setDiceValue] = useState(1); const [isRolling, setIsRolling] = useState(false); const rollDice = () => { if (isRolling) return; setIsRolling(true); // Animate dice roll const rollAnimation = setInterval(() => { setDiceValue(Math.floor(Math.random() * 6) + 1); }, 100); setTimeout(() => { clearInterval(rollAnimation); const finalDiceValue = Math.floor(Math.random() * 6) + 1; setDiceValue(finalDiceValue); setIsRolling(false); }, 1000); }; 

In the end, I wired up a click event on the dice itself and also on a separate “Roll a Dice” button, just to give players multiple ways to get the dice rolling.

This is all part of a Snakes and Ladders game I’m building, which I’ll be sharing soon!


Source: DEV Community.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.