Smart Dice is a 3D digital dice roller built on the ESP32, designed around the rules of African ludo; a game deeply rooted in Nigerian and West African culture. The dice is rendered as a true rotating 3D cube on a 240x240 TFT display. Shaking the device triggers a roll, just like a real dice. The project supports 4 players and implements the classic rule where rolling three consecutive 6s gets you suspended for a round.
This was my first Hackster.io post, built entirely in Arduino IDE with modular code split across multiple files.
HOW IT WORKSThe MPU6050 reads accelerometer data every loop iteration. When the total acceleration magnitude across all three axes exceeds a threshold, a roll is triggered. The randomizer is seeded with a combination of millis() and live accelerometer values for better randomness and to avoid repeating the same number consecutively.
The 3D cube is rendered using perspective projection, and faces are sorted back to front using the painter's algorithm so near faces always paint over far ones.
A TFT_eSprite offscreen buffer renders only the cube region (not the full screen), which preserves surrounding UI text without flicker and works within ESP32 heap constraints.
GAME RULESSmart Dice implements these African ludo rules:
- Each player shakes the device to roll
- Rolling 6 once or twice grants an extra roll
- Rolling 6 three times in a row results in suspension for one full round
- Suspension lifts automatically when the turn comes back around
- The six-streak counter resets on any non-6 roll
The biggest challenge was the 3D face snapping. The cube would decelerate and stop, but the visible face rarely matched the announced result. Three separate bugs contributed: the target angle table did not align with the face value mapping, the result was being forced onto one specific face by overwriting the value map each roll, and the snap function was rounding to the nearest 90 degrees without checking which face that actually corresponded to. The final fix was to search the face value array for the result number, find its index, and lerp the angles toward that face's pre-defined orientation.
Memory was another challenge. A full 240x240 16-bit sprite requires 115KB of contiguous RAM. The ESP32 has enough total RAM but heap fragmentation means that contiguous block often does not exist. The solution was to set the sprite color depth to 8-bit and size it to the cube region only rather than the full screen.
WHAT'S NEXT- True raycast 3D rendering upgrade (already in progress)
- BLE WiFi provisioning so players can set up the device from a phone
- Sound effects via a small buzzer
- Persistent score tracking across rounds using NVS















Comments