Skip to the content
PCBKitNew board
2 layers393.6 × 142.2 mmRoki, the printed circuit board in 3D

Custom wireless split ergonomic keyboard — PCB, case, CircuitPython firmware, companion tooling

Size
393.6 × 142.2 mm
Copper layers
2
Thickness
1.6 mm
Parts
156
Nets
118
Pads
678
Tracks, vias
835, 76
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
5 Sep 2024
Updated
20 May 2026

Overview

Roki is an open-source printed circuit board by rodrigokimura, from the rodrigokimura/roki repository on GitHub, published under the MIT licence. It is a 2-layer board of 393.6 × 142.2 mm with 156 parts on 118 nets, routed with 835 tracks and 76 vias.

Its parts include 62 switches, 60 diodes and 4 ICs. It belongs with the nRF52 and nRF5x boards of this library.

README

README.md

RoKi

An ergonomic, wireless, split mechanical keyboard — hardware, firmware and tooling in one repo.

RoKi (from the author's surname) is a custom, from-scratch split keyboard project. It covers the full stack: PCB design, 3D-printable case parts, CircuitPython firmware running on the nice!nano v2 (wireless Bluetooth Low Energy controller), and a companion Python CLI / web UI / TUI to flash, configure and debug the board.

⚠️ Status: Work in progress. Breaking changes are expected.


Features

  • Split layout with BLE-based inter-half communication (no TRRS cable).
  • 5 rows × 6 columns per half, diode matrix.
  • Thumb cluster with analog thumbstick (for pointer / scroll / layer control).
  • Rotary encoder on each half.
  • Piezo buzzer for audio feedback.
  • Layer system with custom layer_handler (tap / hold / toggle commands).
  • HID support for keyboard, mouse and consumer-control (media) keys, via adafruit_hid.
  • Per-side configuration (primary / secondary) selected via environment.
  • Runtime calibration of the analog thumbstick (deadzone, center, range).
  • Read-only filesystem toggle at boot, driven by a hardware switch, so you can hot-swap between "keyboard mode" and "developer mode" without rebuilding firmware.

Repository layout

text
roki/
├── roki/                    # Python package
│   ├── firmware/            # CircuitPython firmware (runs on nice!nano v2)
│   │   ├── boot.py          # Early boot: filesystem readonly switch
│   │   ├── code.py          # Main entry point, pin mapping
│   │   ├── kb.py            # Primary / Secondary keyboard classes
│   │   ├── keys.py          # HID key definitions and handlers
│   │   ├── layer_handler.py # Layer / Command system
│   │   ├── calibration.py   # Thumbstick calibration
│   │   ├── config.py        # Runtime config model + JSON loader
│   │   ├── service.py       # BLE service for half-to-half comms
│   │   ├── buzzer.py        # Audio feedback
│   │   ├── logging.py       # Color-coded adafruit_logging formatter
│   │   ├── params.py        # Env-based parameter singleton
│   │   └── config.json      # Default key map / layers
│   ├── cli/                 # Host-side CLI (typer)
│   │   ├── app.py           # `roki` command entry point
│   │   ├── utils.py         # Mount / unmount / lib install helpers
│   │   ├── file_management.py
│   │   ├── html_generator.py
│   │   └── logging.py
│   ├── tui/                 # Textual-based TUI key-map configurator
│   │   ├── app.py
│   │   ├── screens/

Hardware

ItemChoice
Microcontrollernice!nano v2 (nRF52840, BLE)
LayoutSplit, 5×6 + thumb cluster + encoder per half
SwitchesMX-compatible, hotswap
Inter-half commsBluetooth Low Energy (custom GATT service)
PowerLi-Po, per-half power switch
Analog inputThumbstick (X / Y + push)

PCB sources live in kicad/roki/. Case, keycaps and mechanical parts live in freecad/ as .FCStd files.


Firmware (CircuitPython)

Runs on CircuitPython for nRF52840. The firmware is structured around a Primary / Secondary pair of keyboard halves:

  • Primary holds the full config, scans its own matrix, talks HID over BLE to the host, and receives key events from the secondary over a custom BLE service.
  • Secondary scans its matrix and forwards events to the primary.

The side is chosen at boot via the IS_LEFT_SIDE environment variable (or the boot.py switch pin), so the same code runs on both halves.

Pin mapping

Defined in roki/firmware/code.py:

python
Roki(
    row_pins=("P0_24", "P1_00", "P0_11", "P1_04", "P1_06"),
    column_pins=("P0_09", "P0_10", "P1_11", "P1_13", "P1_15", "P0_02"),
    buzzer_pin="P0_06",
    thumb_stick_pins=("P0_22", "AIN7", "AIN5"),  # switch, X, Y
    encoder_pins=("P0_17", "P0_20"),
)

See the nice!nano pinout & schematic for reference.

Boot-time write protection

boot.py reads pin P0_22 on startup. When the switch is open the filesystem is mounted read-only (normal keyboard mode); when closed, read-write — useful for editing files over USB without your OS fighting CircuitPython.


Host-side tooling

A typer CLI is installed as roki:

sh
roki upload        # (alias: u)  Flash firmware + libs to the connected board
roki run           #             Launch the TUI key-map configurator
roki serve         #             Start the FastAPI + Jinja web config UI
roki generate      # (alias: g)  Generate static HTML / artifacts
roki config        #             Show / edit config.json

Install

sh
uv sync

(Uses uv as the package manager; Python 3.12+.)

Run the tests

sh
uv run pytest

With coverage:

sh
uv run pytest --cov=roki --cov-report=term

Current coverage: 88% across ~2.3k lines of source with 109 tests.

Run the web configurator locally (HTTPS)

sh
# Generate self-signed certs once
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365

uv run roki serve

Environment variables

Set in roki/firmware/settings.toml on the board, or via your shell for host-side runs:

VariableDefaultMeaning
IS_LEFT_SIDE11 for primary (left), 0 for secondary
DEBUG01 enables the stream logger
LOG_LEVEL0Standard logging levels (10 = DEBUG, etc.)

Development workflow

This repo uses commitizen for Conventional Commits and ruff for linting / import sorting.

sh
uv run cz commit            # interactive commit
uv run ruff check --fix .   # lint + autofix
uv run ruff format .        # format

Pre-commit hooks are configured in .pre-commit-config.yaml.


License

MIT © Rodrigo Eiti Kimura

Parts

156
QtyValueFootprintReferences
60DiodeScottoKeebs_Components:Diode_SOD-123D1, D2, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23 +44
58KeyswitchScottoKeebs_Hotswap:Hotswap_MX_1.00uS1, S2, S10, S11, S12, S13, S14, S15, S16, S17, S18, S19, S20, S21, S22, S23 +42
2Battery_CellBattery:BatteryHolder_MPD_BH-18650-PC2BT1, BT2
2BuzzerBuzzer_Beeper:Buzzer_TDK_PS1240P02BT_D12.2mm_H6.5mmBZ1, BZ2
2Nice_Nano_V2ScottoKeebs_MCU:Nice_Nano_V2U1, U4
2RotaryEncoder_SwitchRotary_Encoder:RotaryEncoder_Alps_EC11E-Switch_Vertical_H20mmSW1, SW3
2SW_SPDTButton_Switch_SMD:SW_SPDT_PCM12SW2, SW4
2~Library:thumb_stickU2, U3

The 130 most common of 156 parts.

Questions

How big is the Roki PCB?

It measures 393.6 × 142.2 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Roki use?

156 parts. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Roki KiCad files?

From the rodrigokimura/roki repository on GitHub, at the commit this page was made from: the board is kicad/roki/roki.kicad_pcb and its schematic kicad/roki/roki.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Roki design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers65 × 100 mmJOVE, the printed circuit board in 3D

    JOVE

    minisystem/JOVE

    Eurorack multimode filter inspired by the Roland Jupiter-6

    156 parts109
  • 2 layers85 × 56.5 mmAIOR, the printed circuit board in 3D

    AIOR

    GBert/misc

    miscellaneous stuff / unsorted

    156 parts99
  • 2 layers109 × 71 mmGamma split, the printed circuit board in 3D

    Gamma split

    ahtn/keyboard_pcb

    156 parts96
  • 2 layers313.3 × 131.6 mmKBIC65, the printed circuit board in 3D

    KBIC65

    b-karl/KBIC65

    65% keyboard PCB with ProMicro footprint. Through-hole kit design with focus on wireless.

    156 parts67MIT
  • 2 layers191.2 × 129.5 mmJonkey v2, the printed circuit board in 3D

    Jonkey v2

    AtomicJon/jonkey

    The JONKEY is a columnar split keyboard created using ergogen.

    156 parts33
  • 2 layers361 × 120.7 mmTrifecta, the printed circuit board in 3D

    Trifecta

    swiftrax/Trifecta

    Open source Alice like mechanical keyboard with arrow keys and support of up to 3 rotary encoders

    156 parts32GPL-2.0
  • 2 layers90 × 38 mmKampela, the printed circuit board in 3D

    Kampela

    Alzymologist/Kampela

    Hardware signer and key storage for Substrate ecosystem

    156 parts21GPL-3.0