QMK keyboard layouts written in Markdown, see example.
This is a work-in-progress prototype I'm experimenting with to find an easier way to represent QMK keyboard layout.
A keyboard layout will be represented by a markdown file with multiple types of code blocks:
-
Structure - defines the structure of the grid (the way it is structured in the keymap.c file). e.g.
```structure 37 38 39 40 41 42 || 43 44 45 46 47 48 49 1 2 3 4 5 || 6 7 8 9 10 50 51 11 12 13 14 15 || 16 17 18 19 20 52 53 21 22 23 24 25 54 || 55 26 27 28 29 30 56 31 32 33 || 34 35 36 ```
This block has to be perfectly indented, each cell is exactly 3 characters (2 for the key index + space). For split keyboards we add
||between the halfs. -
Layout - defines each layout in the keyboard, basically a shorter, easier-to-read representation of a call to
LAYOUT()in QMK. e.g.```layer:base esc 1 2 3 4 5 || 6 7 8 9 0 bs tab q w e r t || y u i o p \ lgui lctl/a lalt/s lgui/d l(f)/f g || h l(j)/j rgui/k ralt/l rctl/; ' lsft z x c l(v)/v b home || end n m , . / rsft lctl osm(lgui) spc || osm(rsft) ent bs ```
-
Aliases - to keep the layer short you can create aliases, e.g.
```aliases # Previous tab tabp = g+s+[ # Next tab tabn = g+s+] ```
You can also enter QMK strings directly:
```aliases # Previous tab tabp = LGUI(S(KC_LBRC)) # Next tab tabn = LGUI(S(KC_RBRC)) ```
Instead of using QMK KC_* we use a shorter format (haven't decided on all of them yet).
Install the Go CLI with:
go install github.com/elentok/qmkmd@latestOr build it from a local checkout:
go build .Or install it from Homebrew after the first tagged release:
brew tap elentok/stuff
brew install --cask qmkmdTo build a markdown file into a header file you can import in keymap.c run:
qmkmd build layout.mdOr choose an explicit output path:
qmkmd build layout.md --output generated-layout.hIt will create generated-layout.h which you can then import into your keymap.c
using:
#include "generated-layout.h"If your keyboard layout uses another function other than LAYOUT you can
override it in the options block:
```options
layoutFn = MY_LAYOUT
```To preview the formatted markdown on stdout:
qmkmd format layout.mdTo rewrite the file in place:
qmkmd format layout.md --writeIf you're using Neovim you can setup conform to format the file whenever you save like this:
require("conform").setup({
formatters = {
qmkmd = {
command = "qmkmd",
args = { "format", "$FILENAME", "--write" },
stdin = false,
condition = function(_, ctx) return vim.endswith(ctx.filename, ".layout.md") end,
},
},
formatter_by_ft = {
markdown = { "prettierd", "qmkmd" },
}
})To preview copied mappings on stdout:
qmkmd copy source.md target.mdTo rewrite the target file, optionally limited to an inclusive key range:
qmkmd copy source.md target.md --range 10-20 --writeThis repo ships a Claude Code
skill under skill/ that teaches Claude the qmkmd block structure and
mapping syntax. With it installed, Claude can author and edit .layout.md files
and validate them against the qmkmd CLI.
Install it into ~/.claude/skills/qmkmd with the helper script:
# symlink (recommended — picks up repo changes automatically)
scripts/install-skill.sh symlink
# or copy a snapshot
scripts/install-skill.sh copyThe skill activates when you edit a *.layout.md file or any Markdown file
containing qmkmd code blocks.
I wrote this entire project myself with TypeScript in Dec 2023 but on April 2026 I migrated the whole thing to Go using Codex (see docs/go-migration-plan.md).
I wanted it to be faster and easier to install.
