A personal ZMK (Zephyr Mechanical Keyboard) firmware configuration repository for building custom keyboard firmware. It supports a Cheapino v2, Ergonaut One, and stock Kinesis Advantage 360 Pro with OS-aware home row modifiers, platform-optimized navigation, and automated visual keymap diagrams.
The development environment is streamlined using Nix for reproducible isolation,
direnv for automatic environment activation, and Just for task automation. It
includes declarative build matrices in build.yaml and automated keymap drawing
with keymap-drawer.
- β¨οΈ Keymaps
- π οΈ Features
- π Installation
- π Usage
- π€ GitHub Actions
- π¨ Customization
- π Glossary
- π€ Contributing
- π License
Generated diagrams (via just draw) for the keyboards currently configured in
this repo:
| Keyboard | Description | Keymap Diagram |
|---|---|---|
| Cheapino v2 | rp2040_zero + local cheapinov2 shield |
|
| Ergonaut One | xiao_ble//zmk left/right shields |
|
| Kinesis Advantage 360 Pro | upstream adv360pro_{left,right}//zmk boards |
- Cross-Platform Support: Cheapino and Ergonaut have separate Windows and macOS layers; the Advantage 360 Pro intentionally uses a simpler Windows-first map.
- Home Row Modifiers: Ergonomic modifier placement for efficient typing.
- Navigation Layers: Dedicated layers for arrows, paging, and media keys.
- Number Layers: Quick access to numbers and function keys.
- Visual Keymap Diagrams: Automatically generated SVG diagrams using keymap-drawer.
- Reproducible Environment: Nix-based setup ensures consistent development across machines.
- Automated Builds: Declarative build matrix in
build.yamlfor easy firmware generation.
-
Clone the repository:
git clone https://github.com/kaiiiiiiiii/zmk-config.git cd zmk-config -
Allow direnv to load the environment:
direnv allow
-
Initialize the Zephyr workspace:
just init
This will set up the Nix environment, install dependencies, and initialize the Zephyr workspace.
The Justfile provides a set of commands to manage the build, test, and
visualization process. Here's how everything works:
just init: Initialize Zephyr workspace (west init + update + export).just list: Show all build target tuples derived frombuild.yaml.just build <expr>: Filter targets (case-insensitive substring match;allexpands). Builds firmware artifacts tofirmware/.just draw [targets...]: Generate visual keymap diagrams. No args orallβ all known targets.just check: Check build-matrix, hardware, Bluetooth, and keymap invariants.just clean: Clean build artifacts.just clean-all: Clean everything including Zephyr modules.just upgrade-dependencies: Update all pinned Nix dependencies.
The build process uses build.yaml as a declarative matrix:
# build.yaml targets use current Zephyr board-variant syntax.
include:
- board: rp2040_zero
shield: cheapinov2
snippet: studio-rpc-usb-uart
artifact-name: cheapinov2-rp2040_zero
- board: xiao_ble//zmk
shield: ergonaut_one_left
artifact-name: ergonaut_one_left-xiao_ble
- board: adv360pro_left//zmk
artifact-name: adv360pro_left
- board: adv360pro_left//zmk
shield: settings_reset
artifact-name: settings_reset-adv360pro_left
- board: adv360pro_right//zmk
shield: settings_reset
artifact-name: settings_reset-adv360pro_rightInternals:
_parse_targets: Parsesbuild.yamlusingyqto generate build tuples._build_single: Invokeswest buildwith appropriate flags and copies artifacts.
Keymap drawing pipeline:
- Parse the keymap with
keymap parseand explicit display-layer names. - Render with
keymap drawto produce YAML and SVG files.
Metadata for layouts and keyboards is defined in the Justfile:
LAYOUTS["cheapinov2"]=LAYOUT_split_3x5_3
KEYBOARDS["cheapinov2"]=corne_rotatedBuild all targets:
just build all -p # Pristine build
# or build a specific keyboard
just build adv360proBuild specific keyboard:
just build cheapinov2
just build adv360proDraw keymaps:
just draw cheapinov2 ergonaut_one adv360proThis repository includes GitHub Actions for automated building:
- Trigger: Pushes to
main, pull requests, and manual dispatch - Workflow:
build.yml - Actions:
- Sets up the pinned Nix environment and West workspace
- Builds every target in
build.yamland generates diagrams - Uploads firmware artifacts
- Commits refreshed diagrams only for pushes to
main
The workflow uses GitHub-hosted Ubuntu runners. Pull requests receive read-only permissions; the separate push-only diagram job receives the write permission needed to commit refreshed drawings. Third-party actions are pinned to commit SHAs.
The Cheapino target matches the official v2 ordering/build documentation: one Waveshare RP2040-Zero on the left PCB and a normal straight-through RJ45 cable between the two halves. It is a single-controller USB keyboard; the RJ45 cable extends the directed key matrix and is not a ZMK split transport.
The local module in hardware/cheapino/ contains the upstream v2 pin mapping,
physical layout, matrix-connected encoder integration, and the v2-specific
phantom-key suppression masks from the official firmware. Encoder actions are:
- Press: play/pause.
- Rotate normally: Page Down/Page Up.
- Rotate on the macOS navigation layer: next/previous tab.
- Rotate on the macOS number layer: redo/undo.
- Rotate on the system layer: volume up/down.
To flash, hold BOOT while connecting the RP2040-Zero (or use its BOOT/RESET
sequence), then copy firmware/cheapinov2-rp2040_zero.uf2 to the mounted USB
drive. Use a straight-through Ethernet cable; crossover cables do not match the
Cheapino routing.
The Advantage360 Pro uses the boards shipped in upstream ZMK. Both halves and both settings-reset images are built. Standard ZMK does not provide Kinesis's graphical editor or its advanced indicator-LED behavior. When repairing split pairing, flash the matching settings-reset image to each half, then reflash both normal firmware images.
-
Add entry to
build.yaml:- board: <board> shield: <shield> snippet: <optional> artifact-name: <optional>
-
Add board support as a local module under
hardware/or declare an external module inconfig/west.yml. -
Update
Justfiledraw metadata when the keyboard has a visual keymap. -
Run
just init, thenjust build <shield>to test.
Edit the keymap files in config/:
base.keymap: Common behaviors<keyboard>.keymap: Keyboard-specific layers
Use ZMK documentation for keycode references.
Modify flake.nix to add dependencies or change versions.
- ZMK: Zephyr Mechanical Keyboard firmware
- West: Zephyr's meta-tool for managing workspaces
- Shield: ZMK term for keyboard-specific configurations
- Layer: A set of key bindings that can be activated
- Home Row Modifiers: Modifiers placed on the home row for ergonomic access
- Nix Flake: A declarative way to define Nix environments
- Direnv: Tool for loading/unloading environment variables based on directory
- Just: Command runner for saving and running project-specific commands
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
Please follow the established patterns in the codebase and update documentation as needed.
This project is licensed under the Apache License 2.0. See the
LICENSE file for full terms.
Note on thirdβparty code & packages:
- Nix flakes in
inputs(e.g.nixpkgs) and any packages you build or distribute through this configuration are covered by their own upstream licenses. - Refer to
nixpkgspackage metadata (meta.license) or upstream project repositories for details before redistributing binaries. - Nothing in this repository alters or supersedes those thirdβparty licenses; the Apache 2.0 terms apply only to the original material contained here.
If you contribute, you agree your contributions are provided under Apache 2.0 unless explicitly stated otherwise.
Made with β€οΈ for mechanical keyboards
Special thanks to Urob and zmk-helpers for inspiration and amazing ZMK modules.