Games in the Round: a Gaming Platform from the M5Stack Dial's Bezel and Round Screen

Series: alt.ctrl activities

Bezel and round-screen interactions have been around for decades, and for hundreds of years if compasses and related navigational tools count, but they have not been used much for gaming or playful interaction. This is a good opportunity for design in the round, pushing back on the Cartesian hegemony of much computer GUI.

Knobs have long driven games, from Pong's paddles to Atari's Tempest (1981), whose player snaps from lane to lane round a tube seen end-on as a rotary knob turns; but on rectangular screens. Pie menus set choices round a centre (Callahan, Hopkins, Weiser and Shneiderman, CHI '88). Nest's Learning Thermostat (2011) put a ring that turns and presses in, round a display at the centre of its circular face (Nest's patent). Samsung's Gear S2 (2015) then put a turning ring round a circular watch screen, and Samsung's design guidance for the rotating bezel of its later watches lists "Create a game based on bezel utilization." among its examples.

There are plenty of hardware platforms to build from that combine a rotary encoder with a round watch screen. This recipe starts from M5Stack's Dial, a round touch screen inside a ring that turns and clicks, with Wi-Fi, a buzzer, a clock, an RFID reader and a battery connector. Its microcontroller is a module that can be replaced: M5Stack's Stamp, an ESP32-S3 today, which plugs into two rows of 1.27 mm sockets.

Two games for it were written with a coding assistant: GearJam, from a paragraph and then seventeen rounds of playing and asking for changes, in which the ring rolls a bat round a central hole to bounce a ball into a turning gear and jam it; and Vortex Pinball (pictured), from one more paragraph and two rounds, a pinball table that slopes into a vortex. The pictures are the games' own frames, drawn on a computer by the same code that draws them on the Dial.

Both games run on the Dial. Several players need no server, because each Dial has Wi-Fi built in.

A round screen inside a steel rim: a dark table with a teal vortex at the centre ringed by a thin arc with two flippers and two green triangles, grey wedges at the rim, red posts and gold stars, a curved lane at the right, a gold ball above a lit kicker with +100 beside it, a +10, a 3 in the vortex, three of five ball dots lit and the score 110 at the bottom.
Vortex Pinball, a game for the Dial: the table slopes into the vortex at the centre, where the ring turns a pair of flippers. The game's own frame, drawn on a computer by the Dial's drawing code, enlarged twice, pixel for pixel.

Materials

The Dial, its battery and its case
ItemAmazonAdafruitM5StackThe Pi Hut
M5Stack Dial: a 1.28-inch, 240 × 240 round touch screen inside a ring that turns in 16 detents and clicks, an ESP32-S3 on M5Stack's Stamp module (the Stamp-S3, or the Stamp-S3A on version 1.1) with 8 MB of flash and Wi-Fi, a buzzer, a real-time clock, an RFID reader, two Grove ports and a 1.25 mm 2-pin battery socket; it comes with an M2 hex wrench5966Dial v1.1Dial v1.1
A protected single-cell 3.7 V LiPo with a 1.25 mm 2-pin plug, small enough to sit under the Dial in the case: for example, a 400 mAh AKZYTUE PL802525 (8.6 × 25 × 25 mm, a 200 mA charging limit) or The Pi Hut's 500 mAh PKCell cell (35 × 30 × 5 mm)B0FRFY1F76500 mAh PicoBlade
A 1.25 mm 2-pin cable pair, PicoBlade-compatible, in case the cell's plug does not mate with the Dial's socket47204720
Filament for the case: PCTG
Another Dial for each extra player (optional)

Tools

  • A computer with the Arduino IDE or arduino-cli, Espressif's ESP32 core, and M5Stack's M5Unified and M5GFX libraries
  • A USB-C cable
  • A multimeter, for the battery's polarity
  • The M2 hex wrench that comes with the Dial, to open it
  • A 3D printer and its slicer, such as a Bambu A1
  • A coding assistant, given the Coding Prompt Build Block below

Skills

  • Programming an ESP32 with Arduino (C++)
  • Geometry in polar coordinates: angle and radius
  • Game physics: motion, collision and reflection
  • Handling lithium-polymer cells safely
  • 3D printing a threaded part
  • Programming with a coding assistant

Instructions

  1. Learn the Dial's controls: the ring turns in 16 detents (its encoder is on GPIO 41 and 40, A and B in M5Stack's listing; swap them if turning clockwise counts down) and clicks as a button when pressed down (GPIO 42, which M5Unified reads as BtnA), and the screen senses touch. The RST button resets the board, and holding the Stamp's G0 button while powering on enters download mode.
  2. Set up the tools: Espressif's ESP32 core and M5Stack's M5Unified and M5GFX. The games pictured were built with core 3.3.12, M5Unified 0.2.23 and M5GFX 0.2.30; newer M5Unified releases ask for a newer M5GFX. Build for the Dial with its 8 MB of flash: esp32:esp32:m5stack_dial:FlashSize=8M,PartitionScheme=default_8MB.
  3. Before each upload, check that the board on the port is the Dial: have the game print the board it finds at start (M5GFX names it board_M5Dial). A port name is not an identity: a build can go onto another ESP32-S3 board that way.
  4. Design in the round: place everything by angle and radius from the screen's centre, not by x and y; let the ring turn things round the centre; keep the click for the main action and a long hold of it for leaving to a menu; and put text near the centre, since the screen has no corners.
  5. Write the pinball in the round with a coding assistant, from the Coding Prompt Build Block below; this is Vortex Pinball. The table is a cone sloping into a vortex at the centre instead of a straight slope. Five balls are served one at a time, thrown round the rim by spinning the ring. Falling inward they meet triangular wedges at the edge, active kickers that hit the ball, slingshots, drop targets, posts, a noisy spinner gate and star rollovers. The ring turns a pair of flippers round the vortex and the click flips them; keep a gap between the flippers that a ball can drain through: that annoying aspect of pinball.
  6. Play-test on the computer as well as on the Dial: these games draw their frames on the computer with the same drawing code (the pictures here) and also run in a browser, so a change can be seen and played before it is flashed. Tune by playing, one change at a time.
  7. Keep the Dial on when it runs from the battery: at start the game sets the HOLD pin, GPIO 46, high, or the Dial goes back to sleep. On battery, pressing the ring (the WAKE button, on GPIO 42) or the clock's alarm wakes it, and RST, or HOLD set low, turns it off.
  8. Add a menu: a long hold of the ring's click opens it, to change a game's settings, to switch games once there is a second (such as GearJam, in the variations), and to turn the Dial off with an Off item that saves, then sets HOLD low, since the RST button ends up inside the case (on USB power the Dial stays on). Keep the settings in the ESP32's flash (NVS) so they survive power-off, and write them only when they change; the games pictured save their running counts at once when the menu opens, when it closes with a changed setting, on a new best and on Reset counts, and otherwise at most once a minute, to spare the flash.
  9. Find the battery socket's polarity before connecting any cell. Open the Dial with the M2 hex wrench: the 1.25 mm 2-pin socket is inside, under the Stamp module. M5Stack's schematic makes pin 1 the battery's positive and pin 2 ground, but nothing marks which side is pin 1. With nothing connected (no cell, no USB, nothing on the power terminal on the back), set the multimeter to resistance, not its continuity beeper, which can chirp on pin 1 while a capacitor there charges. Check a ground first: the USB-C shell to pin 4 of a Grove port (the black wire) reads as the shorted leads; if it does not, stop. Then measure each socket pin to that ground, in both lead orders: ground reads as the shorted leads, steadily, both ways. The cell's black wire goes to that pin; if a lead is reversed, swap the crimped pins in its housing. Never plug a cell in reversed to find out.
  10. Connect the battery. The cell must carry its own protection board: the Dial has none on the battery line. The Dial charges it from USB-C through its TP4057 at about 100 mA (10 kΩ on PROG, from one maker's datasheet, which gives 90 to 110 mA), so choose a cell with a charging limit of at least 110 mA: for a cell rated to charge at 0.5C, 220 mAh or more. Both JST GH and PicoBlade-type plugs come up for this socket on M5Stack's forum; the socket drawing M5Stack links matches PicoBlade's width, by KiCad's footprint. So before any cell's plug goes near the socket, with nothing connected, measure the socket across its side tabs: about 7.55 mm is PicoBlade-type, about 5.75 mm is JST GH. Tell the plug's family by its face, not its listing, which may name both: a JST GH plug has a latch window, a PicoBlade-type plug friction ramps. Use a cell whose plug is the same family, or fit the cable pair, cutting and joining one wire at a time, and push the plug home only with its black wire on the ground pin; never push in a plug that can seat either way round. The Dial cannot report the charge left: the Stamp has no fuel gauge. Even though these are small LiPo cells, the Dial should travel in your carry-on when flying, not in checked baggage; and the FAA's rule for US flights puts spare cells, or a cell unplugged for the trip, in the carry-on too, with their plugs covered (check the airline's).
  11. Print a case that holds the Dial and the battery in a pleasing form to play with: a round container the Dial screws into in place of its own threaded ring, with the battery below and a slot for the USB-C port. Take the thread from M5Stack's published model of the Dial (M5_Hardware, MIT): in that model the thread is right-handed, one start, with a 2.6 mm lead. Print a test coupon of the thread at several clearances first, face down at 0.12 mm layers, and keep the clearance that turns freely without play. Check whether and where the cell's lead can leave the closed Dial (extend it with the cable pair if needed), and how warm the cell gets charging in the closed case; until that is known, charge it with the case open and stay nearby.
  12. Play with others without a server: Dials can talk directly over Wi-Fi with Espressif's ESP-NOW, with no router: up to 20 paired peers, and broadcasts that every Dial in range receives, 250 bytes a message in its first version. The Arduino core's examples include a network whose Dials elect a host among themselves. One Dial can also be the access point for the others, with UDP or OSC messages between them.
  13. Play: one hand turns the ring, a thumb clicks it.
Four round pinball frames: a ball thrown along the rim with a gold arc of launch power; a ball by the flippers with +1; a ball through the spinner gate at the right with +5; a ball by a lit star with +25, a +50 at the orange bar at the bottom and a +10, and the score 135.
Playing Vortex Pinball: a ball thrown round the rim by spinning the ring, a flip, the spinner gate, and targets. The game's own frames, at the screen's 240 × 240.

Variations

  • Another round platform: LilyGO's T-Encoder-Pro, a knob with a 2.04-inch round AMOLED touch screen that turns, with a beeper, on an ESP32-S3 with 8 MB of PSRAM. LilyGO says the knob clicks and has a vibration motor; check both before designing around them: pressing the knob body does nothing, so try pressing the screen's very centre. Or a round touch screen such as Seeed's Round Display for XIAO, with a rotary encoder added.
  • GearJam, the first of the two games (pictured): a bat rolled round the hole, a ball, a wrench or other bodies to bounce, and gears to jam.
  • Upgrade an original Dial's Stamp-S3 to the Stamp-S3A, the module Dial v1.1 ships with; the version with 1.27 mm pins (S007-PIN127-V033) plugs into the same sockets. M5Stack's comparison gives it an optimised antenna with better signal reception, for play over Wi-Fi, and a lower draw: on standby about 25.5 mA against 33 mA. Set GPIO 38 high before using its RGB LED. A Stamp built on Espressif's newer ESP32-S31 is expected in early 2027.
  • Read the Dial's RFID reader to choose a game or a player with a card. M5Stack recommends tags of bank-card size.
  • Use the Dial as a controller instead: CNMAT's M5DialOscuino example sends the ring, the click and touch as OSC over USB, and draws on the screen from OSC.
Four round frames: a dark field inside a steel ring gear with a small gold pinion at the top right and a gold ball by a curved bat round the central hole; the ball jammed between the gears with a red 8; a wrench in flight; and a settings menu with Game, Vortex Pinball highlighted between arrows.
GearJam, the first of the two games for the Dial: roll the bat round the hole with the ring and bounce the ball, or a wrench, into the gears to jam them; and the menu that switches between the two games.

Related resources

Coding Prompt Build Block

A prompt to give a coding assistant, to start the code for this activity. Copy the box, answer its questions about your board and pins, and test what comes back on the bench before you rely on it.

I am building "Games in the Round: a Gaming Platform from the M5Stack Dial's Bezel and Round Screen", the activity at https://adrianfreed.com/dial-games-in-the-round.html.

Help me make a game for the M5Stack Dial: a round 240 × 240 touch screen inside a ring that turns in 16 detents and clicks, with an ESP32-S3. Design it in the round: place things by angle and radius from the screen's centre, not on a grid, let the ring turn things round the centre, and keep text near the centre, since the screen has no corners.

The game is pinball on a cone: the table slopes down into a vortex at the centre instead of down a straight slope. Five balls are served one at a time, thrown round the outside edge by spinning the ring. As they fall toward the centre they meet triangular wedges at the edges and active kickers that hit the ball, as in a pinball machine. A pair of flippers near the vortex is turned round it by the ring and flips when the ring is clicked; leave a gap between them that a ball can drain through. A ball lost to the vortex is a life; score points for each hit. Ask me the sizes, speeds, how lossy the walls are and the points, and let me tune them by playing.

Read the ring's encoder on GPIO 41 and 40 (swap them if turning clockwise counts down) and its click on GPIO 42 (M5Unified's BtnA), and touch through M5Unified. Draw each frame into an off-screen sprite with M5GFX and push it whole. A long hold of the click opens a menu to change settings, and to switch games once there are two; keep the settings in flash (NVS), written only when they change.

On battery the Dial stays on only if the game sets GPIO 46 (HOLD) high at start; give the menu an Off item that saves anything not yet saved, such as scores, then sets it low (on battery; on USB power the Dial stays on), since the RST button will be inside the case. Print the board's identity at start, so I can check that the right board is on the port before each upload.

Keep the physics apart from the drawing, so that it builds and runs on a computer too, with tests, and render frames to image files there to check the look before flashing.

Later, for several players without a server, the Dials can send each other short messages over ESP-NOW: ask me what each Dial sends and who keeps the score.

Libraries to explore:

  • M5Unified: M5Stack's library for its controllers' built-in hardware; on the Dial, the display (through M5GFX), touch, the ring's click as BtnA, the buzzer, power and the RTC (the Dial has no motion sensor); it needs M5GFX (https://github.com/m5stack/M5Unified)
  • M5GFX: M5Stack's graphics library, with the Dial among its boards; an M5Canvas, its sprite (LovyanGFX's LGFX_Sprite), draws a frame off screen to push to the display at once (https://github.com/m5stack/M5GFX)
  • M5Dial: a thin library for the Dial over M5Unified (display, touch, power, RTC, speaker, the ring's click) that adds the encoder on pins 41 and 40 and the RFID reader (https://github.com/m5stack/M5Dial)
  • Arduino-ESP32 ESP_NOW library: Espressif's connectionless messages between ESP32s, with no router or access point: to paired peers or as broadcasts; its examples include a broadcast sender and receiver, and a network whose devices elect a host by their MAC addresses (https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP_NOW)
  • OSC for Arduino (CNMAT): encodes and decodes OSC messages, and sends them over USB or hardware serial (framed with SLIP) or over Ethernet and Wi-Fi UDP; its Applications folder has Max/MSP and Pd examples that receive them (https://github.com/CNMAT/OSC)

Before writing anything, ask me what I am using: the board and its pins, or the software (such as Max, Pd or Python), and check its documentation for what this needs. Put the pin numbers, ranges and other settings in one block at the top, each with a comment. Say which of the libraries above you use, and why. Start with a test that shows the raw readings, so that I can check the wiring and the ranges before the rest.

This activity by Adrian Freed is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0): you may share and adapt it with attribution, for non-commercial purposes such as personal projects and teaching, and you must share adaptations under the same licence. Product names and links belong to their suppliers.

Design strategies: