Alex Grinman
Founder & Engineer
[Index]2026-09-07

~*~

Building tinykeys: a programmable RGB keypad

I built tinykeys, a little nine-key keyboard for my Mac. It has clicky blue switches, translucent keycaps, and an RGB panel underneath. Press a key and the panel lights up in its color while the Mac runs a shortcut or opens an app. You could give Terminal its own button, put a screenshot shortcut on another, and make both an unreasonable shade of pink.

Inside is a Seeed Studio XIAO ESP32C3, nine handwired switches and an LED panel. I printed the case and keycaps, then wrote a Mac app for choosing the colors and assigning actions. You can change what a key does without taking the case apart or uploading new firmware.

Here's how to build one. The project files include the printable parts, firmware and Mac app, with the exact dimensions and wiring details if you're following along at the workbench.

Print the case and keys

I designed the parts in Python using Codex, text-to-cad and build123d. The case, switch plate and keycaps share their dimensions in code, so changing the layout doesn't mean updating three unrelated models. You can edit those models, or go straight to the ready-to-print files in hardware/stls/.

CAD assembly of tinykeys with its translucent plate and keycaps.

The parts stacked in CAD. The four screws that hold the plate to the case aren't shown.

The case is about three inches square. The LED panel sits inside, facing up, and the switches clip into a removable plate above it. Four screws hold the plate down. The XIAO sits at the front, where you can plug a USB cable directly into it.

Start by printing one keycap and the little corner test piece included with the files. Those let you check the switch fit and screw closure before printing the whole enclosure. It's much nicer to discover a tight fit on a little test piece than on a finished case.

Then print the base, switch plate and nine caps. Use translucent filament for the plate and caps so the light can get through. The files are already oriented for printing; the printing guide covers settings and fit adjustments.

I used PT Mono for the letters, cutting them into the caps while leaving a thin layer of plastic underneath. The light shines through that layer. Try the test cap over the panel too, since the switch and stem can cast shadows on the lettering.

My caps read A J G across the top, then 1 through 6. Those labels are just labels; the Mac app decides what they do.

Wire nine keys with six wires

A switch is just a connection that closes when you press it. We could give every key its own input, but that would use nine pins on a very small board. A 3×3 matrix gets us down to six: three rows and three columns.

The board checks one row at a time. If it selects the top row and sees the center column connected, it knows you've pressed J. It doesn't need a dedicated J wire.

Clip the switches into the plate before soldering. One terminal of each switch joins its column wire; the other connects through a diode to its row wire. The diode's band faces the row. Each switch needs its own diode to prevent false presses when several keys are held. QMK's matrix explanation shows how this works.

Underside CAD showing the six matrix buses and nine diodes.

The wiring from underneath. The keys are mirrored here; board placement is illustrative and power wiring isn't shown.

Label the rows and columns before flipping the plate over. From underneath, the top row reads G J A. Insulate wire crossings and exposed diode leads, and leave enough slack to lift the plate later. No switch terminal goes to 5 V.

Add some color

The panel has 64 LEDs, even though there are only nine keys. They all take the color of the key you press, so the whole keypad changes color together. Hold several keys and the most recently pressed one wins. Release them all and the panel turns off.

The XIAO sends data at a lower voltage than the panel uses. A small level-shifting chip, the 74AHCT125, bridges that difference. The wiring guide covers its connections and the resistor and capacitors around it. For this build's companion firmware, use D0 for LED data where the older guide says D8. Follow the pull-up and reset checks in the companion notes; that pin also affects how the board starts.

Power the XIAO over USB and the panel and buffer from a separate, current-limited 5 V supply. Connect their grounds, but don't join their 5 V rails. Run LED power directly from the supply, never through a GPIO or the board's 3V3 regulator. Power the panel and buffer before sending LED data, and stop data before turning their supply off. The firmware limits brightness, but that isn't current protection.

There's room for a battery and gyro in the CAD, but neither is used in this wired build. Leave the battery disconnected; portable power needs its own verified charging and protection circuitry.

Connect it to the Mac

With the power disconnected, check for shorts and inspect the diode and capacitor polarity. Keep the case open while you get the electronics running.

The firmware is Arduino C++ with Adafruit NeoPixel handling the lights. It scans the rows and columns and gives each switch a moment to settle before reporting a press. Mechanical contacts can bounce, and one click should count as one press.

Use the firmware build and upload instructions to load it onto the XIAO over USB. Close the Mac app or serial monitor before uploading so the port is free.

The ESP32-C3 can't act as a regular USB keyboard through its built-in USB peripheral. Instead, it sends a small message to the Mac when a key changes:

KEY 0 DOWN
KEY 0 UP

That's a press and release of the top-left key. The Mac app receives those messages and turns them into actions.

Give each key a job

I built the editor in SwiftUI. Follow the Mac app setup instructions, open it, select the keypad's USB port and click Connect.

tinykeys Mac app showing key assignments and color controls.

The editor in offline demo mode.

Click a key, pick its color, and choose Shortcut or Open App. For a first assignment, give it an app you can easily recognize when it opens. Once that works, try recording a shortcut.

Enable key actions, then switch away from the editor before pressing the physical key. Actions pause while you're configuring them, so recording a shortcut doesn't also fire it. Keyboard shortcuts need macOS Accessibility permission; opening apps doesn't.

Assignments save automatically on the Mac. Save LEDs to device stores the colors and brightness on the board. That's why changing a key from “open Terminal” to a screenshot shortcut doesn't require another firmware upload.

Closing the window leaves tinykeys running in the menu bar. Quitting stops the actions, and you'll need to enable them again when you next launch it.

Close it up

Try every key with the case still open. Hold a few together, check their actions and colors, and make sure saved colors survive a power cycle. These checks are much easier while you can still reach the wiring.

Fit the XIAO at the front opening and try your actual USB cable before securing the board. Seat the LED panel on its supports, then lower the wired switch plate. Keep wires clear of the screws, tighten them lightly, and fit the caps. Every key should press all the way down without rubbing.

Now you can enjoy your own customized mechanical macro pad.

Share:[X][HN][Reddit]