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.

Creating the Faces

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 (
                    
                        
                            
                        
                    
                );
            case 2:
                return (
                    
                        
                            
                        
                        
                            
                        
                    
                );
            case 3:
                return (
                    
                        
                            
                        
                        
                            
                        
                        
                            
                        
                    
                );
            case 4:
                return (
                    
                        
                            
                                
                            
                            
                                
                            
                        
                        
                            
                                
                            
                            
                                
                            
                        
                    
                );
            case 5:
                return (
                    
                        
                            
                                
                            
                            
                                
                            
                        
                        
                            
                                
                            
                        
                        
                            
                                
                            
                            
                                
                            
                        
                    
                );
            case 6:
                return (
                    
                        
                            
                                
                            
                            
                                
                            
                            
                                
                            
                        
                        
                            
                                
                            
                            
                                
                            
                            
                                
                            
                        
                    
                );
            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!