{"id":16406462,"url":"https://github.com/wincent/yak-layout","last_synced_at":"2025-06-21T05:03:09.936Z","repository":{"id":36335958,"uuid":"40640672","full_name":"wincent/yak-layout","owner":"wincent","description":"Yak keyboard layout and optimizer","archived":false,"fork":false,"pushed_at":"2025-01-24T10:07:28.000Z","size":52,"stargazers_count":26,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-06T20:46:21.625Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wincent.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-08-13T05:31:57.000Z","updated_at":"2024-07-31T10:21:03.000Z","dependencies_parsed_at":"2025-06-21T05:02:54.874Z","dependency_job_id":null,"html_url":"https://github.com/wincent/yak-layout","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/wincent/yak-layout","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wincent%2Fyak-layout","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wincent%2Fyak-layout/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wincent%2Fyak-layout/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wincent%2Fyak-layout/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wincent","download_url":"https://codeload.github.com/wincent/yak-layout/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wincent%2Fyak-layout/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261065254,"owners_count":23104763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T06:09:49.945Z","updated_at":"2025-06-21T05:03:04.885Z","avatar_url":"https://github.com/wincent.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# The \"Yak\" keyboard layout and optimizer\n\nYak is a tool for developing keyboard layouts via a genetic algorithm. The\nlayouts are optimized for programming and typing English text.\n\nYak will also be the name for the layout produced by the tool. At this time I\nhaven't declared a definitive, final version, but it could end up looking\nsomething like the following (this is a sample produced by 10,000 iterations\nof optimization, using the Colemak layout as a starting point):\n\n```\n⎋  F1  F2  F3  F4  F5  F6  F7  F8  F9  F10  F11  F12  ⌽\n`  1  2  3  4  5  6  7  8  9  0  -  =  ⌫\n⇥  d  c  m  p  b  j  x  v  y  ;  [  ]  \\\n⇪  a  r  t  i  h  g  s  n  e  o  '  ↩\n⇧  u  l  w  f  z  k  q  ,  .  /  ⇧\nfn ⌃  ⌥  ⌘  ␣  ⌘  ⌥  ←  ↑  ↓  →\n```\n\n## Design guidelines\n\n- Learning a new layout is hard: so hard, that you probably only want to do it\n  once in your life. Therefore, the design should go \"all in\" and feel free to\n  move all and any keys from their Qwerty positions.\n- Inward rolls are delightful and should be prioritized.\n- Both the training corpus and the genetic algorithm should be highly\n  personalized; for example, the finger-to-key placement model should be based\n  on what the user actually does in practice and not what they _should_ do if\n  they follow idealzed typing recommendations (for example, I pretty much avoid\n  using pinkie fingers for anything, so the model should reflect that reality).\n- The genetic algorithm should take cues from Martin Krzywinski's excellent work\n  on the [carpalx project](http://mkweb.bcgsc.ca/carpalx/?colemak), but it\n  should feature a multi-factor fitness model that goes beyond carpalx's three\n  factors (base, penalty and stroke path).\n\n## Why a new keyboard layout?\n\n### Short version\n\nFrom the \"Standard Justification For a Project's Existence\" playbook:\n\n\u003e ... I realized I needed [blah, blah, blah] but when I surveyed the already\n\u003e existing projects I found that [blah, blah, blah], when what I really needed\n\u003e was [blah blah blah]. So, this project was born...\n\n### Longer version\n\nI've been aware of alternative keyboard layouts for a long time — years — and as\na relentless optimizer, I've been strongly tempted to make the switch to one.\nBut I'm also a Vim user, and the problematic location of the `h`, `j`, `k`, `l`\nkeys made me doubt. None of the major alternative layouts had these keys in\nlocations that maintained their spatial relationships in a reasonable way, and I\ndidn't want to go down the rabbit hole of remapping Vim's core functionality (I\nvery much prefer to keep things vanilla in that respect).\n\nThis was enough to deter me, literally for years.\n\nFast forward to 2015 and I'm on parental leave so have a little bit of time in\nwhich I can take the speed hit of learning a new layout. I did a bunch of\nsearching and revisited the major layouts (in my mind,\n[Dvorak](https://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard),\n[Colemak](http://colemak.com/), [Workman](http://colemakmods.github.io/mod-dh/),\n[Norman](https://normanlayout.info/)) as well as some of the more obscure\noptions ([Arnesito](http://www.pvv.org/~hakonhal/main.cgi/keyboard) probably\nbeing the most radical) and variants on the more common layouts (such as\n[Colemak Mod_DH](http://colemakmods.github.io/mod-dh/)). None of these address\nmy concerns with `h`, `j`, `k`, `l`.\n\nI was aware of the fantastic [carpalx](http://mkweb.bcgsc.ca/carpalx/) tool,\nwhich is highly parameterizable, and which I thought I might be able to use to\ngenerate a much-better-than-Qwerty layout without changing the position of `h`,\n`j`, `k`, `l` (or at least, changing them to some other places where the spatial\nrelationships were maintained).\n\nAlas, I found it wasn't quite flexible enough to do exactly what I wanted. I\ncould use the \"mask\" functionality, for example, to pin a key in place, but I\ncouldn't specify more sophisticated constraints such as \"put these two keys next\nto each other but I don't care where\", and so on.\n\nI looked at Micheal Dicken's [genetic layout\noptimizer](https://github.com/michaeldickens/Typing) which produced the so\ncalled \"MTGAP\" layouts, and I read his accompanying [blog\nposts](https://mathematicalmulticore.wordpress.com/category/keyboards/) ([this\nintro\npiece](https://mathematicalmulticore.wordpress.com/2009/08/07/optimized-evolutionary-algorithm-for-keyboard-design-part-1/)\nis a good example). I also dived into the [Colemak\nforums](http://forum.colemak.com/) and read about [other people's\nattempts](http://forum.colemak.com/viewtopic.php?id=397) at making keyboards\nusing genetic algorithms. It's a fascinating field of study.\n\nThe problem space here is really large. There are too many possible keyboard\nlayouts to make testing them all feasible, and defining what makes one layout\nbetter than another is a highly subjective matter. These tools all have\ndifferent takes on how to establish the \"fitness\" of a given layout. The main\nstrategies are some blend of the following heuristics:\n\n- Strokes with weaker fingers are penalized.\n- Keys farther away from the base home row positions are penalized.\n- Hand alternation may (or may not) be preferred.\n- \"Rolls\" are considered good things (towards the inside; less so or not at all\n  towards the outside).\n- Finger movement distance should be minimized; especially same-finger movement.\n- The most common digrams and trigrams (two-letter and three-letter sequences)\n  should be very easy to type, to the extent that entire layouts exist to make\n  typing \"th\" or similar easier.\n- Some layouts try to keep important shortcut keys (eg. \"C\" for copy, \"V\" for\n  paste etc) in their Qwerty positions.\n- Others may avoid moving Qwerty keys between fingers or hands.\n- Some maintain punctuation in Qwerty positions; others swap the shifted and\n  unshifted values of the number keys to make punctuation more accessible;\n  others still mix punctuation in among the main \"block\" of letter keys.\n\nWhich of these heuristics should be weighed more heavily is open to debate.\nUnfortunately, the cost of experimentation is high, as one cannot simply learn a\nnew layout every week (for example, to learn a high-alternation layout like\nDvorak one week, a distance-minimizing layout like Arnesito the next week, and a\nbalanced layout like Colemak the following week). This means much of this is\nmore art than science, as you end up having to go with your gut instinct.\n\nLike any programmer faced with an excessive amount of choice, I decided it was\ntime to write my own tool, one capable of perfectly expressing my intent. If I\nwas going to go through the pain of learning a new layout, I wanted to do it\nonly once in my lifetime, using an optimal algorithm tailored to my needs, and\ndrawing on a corpus of my own typing.\n\nBy this point I'd realized two things:\n\n- Doing this _properly_ was going to be a lot of work: not only would I have to\n  develop the algorithm, but I'd need to get a high-quality corpus, and that\n  could be very time-consuming indeed. For example, it wasn't going to be enough\n  to just pipe source code into the corpus. Source code is heavily edited and\n  re-edited, and shortcuts, autocomplete and snippets are used to produce large\n  amounts of text without actually typing it. Furthermore, in Vim, a lot of\n  typing occurs outside of \"insert\" mode but doesn't wind up reflected in the\n  document. In short, the only way to get an authoritative corpus would\n  effectively be to keylog (capturing keystroke and timing information) for an\n  extended period, which would not be without its technical difficulties, and\n  would also burn through the window of opportunity that I had during parental\n  leave to learn a new layout.\n- The difference between the popular alternative layouts is small, and choosing\n  a \"best\" layout is hard and of dubious advantage; simply switching away from\n  Qwerty towards any other layout would probably be a winning move.\n\nIn my gut, I sensed that Colemak would be good enough, and it comes on OS X by\ndefault, so no messing with layout files or other complicated set-up would be\nrequired in order to use it. Additionally, even though the `h`, `j`, `k`, `l`\nkeys don't have the desired spatial configuration, they _are_ at least close to\none another, and I have the option of using a tool like\n[Karabiner](https://pqrs.org/osx/karabiner/) to end-run around the problem and\ndefine an alternate layer that brings the cursor keys onto the home row whenever\nI hit a dead key or hold down Alt.\n\nSo, I decided to switch to Colemak, build the layout optimizer for fun, and\nthrow a good-but-not-perfect corpus at it (ie. I was going to skip the\nkeylogging step). This was still going to be a non-trivial side-project, with\nmultiple steps involved. In short yak-shaving. Some layouts have names (like\nQGMLWB) are hard to remember and even hard to pronounce. Given the amount of\nyak-shaving involved in my plan, \"Yak\" seemed like a good name for the layout.\n\n## Install\n\n```sh\n$ npm install -g yak-layout\n```\n\n## Usage\n\n```sh\n$ yak help # show usage info\n$ yak corpus-stats # show corpus statistics\n$ yak layout-stats [layout] # show layout statistics (defaults to QWERTY)\n$ yak optimize [layout] # generate an optimal layout\n```\n\n### Sample output\n\n- [yak optimize](https://gist.github.com/wincent/71731c1ba9afaf9f0b35)\n- [yak corpus-stats](https://gist.github.com/wincent/59d46104c20442f9ae2b)\n- [yak layout-stats](https://gist.github.com/wincent/1fc73024b61b19263252)\n\n### `yak optimize`\n\n`yak optimize` takes a couple of options that alter its behavior:\n\n- `-i` or `--iteration-count [count]` changes the number of iterations of its\n  genetic algorithm that `yak` will use to find an optimal layout. The default\n  is 10,000.\n- `-r [count]` or `--rounds [count]` activates a special batch mode in which\n  `yak` will try `count` times to find an optimal layout. Each \"round\" saves its\n  best-seen layouts to disk, and interrupted runs can be resumed by reading from\n  that file. As an example, `-r 1000 -i 20000` would cause `yak` to perform\n  1,000 rounds of optimization, each one of 20,000 iterations.\n\n## Known issues\n\n- You have to B.Y.O.C. (Bring Your Own Corpus) and store in in\n  `./yak/corpus.txt` (although the repo contains a dead-simple script in the\n  \"extras\" directory that I used to throw together a quick-and-dirty corpus).\n- We don't yet model alternate layers (for example, the \"Alt\" layer).\n- We treat shifted versions of keys as wedded to their unshifted keys, always\n  moving them together.\n- Not yet implemented: more sophisticated constraints such as \"move numbers but\n  keep them in this row\".\n- Configurability is limited from the command-line; many things can only be\n  tweaked by editing data structures in the source code.\n- There is no built-in facility for running the `optimize` subcommand\n  repeatedly, accumulating the serialized, optimized layouts onto disk for later\n  processing; there's not built-in facility for analyzing such batches of\n  optimized layouts either.\n\n\n## Links\n\n- Source: [github.com/wincent/yak-layout](https://github.com/wincent/yak-layout)\n- Package:\n  [www.npmjs.com/package/yak-layout](https://www.npmjs.com/package/yak-layout)\n\n## License\n\n### The MIT License (MIT)\n\nCopyright (c) 2015-present Greg Hurrell\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwincent%2Fyak-layout","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwincent%2Fyak-layout","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwincent%2Fyak-layout/lists"}