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 :
-
flexandjustify-centerfor alignment -
w-3 h-3 bg-black rounded-fullfor perfect dots -
gap-1andp-2for 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