- Chord Mode - Type 220+ common words with just two letters! See the complete documentation for details.
- Design Philosophy - Learn about the hardware, ergonomics, and design principles behind this layout
- Home Row Mods - Modifiers on home row for ergonomic access
- Window/Tab Switching - Fast application and tab switching
- X-Case - Multiple case conversion modes (camelCase, snake_case, etc.)
- The keyboard layout is generated using generateKeyboard from this file. => link to Generator
- The generated keyboard can be found in the qmk directory.
- tested with Ferris Sweep keyboard
- To extract local source-word candidates for magic migration:
mise run extract-source-words -- ~/source --output source_words.tsv --limit 500 --min-count 3 - To extract authored GitHub/chat-style words for magic migration:
mise run extract-github-words -- --output github_words.tsv --limit 500 --min-count 3 - To extract local Codex/chat-export words for magic migration:
mise run extract-local-chat-words -- --output local_chat_words.tsv --limit 500 --min-count 3 - To merge candidate lists before ranking:
mise run merge-word-lists -- general_words.tsv source_words.tsv --output merged_words.tsv - To rank those candidates into free magic slots:
mise run find-available-chords -- --candidates-file source_words.tsv --limit 50 - To review explicit placement ideas against current table occupancy:
mise run suggest-magic-placements -- --prefer-row 'thank you=t' --prefer-row 'gregor=z' 'thank you' gregor - Prefer
mise run ...for these helper workflows; the implementations live underscripts/, not at repo root.
On all other layers, the modifiers are as shown in the table below.
| Home Row Modifiers | Finger |
|---|---|
| Alt | Ring |
| Ctrl | Middle |
| Shift | Index |
- win โก๏ธ and tab โก๏ธ are used to Short windows and tabs.
- Once you press any of those keys, you're in switcher mode, where all other keys are replaced by shift-tab.
- Switcher mode is exited when you go back to the base layer.
How to read this layout:
- ๐ = combo key (e.g. middle and index finger in top row pressed together produce "b")
- ๐ = key can't be used because the layer was activated with that key or because it's reserved for a modifier
- empty = use key from base layer
- FnSym = capitalized words are layer names - if they are a key, the layer is activated as toggled or one shot layer (if the "OneShot" flag is set in the layer flags)
- *Mouse = layer is active while key is held
- C-w = Ctrl-w (same for Alt and Shift)
- f12+Num = tab-mod - f12 on tap and Num on hold
- "that" = combo that produces "that"
- #g = exact symbol token;
#...entries must exist in the Symbols table - [ { = { is the shifted key of [, so it's used when Shift is held (only for information)
- The symbol table at the bottom shows the meaning of the symbols used in the layout.
Currently unused features:
- /+Ctrl = tab-mod - / on tab and CTRL on hold
- $Mouse = layer is active while key is held (double tap to lock layer)
- @Num = layer is active for the next keypress
- Sym/Nav = layer is active for the next keypress: If the activation key is still down when the next key is pressed, the Nav layer is used, otherwise the Sym layer is used
Note: The layout is generated from this file directly.
Rows = preceding key. Columns = the eleven physical magic keys (see the Layout table for their positions).
Cell = what to emit.
- A cell may be prefixed with
โซto forceBS + outputwhen the preceding key is replaceable. This is an explicit table-level override and drives the generated logic directly. - Single-char letter cells append or tap unless prefixed with
โซ(e.g.a+eyieldsae, whilespc+โซzyieldsz). Single-char punctuation/symbol cells doโซ + charwhen the preceding key is replaceable (typically a letter orspc), sot+.yields.. A repeated press of the same magic key then replays just the emitted letter or symbol, with no extra backspace. No suffix state. - Bare words/phrases (unquoted multi-char, e.g.
because,thank you): generator auto-appends a trailing space and activates the suffix state machine. From there, the next magic press chains the suffix shown in thesuffixrow; theingkey also works with vowel-drop..exits with one-shot shift,,exits without shift. Bare words may append, strip the repeated prefix letter, or doโซ + word, depending on the preceding key. - Quoted strings (literal โ no auto-space, no suffix state):
- Preceding key is a letter and cell starts with it โ strip prefix.
b+"because"emitsecause, yieldingbecause. - Preceding key is a letter and cell does not start with it โ
โซ + cell. - Preceding key is not a letter (spc, punctuation) โ append as-is.
,+" and "yields, andplus a trailing space.
- Preceding key is a letter and cell starts with it โ strip prefix.
- Order note: the table is still authored as
preceding key + magic. Reverse order (magic + following key) is only a fallback when there is no fresh, valid preceding-key interpretation, so forward magics remain authoritative in ambiguous sequences. Reverse fallback is limited to replacement cells; append and prefix-strip cells still require forward order. [name]bracket tokens invoke named handlers.[dotSpc]= BS +.then one-shot shift. In thesuffixrow,[next]replaces the current word with the next item from theCycletable while keeping suffix mode active.- Row "r" is reserved for future use.
| Magic | magic_a | magic_b | magic_c | magic_d | magic_e | magic_f | magic_g | magic_h | magic_i | magic_j | magic_k |
|---|---|---|---|---|---|---|---|---|---|---|---|
| suffix | ed | ly | n't | ? | ", " | [next] | " the " | ". " | s | ||
| a | e | ||||||||||
| b | background | basically | become | observability | disable | obsolete | because | d | before | ||
| c | n | "'ll " | "n't " | d | "'ve " | comment | "'re " | "'d " | "'s " | ||
| d | c | h | don't | difficulty | didn't | doesn't | f | does | |||
| e | u | another | h | explain | |||||||
| f | confusing | conflict | performance | frequency | focused | following | d | ||||
| g | global | f | organize | change | general | generate | k | d | suggest | ||
| h | "qu" | y | |||||||||
| i | implement | "mpl" | |||||||||
| j | just | ||||||||||
| k | r | question | think | merged | update | know | x | knew | |||
| l | m | h | language | already | available | elaborate | r | c | b | ||
| m | r | h | migration | multiple | mismatch | instrumentation | ment | l | t | ||
| n | r | h | never | anything | understand | "qu" | x | p | |||
| o | e | h | |||||||||
| p | y | m | people | probably | python | production | n | d | Prometheus | ||
| r | " | "q" | โซ"n't" | โซ? | x | โซ! | โซ' | โซ, | โซ. | "j" | |
| s | someone | r | possible | support | similar | separate | "sion" | d | something | ||
| t | n | f | through | though | "tion" | without | thought | ||||
| u | h | ||||||||||
| v | validation | everything | improve | version | #dc | approval | resolve | I've | |||
| w | always | wasn't | workflow | otherwise | switch | which | s | x | worse | ||
| x | exception | w | except | explicit | exclude | r | d | example | |||
| y | only | r | |||||||||
| z | realize | #g | OpenTelemetry | Spring Boot | |||||||
| spc | [dotSpc] | โซz | and | the | |||||||
| tab | and | the | |||||||||
| enter | and | the | |||||||||
| , | " and " | " but " |
Rows are grouped sequences. Each item cycles to the next item in the row, and the last item wraps back to the first. Cycle entries are authored without the trailing auto-space.
| Cycle | next |
|---|---|
| implement | implementation |
| Gregor | " Zeitlinger " |
| Adaptives | Key | Output |
|---|---|---|
| a | e | u |
| b | d | s |
| c | d | c |
| c | n | k |
| d | c | v |
| d | f | d |
| d | h | g |
| e | h | e |
| e | u | o |
| f | d | f |
| g | d | n |
| g | f | l |
| k | r | n |
| l | b | k |
| l | c | v |
| l | h | p |
| l | r | l |
| m | h | m |
| m | r | p |
| m | t | b |
| n | h | n |
| n | p | k |
| n | r | g |
| n | x | l |
| o | h | o |
| p | d | l |
| p | n | p |
| p | y | s |
| r | x | r |
| s | d | p |
| s | r | s |
| t | f | w |
| t | n | t |
| u | h | a |
| w | x | n |
| x | d | c |
| x | w | p |
| y | r | i |
| Layer | L. Pin. | L. Ring | L. Mid. | L. Ind. | R. Ind. | R. Mid. | R. Ring | R. Pin. |
|---|---|---|---|---|---|---|---|---|
| Base | esc | x | w | dead3 | dead2 | magic_a | magic_b | dead1 |
| Base | s | c | n | t | a | e | i | h |
| Base | *Right | f | l | d | u | o | y | *Left |
| Base | *Nav | r | spc | *FnSym | ||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Base | v | ing | ||||||
| Base | ๐ | ๐ | ||||||
| Base | k | magic_h | ||||||
| Base | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Base | m | magic_d | ||||||
| Base | ๐ | ๐ | ||||||
| Base | g | magic_i | ||||||
| Base | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Base | p | magic_e | ||||||
| Base | ๐ | ๐ | ||||||
| Base | b | magic_j | ||||||
| Base | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Base | magic_c | magic_f | ||||||
| Base | ๐ | ๐ | ||||||
| Base | magic_g | magic_k | ||||||
| Base | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Right | dead3 | " | q | |||||
| Right | C-f | C-r | ||||||
| Right | ๐ | ๐ | ๐ | ๐ | _ | |||
| Right | A-f7 | C-n | [ | ] | ||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Right | ` | |||||||
| Right | ๐ | ๐ | ||||||
| Right | CS-r | ' | ||||||
| Right | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Right | n't | |||||||
| Right | ๐ | ๐ | ||||||
| Right | CS-f | , | ||||||
| Right | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Right | ? | |||||||
| Right | ๐ | |||||||
| Right | . | |||||||
| Right | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Right | @ | |||||||
| Right | ๐ | |||||||
| Right | j | |||||||
| Right | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| RMods | ||||||||
| RMods | ||||||||
| RMods | ๐ | ๐ | ๐ | ๐ | = | |||
| RMods | [ | ] | ||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Left | dead1 | |||||||
| Left | *CNum | *Case | *Media | |||||
| Left | : | ๐ | ๐ | ๐ | ๐ | |||
| Left | ; | *ANum | *Num | |||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Left | ! | |||||||
| Left | ๐ | |||||||
| Left | z | |||||||
| Left | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| LMods | ||||||||
| LMods | ||||||||
| LMods | - | ๐ | ๐ | ๐ | ๐ | |||
| LMods | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| FnSym | dead2 | f10 | f9 | dead2 | dead3 | ( | ) | dead1 |
| FnSym | f4 | f3 | f2 | f1 | ๐ | ๐ | ๐ | =+Num2 |
| FnSym | f8 | f7 | f6 | f5 | - | { | } | *Num |
| FnSym | f12 | ๐ | ๐ | |||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| FnSym | โ | win | ||||||
| FnSym | ๐ | ๐ | ||||||
| FnSym | โ | ~ | ||||||
| FnSym | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| FnSym | * | < | ||||||
| FnSym | ๐ | ๐ | ||||||
| FnSym | f11 | / | ||||||
| FnSym | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| FnSym | pipe | > | ||||||
| FnSym | ๐ | ๐ | ||||||
| FnSym | & | # | ||||||
| FnSym | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| FnSym | ^ | \ | ||||||
| FnSym | ๐ | ๐ | ||||||
| FnSym | $ | % | ||||||
| FnSym | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | dead3 | C-x | C-v | CS-z | dead1 | esc | ins | dead2 |
| Nav | copy | ๐ | ๐ | ๐ | โฌ ๏ธ | โฌ๏ธ | โฌ๏ธ | โก๏ธ |
| Nav | C-z | C-w | tab โก๏ธ | win โก๏ธ | โฉ๏ธ๏ธ | bspc | del | tab |
| Nav | ๐ | ๐ | spc | |||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | CS-v | รผ | ||||||
| Nav | ๐ | ๐ | ||||||
| Nav | C-y | โฌ ๏ธโฌ ๏ธ | ||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | C-a | รถ | ||||||
| Nav | ๐ | ๐ | ||||||
| Nav | C-d | โฌ๏ธโฌ๏ธ | ||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | CS-n | รค | ||||||
| Nav | ๐ | ๐ | ||||||
| Nav | C-k | โฌ๏ธโฌ๏ธ | ||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | C-e | ร | ||||||
| Nav | ๐ | ๐ | ||||||
| Nav | CS-c | โก๏ธโก๏ธ | ||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | ||||||||
| Nav | CA-b | ๐ | A-f12 | |||||
| Nav | ||||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | ||||||||
| Nav | C-b | ๐ | ||||||
| Nav | ||||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | ||||||||
| Nav | ||||||||
| Nav | C-f12 | ๐ | C-/ | |||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Nav | ||||||||
| Nav | ||||||||
| Nav | C-p | ๐ | ||||||
| Nav | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Num | dead1 | , | 9 | dead2 | ||||
| Num | 4 | 3 | 2 | 1 | ||||
| Num | 8 | 7 | 6 | 5 | ||||
| Num | . | 0 | ๐ | ๐ | ||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Num | CS-v | |||||||
| Num | ๐ | |||||||
| Num | C-g | |||||||
| Num | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Num | A-f1 | |||||||
| Num | ๐ | |||||||
| Num | CA-l | |||||||
| Num | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Num | AS-x | |||||||
| Num | ๐ | |||||||
| Num | AS-b | |||||||
| Num | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Num | ||||||||
| Num | ๐ | |||||||
| Num | AS-s | |||||||
| Num | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| ANum | ||||||||
| ANum | A-4 | A-3 | A-2 | A-1 | ||||
| ANum | A-8 | A-7 | A-6 | A-5 | ||||
| ANum | A-9 | A-0 | ๐ | ๐ | ||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| CNum | ||||||||
| CNum | C-4 | C-3 | C-2 | C-1 | ||||
| CNum | C-8 | C-7 | C-6 | C-5 | ||||
| CNum | C-9 | C-0 | ๐ | ๐ | ||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Media | dead2 | ๐ | ๐ | dead1 | ||||
| Media | prt | ๐ | ๐ | ๐ | ๐ | |||
| Media | ver | โฎ๏ธ | โญ๏ธ | โฏ๏ธ | ||||
| Media | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Media | ||||||||
| Media | ๐ | |||||||
| Media | @gl | |||||||
| Media | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Media | ||||||||
| Media | ๐ | |||||||
| Media | @gmail | |||||||
| Media | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Media | ||||||||
| Media | ๐ | |||||||
| Media | @zeit | |||||||
| Media | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Media | #G | |||||||
| Media | ๐ | |||||||
| Media | #GL | |||||||
| Media | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- | |
| Case | ||||||||
| Case | sl/case | PasCase | CapW | SN_CASE | ||||
| Case | do.case | camCase | kb-case | sn_case | ||||
| Case | ||||||||
| ------- | ------- | ------- | ------- | ------- | ------- | ------- | ------- |
The order of the options is also the order of the layers in the layer stack.
| LayerOptions | Modifiers Left | Modifiers Right | Fallback Left | Fallback Right | Flags | Combo Timeout |
|---|---|---|---|---|---|---|
| Base | 200 | |||||
| Left | BottomRow+LMods | Base | Shifted | 200 | ||
| Right | BottomRow+RMods | Base | Shifted | 200 | ||
| LMods | BottomRow+LMods | Base | ||||
| RMods | BottomRow+RMods | Base | ||||
| Nav | HomeRow | DirectComboLeft | 200 | |||
| FnSym | HomeRow | DirectComboRight | 200 | |||
| Num | TriLayer | 200 | ||||
| Num2 | HomeRow | Num | ||||
| ANum | ||||||
| CNum | 200 | |||||
| Media | 200 | |||||
| Case |
Exact-match symbol tokens such as #g, #G, and #GL must be declared here.
| Symbol | Command |
|---|---|
| โฌ ๏ธ | KC_LEFT |
| โฌ ๏ธโฌ ๏ธ | KC_HOME |
| โฌ๏ธ | KC_DOWN |
| โฌ๏ธโฌ๏ธ | KC_PGDN |
| โฌ๏ธ | KC_UP |
| โฌ๏ธโฌ๏ธ | KC_PGUP |
| โก๏ธ | KC_RIGHT |
| โก๏ธโก๏ธ | KC_END |
| โ | KC_KP_MINUS |
| โ | KC_KP_PLUS |
| ins | KC_INS |
| del | KC_DEL |
| spc | KC_SPC |
| esc | KC_ESC |
| โฉ๏ธ๏ธ | KC_ENT |
| enter | KC_ENT |
| bspc | KC_BSPC |
| win | KC_LGUI |
| tab | KC_TAB |
| prt | KC_PSCR |
| pipe | KC_PIPE |
| ๐ | KC_MUTE |
| โฏ๏ธ | KC_MPLY |
| โฎ๏ธ | KC_MPRV |
| โญ๏ธ | KC_MNXT |
| ๐ | KC_VOLU |
| ๐ | KC_VOLD |
| ๐ | KC_BRIU |
| ๐ | KC_BRID |
| copy | C(KC_C) |
| รค | UP(UMLAUT_a, UMLAUT_A) |
| รถ | UP(UMLAUT_o, UMLAUT_O) |
| รผ | UP(UMLAUT_u, UMLAUT_U) |
| ร | UM(UMLAUT_s) |
| magic_a | magic:MAGIC_A |
| magic_b | magic:MAGIC_B |
| magic_c | magic:MAGIC_C |
| magic_d | magic:MAGIC_D:qu |
| magic_e | magic:MAGIC_E |
| magic_f | magic:MAGIC_F |
| magic_g | magic:MAGIC_G |
| magic_h | magic:MAGIC_H |
| magic_i | magic:MAGIC_I |
| magic_j | magic:MAGIC_J |
| magic_k | magic:MAGIC_K |
| tab โก๏ธ | custom:NEXT_TAB NoHold |
| win โก๏ธ | custom:NEXT_WINDOW NoHold |
| n't | custom:N_T |
| ing | custom:ING |
| ver | custom:PRINT_VERSION |
| CapW | custom:CAPS_WORDS |
| sn_case | custom:SNAKE_CASE |
| SN_CASE | custom:SCREAMING_SNAKE_CASE |
| camCase | custom:CAMEL_CASE |
| PasCase | custom:PASCAL_CASE |
| sl/case | custom:SLASH_CASE |
| do.case | custom:DOT_CASE |
| kb-case | custom:KEBAP_CASE |
| dead1 | custom:DEAD1 |
| dead2 | custom:DEAD2 |
| dead3 | custom:DEAD3 |
| @gmail | zeitlinger@gmail.com |
| @gl | gregor.zeitlinger@grafana.com |
| @zeit | gregor@zeitlinger.de |
| #g | gregor |
| #G | Grafana |
| #GL | Grafana Labs |
| #dc | declarative config |
- should be usable with any keyboard layout
QMK: https://github.com/zeitlinger/qmk_firmware/tree/ferris
- run
mise run installto install the dependencies in QMK directory - run
mise run flashto flash the keyboard in this directory