Firmware targets
Remappr compiles one config to several firmwares. There are three compiler targets — zmk, qmk, keychron — and the builder's selectable firmware ids — zmk, qmk, via, vial — where VIA and Vial both build through the QMK family.
Targets
| Builder id | Compiles via | Output | Wireless |
|---|---|---|---|
| ZMK | zmk | devicetree .keymap + .overlay | ✅ |
| QMK | qmk | keymap.c + keyboard.json | — |
| VIA | qmk (+ VIA def) | QMK + via/<kb>.json | — |
| Vial | qmk (+ Vial def) | QMK + vial.json + UID/unlock config.h | — |
| Keychron | keychron | VIA/QMK stack + BLE radio | ✅ |
The exact files each target emits are listed in Export, build & flash.
Output examples
The same demo layer compiled to each target.
ZMK .keymap (devicetree):
compatible = "zmk,keymap";
base {
bindings = <
&kp Q &kp W &kp E
&mt LSHFT A // home-row mod (mod_tap)
< 1 SPACE // layer-tap
&mo 2 // momentary layer
&kp LC(C) // "Ctrl+C"
&bt BT_SEL 0 // bluetooth profile
&rgb_ug RGB_TOG // underglow toggle
>;
};Macros, tap-dances and combos become zmk,behavior-macro / zmk,behavior-tap-dance / combo_<name> nodes; encoders use &inc_dec_kp. A tap-hold with a timing/flavor emits a dedicated node (flavor = "hold-preferred").
ZMK .overlay — the physical layout + matrix-transform:
#include <physical_layouts.dtsi>
compatible = "zmk,physical-layout"; // key_physical_attrs per key
#include <dt-bindings/zmk/matrix_transform.h>
compatible = "zmk,matrix-transform"; // one RC(r,c) per key, in keymap order
transform = <&default_transform>;Board hardware you didn't supply (kscan, pinctrl) appears as a /* NOT GENERATED by remappr */ checklist.
QMK keymap.c:
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT( KC_Q, KC_W, KC_E,
LSFT_T(KC_A), // mod_tap
LT(1, KC_SPC), // layer_tap
MO(2), // momentary layer
LCTL(KC_C), // Ctrl+C
RGB_MOD ), // per-key effect-next (fine on QMK)
};QMK also emits keyboard.json (matrix pins, diode, MCU/USB identity); VIA/Vial add via/<kb>.json / vial.json.
Capability matrix
Each target supports a different feature set. The compiler consults this matrix to emit a warning and drop an unsupported binding to a no-op, rather than failing the build.
Lighting axes
| Axis | ZMK | QMK | Keychron |
|---|---|---|---|
underglow | ✅ | ✅ | ✅ |
backlight | ✅ | ✅ | ✅ |
per_key | — | ✅ | ✅ |
ZMK has no per-key RGB matrix control.
Output routing
Output action | ZMK | QMK | Keychron |
|---|---|---|---|
usb | ✅ | ✅ | ✅ |
bluetooth* (incl. profile index) | ✅ | — | ✅ |
toggle, none | ✅ | — | ✅ |
Stock QMK is wired-only. ZMK and Keychron support Bluetooth output and profile indices.
Behaviors with a codegen path
| Behavior | ZMK | QMK | Keychron |
|---|---|---|---|
| Caps Word | ✅ | ✅ | ✅ |
| Sticky key | ✅ | ✅ | ✅ |
| Sticky layer | ✅ | ✅ | ✅ |
| Tap dance | ✅ | ✅ | ✅ |
| Macro | ✅ | ✅ | ✅ |
| Combo | ✅ | ✅ | ✅ |
Which targets can I compile for?
- No device connected (builder / demo) — all targets are available; you pick in the Identity panel.
- A device connected — only that device's own firmware family is offered, so you cannot accidentally compile a ZMK keymap for a QMK board.
Readiness
Before a target will build cleanly it needs certain fields set (controller, USB ids, matrix wiring, Vial UID/unlock). The export modal runs a per-target readiness check and shows what is missing — see Export, build & flash → Readiness.
Roadmap
Behavior coverage continues to expand per firmware. The project README tracks the detailed, per-behavior status matrix (done / in-progress / planned).
