{"id":13594342,"url":"https://github.com/caksoylar/keymap-drawer","last_synced_at":"2025-04-09T07:31:44.657Z","repository":{"id":65591173,"uuid":"562298375","full_name":"caksoylar/keymap-drawer","owner":"caksoylar","description":"Visualize keymaps that use advanced features like hold-taps and combos, with automatic parsing","archived":false,"fork":false,"pushed_at":"2024-04-13T07:16:17.000Z","size":621,"stargazers_count":459,"open_issues_count":14,"forks_count":50,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-13T20:09:52.251Z","etag":null,"topics":["keyboard","keymap-drawer","keymaps","qmk","qmk-keymap","zmk"],"latest_commit_sha":null,"homepage":"https://caksoylar.github.io/keymap-drawer","language":"Python","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/caksoylar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2022-11-05T22:36:26.000Z","updated_at":"2024-04-15T00:31:41.390Z","dependencies_parsed_at":"2023-02-18T14:15:47.456Z","dependency_job_id":"26caa466-9ebc-415c-bbbd-ded908328789","html_url":"https://github.com/caksoylar/keymap-drawer","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caksoylar%2Fkeymap-drawer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caksoylar%2Fkeymap-drawer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caksoylar%2Fkeymap-drawer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/caksoylar%2Fkeymap-drawer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/caksoylar","download_url":"https://codeload.github.com/caksoylar/keymap-drawer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223375308,"owners_count":17135346,"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":["keyboard","keymap-drawer","keymaps","qmk","qmk-keymap","zmk"],"created_at":"2024-08-01T16:01:32.034Z","updated_at":"2025-04-09T07:31:44.649Z","avatar_url":"https://github.com/caksoylar.png","language":"Python","funding_links":[],"categories":["Python","Keyboard","Tools and Software","Tools"],"sub_categories":["Keymap Editors GUI"],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg alt=\"keymap-drawer logo\" src=\"https://caksoylar.github.io/keymap-drawer/logo.svg\" max-width=\"100%\"/\u003e\n\u003c/h1\u003e\n\n[![PyPI version](https://img.shields.io/pypi/v/keymap-drawer.svg)](https://pypi.org/project/keymap-drawer/)\n\nParse QMK \u0026 ZMK keymaps and draw them in vector graphics (SVG) format, with support for visualizing hold-taps and combos that are commonly used with smaller keyboards.\n\nAvailable as a [command-line tool](#command-line-tool-installation) or a [web application](https://caksoylar.github.io/keymap-drawer).\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"examples/showcase.yaml\"\u003e\n    \u003cimg alt=\"Example keymap visualization\" src=\"https://caksoylar.github.io/keymap-drawer/showcase.svg\"/\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n## Features\n\n- Draw keymap representations consisting of multiple layers, hold-tap keys and combos\n  - Uses a human-editable YAML format for specifying the keymap\n  - Non-adjacent or 3+ key combos can be visualized by specifying its positioning relative to the keys, with automatically drawn dendrons to keys\n  - Alternatively, output a separate diagram per combo if you have tricky key position combinations\n- Bootstrap the YAML representation by automatically parsing QMK or ZMK keymap files\n- Arbitrary physical keyboard layouts (with rotated keys!) supported, along with parametrized ortho layouts\n- Both parsing and drawing are customizable with a config file, see [\"Customization\" section](#customization)\n- Custom glyph support: render custom SVG icons and not just unicode text\n\nSee examples in [the live web demo](https://caksoylar.github.io/keymap-drawer) for example inputs and outputs.\n\nCompared to to visual editors like [KLE](http://www.keyboard-layout-editor.com/), `keymap-drawer` takes a more programmatic approach.\nIt also decouples the physical keyboard layout from the keymap (i.e., layer and combo definitions) and provides the tooling to bootstrap it quickly from existing firmware configuration.\n\n## Usage\n\n### Try it as a web application\n\nYou can try the keymap parsing and drawing functionalities with a [Streamlit](https://streamlit.io) web application available at \u003chttps://caksoylar.github.io/keymap-drawer\u003e.\nBelow instructions mostly apply for the web interface, where subcommands and option flags are mapped to different widgets in the UX.\n\n### Command-line tool installation\n\nThe recommended way to install `keymap-drawer` is through [pipx](https://pipx.pypa.io), which sets up an isolated environment and installs the application with a single command:\n\n```sh\npipx install keymap-drawer\n```\n\nThis will make the `keymap` command available in your `PATH` to use:\n\n```sh\nkeymap --help\n```\n\nAlternatively, you can `pip install keymap-drawer` in a virtual environment or install into your user install directory with `pip install --user keymap-drawer`.\nSee [the development section](#development) for instructions to install from source.\n\n\u003e #### ℹ️ Windows command-line issues\n\u003e\n\u003e If you are running on Windows, using the `-o`/`--output` parameter to save command outputs to files is recommended instead of redirecting stdout.\n\u003e Otherwise you might run into text encoding issues related to unicode characters in YAMLs and SVGs.\n\n### Bootstrapping your keymap representation\n\n**`keymap parse`** command helps to parse an existing QMK or ZMK keymap file into the keymap YAML representation the `draw` command uses to generate SVGs.\n`-c`/`--columns` is an optional parameter that specifies the total number of columns in the keymap to better reorganize output layers.\n\n- **QMK**: Only json-format keymaps are supported, which can be exported from [QMK Configurator](https://config.qmk.fm/), converted from `keymap.c` via [`qmk c2json`](https://docs.qmk.fm/#/cli_commands?id=qmk-c2json), or from a VIA backup json via [`qmk via2json`](https://docs.qmk.fm/#/cli_commands?id=qmk-via2json):\n\n  ```sh\n  # from keymap.c\n  qmk c2json ~/qmk_firmware/keyboards/ferris/keymaps/username/keymap.c | keymap parse -c 10 -q - \u003esweep_keymap.yaml\n\n  # from VIA backup\n  qmk via2json -kb ferris/sweep sweep_via_backup.json | keymap parse -c 10 -q - \u003esweep_keymap.yaml\n  ```\n\n  Due to current limitations of the `keymap.json` format, combos and `#define`'d layer names will not be present in the parsing output.\n  However you can manually specify layer names using the layer names parameter, e.g. `keymap parse --layer-names Base Sym Nav ...`.\n\n- **ZMK**: `.keymap` files are used for parsing. These will be preprocessed similar to the ZMK build system, so `#define`'s and `#include`s will be expanded.\n\n  ```sh\n  keymap parse -c 10 -z ~/zmk-config/config/cradio.keymap \u003esweep_keymap.yaml\n  ```\n\n  Currently combos, hold-taps, mod-morphs, sticky keys and layer names can be determined via parsing.\n  For layer names, the value of the `display-name` property will take precedence over the layer's node name if provided.\n\nAs an alternative to parsing, you can also check out the [examples](examples/) to find a layout similar to yours to use as a starting point.\n\n### Tweaking the produced keymap representation\n\nWhile the parsing step aims to create a decent starting point, you will likely want to make certain tweaks to the produced keymap representation.\nPlease refer to [the keymap schema specification](KEYMAP_SPEC.md) while making changes:\n\n0. (If starting from a QMK keymap) Add combo definitions using key position indices.\n1. Tweak the display form of parsed keys, e.g., replacing `\u0026bootloader` with `BOOT`. (See [the customization section](#customization) to modify parser's behavior.)\n2. If you have combos between non-adjacent keys or 3+ key positions, add `align` and/or `offset` properties in order to position them better\n3. Add or modify `type` specifiers for certain keys, like `\"ghost\"` for keys optional to the layout\n\nIt might be beneficial to start by `draw`'ing the current representation and iterate over these changes, especially for tweaking combo positioning.\n\n\u003e #### ℹ️ Preserving manual modifications\n\u003e\n\u003e If you need to re-parse a firmware file after it was changed, you can provide the previous parse output that you tweaked to the\n\u003e parse command via `keymap parse -b old_keymap.yaml ... \u003enew_keymap.yaml` and the tool will try to preserve your manual tweaks.\n\n### Producing the SVG\n\nFinal step is to produce the SVG representation using the **`keymap draw`** command.\nHowever to do that, we need to specify the _physical_ layout of the keyboard, i.e., how many keys there are, where each key is positioned etc.\n\nIf you produced your keymap YAML through `keymap parse`, it will have tried to guess the proper layout in the `layout` field of your keymap.\nIf you like you can tweak the field value according to the [spec](KEYMAP_SPEC.md#layout), then finally call the draw command:\n\n```sh\nkeymap draw sweep_keymap.yaml \u003esweep_keymap.ortho.svg\n```\n\nAnd you are done! You can view the output SVG on your browser or use a tool like [CairoSVG](https://cairosvg.org/) or [Inkscape](https://inkscape.org/) to convert to a different format.\n\n\u003e #### ℹ️ Specifying layouts in the CLI\n\u003e\n\u003e If you like you can override the layout specification on the command line.\n\u003e For instance you can provide a QMK keyboard name with `-k`/`--qmk-keyboard` and layout with `-l`/`--layout-name`,\n\u003e or an ortho layout with `--ortho-layout` (using YAML syntax for the value) or `-n`/`--cols-thumbs-notation`.\n\u003e See `keymap draw --help` for details.\n\n## Customization\n\nBoth parsing and drawing can be customized using a configuration file passed to the `keymap` executable.\nThis allows you to, for instance, change the default keycode-to-symbol mappings while parsing, or change font sizes, colors etc. while drawing the SVG.\n\nStart by dumping the default configuration settings to a file:\n\n```sh\nkeymap dump-config \u003emy_config.yaml\n```\n\nThen, edit the file to change the settings, referring to [CONFIGURATION.md](CONFIGURATION.md). You can delete from the file the settings you don't want to change.\n\nYou can then pass this file to either `draw` and `parse` subcommands with the `-c`/`--config` argument (note the location before the subcommand):\n\n```sh\nkeymap -c my_config.yaml parse [...] \u003emy_keymap.yaml\nkeymap -c my_config.yaml draw [...] my_keymap.yaml \u003emy_keymap.svg\n```\n\nSince configuration classes are [Pydantic settings](https://docs.pydantic.dev/usage/settings/) they can also be overridden by environment variables with a `KEYMAP_` prefix:\n\n```sh\nKEYMAP_raw_binding_map='{\"\u0026bootloader\": \"BOOT\"}' keymap parse -z zmk-config/config/cradio.keymap \u003ecradio.yaml\n```\n\nDrawing parameters that are specified in the `draw_config` field can also be overridden in [the keymap YAML](KEYMAP_SPEC.md#draw_config).\nUsing this you can preserve your style customizations along with your keymap in a single file.\n\n## Custom SVG Glyphs\n\n`keymap-drawer` can also use SVG glyphs for legends, in addition to plain or unicode text. The easiest way to do this is\nto use the `$$source:id$$` notation [certain `source`s](CONFIGURATION.md#glyph_urls), which will automatically fetch\nthe SVGs from a given remote `source`, e.g. using `$$mdi:volume-mute$$` will insert the\n[mute icon from Material Design Icons](https://pictogrammers.com/library/mdi/icon/volume-mute/).\nThe following `source` values are currently supported:\n\n- `mdi`: [Pictogrammers Material Design Icons](https://pictogrammers.com/library/mdi/) (use icon name as `id`)\n- `mdil`: [Pictogrammers Material Design Icons Light](https://pictogrammers.com/library/mdil/) (use icon name as `id`)\n- `material`: [Google Material Symbols](https://fonts.google.com/icons) (use value in \"Android\" tab as `id`)\n- `tabler`: [Tabler Icons](https://tabler.io/icons) (\"Outline\" style, use icon name as `id`)\n- `phosphor`: [Phosphor Icons](https://phosphoricons.com) (use `\u003cweight\u003e/\u003cname\u003e` as `id`, e.g. `$$phosphor:bold/lock$$`)\n- `fa`: [Font Awesome](https://fontawesome.com/search?ic=free) (use `\u003ctype\u003e/\u003cname\u003e` as `id` where `type` is `solid`, `regular` or `brands`, e.g. `$$fa:brands/apple$$`)\n\nFetched SVGs will be [cached by default](CONFIGURATION.md#use_local_cache) to speed up future runs.\n\nThe height of the SVG is bound by the config properties `glyph_{tap,hold,shifted}_size` and width will maintain the aspect ratio.\nTo allow for customization, glyphs are assigned CSS classes `glyph` and `\u003cglyph_name\u003e`.\nSVG glyphs currently cannot be used alongside other text in the same legend field.\n\nInstead of automatically fetching them from remote sources, you can also define custom SVG blocks under `draw_config`.\nAfter a glyph is defined this way it can be used in key fields via the glyph name surrounded by `$$`, e.g. `$$vol_up$$`.\nThe provided SVG must specify a `viewBox`, given that positional or dimensional properties will be calculated by `keymap-drawer`:\n\n```yaml\ndraw_config:\n  # specify the size to bound the vertical dimension of your glyph, below are defaults\n  glyph_tap_size: 14\n  glyph_hold_size: 12\n  glyph_shifted_size: 10\n  glyphs: # mapping of glyph name to be used to svg definition\n    vol_up: |\n      \u003csvg viewBox=\"2 3 34 33\"\u003e\n        \u003cpath style=\"stroke: black; fill: black;\" d=\"M23.41,25.25a1,1,0,0,1-.54-1.85,6.21,6.21,0,0,0-.19-10.65,1,1,0,1,1,1-1.73,8.21,8.21,0,0,1,.24,14.06A1,1,0,0,1,23.41,25.25Z\"/\u003e\n        \u003cpath style=\"stroke: black; fill: black;\" d=\"M25.62,31.18a1,1,0,0,1-.45-1.89A12.44,12.44,0,0,0,25,6.89a1,1,0,1,1,.87-1.8,14.44,14.44,0,0,1,.24,26A1,1,0,0,1,25.62,31.18Z\"/\u003e\n        \u003cpath style=\"stroke: black; fill: black;\" d=\"M18.33,4,9.07,12h-6a1,1,0,0,0-1,1v9.92a1,1,0,0,0,1,1H8.88l9.46,8.24A1,1,0,0,0,20,31.43V4.72A1,1,0,0,0,18.33,4Z\"/\u003e\n      \u003c/svg\u003e\nlayers:\n  Media:\n    - [\"\", \"$$vol_up$$\", \"\", \"\", \"\"]\n```\n\n## Setting up an automated drawing workflow\n\nIf you use a [ZMK config repo](https://zmk.dev/docs/user-setup), you can set up an automated workflow that parses and draws your keymaps, then commits the YAML parse outputs and produced SVGs to your repo.\nTo do that you can add a new workflow to your repo at `.github/workflows/draw-keymaps.yml` that refers to the reusable `keymap-drawer` [workflow](.github/workflows/draw-zmk.yml):\n\n\u003c!-- prettier-ignore --\u003e\n```yaml\n# Example for using the keymap-drawer ZMK user config workflow\nname: Draw ZMK keymaps\non:\n  workflow_dispatch:  # can be triggered manually\n  push:               # automatically run on changes to following paths\n    paths:\n      - \"config/*.keymap\"\n      - \"config/*.dtsi\"\n      - \"keymap_drawer.config.yaml\"\n      # - 'boards/*/*/*.keymap'\n\njobs:\n  draw:\n    uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main\n    permissions:\n      contents: write  # allow workflow to commit to the repo\n    with:\n      keymap_patterns: \"config/*.keymap\"        # path to the keymaps to parse\n      config_path: \"keymap_drawer.config.yaml\"  # config file, ignored if not exists\n      output_folder: \"keymap-drawer\"            # path to save produced SVG and keymap YAML files\n      parse_args: \"\"  # map of extra args to pass to `keymap parse`, e.g. \"corne:'-l Def Lwr Rse' cradio:''\"\n      draw_args: \"\"   # map of extra args to pass to `keymap draw`, e.g. \"corne:'-k corne_rotated' cradio:'-k paroxysm'\"\n```\n\n### Modifying the workflow-generated commit\n\nThe workflow will add the generated SVG and keymap representation YAML files to the `output_folder`, and generate a new commit with commit message \"keymap-drawer render\" by default. You can modify this commit message with the `commit_message` input param, e.g.:\n\n```yaml\njobs:\n  draw:\n    uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main\n    with:\n      # Use the triggering commit's message, prepending the \"[Draw]\" tag\n      commit_message: \"[Draw] ${{ github.event.head_commit.message }}\"\n      # …other inputs\n```\n\nAlternatively, you can choose to amend the triggering commit instead of generating a new one by using the `amend_commit: true` option. In this case the triggering commit's message will be used by default, and the `commit_message` input will be ignored. E.g.:\n\n```yaml\njobs:\n  draw:\n    uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main\n    with:\n      amend_commit: true\n      # …other inputs\n```\n\n\u003e #### ⚠️ Rewriting history\n\u003e\n\u003e You should understand the implications of rewriting history if you amend a commit that has already been published. See [remarks](https://git-scm.com/docs/git-rebase#_recovering_from_upstream_rebase) in `git-rebase` documentation.\n\n## Community\n\nBelow are a few tools and example usages from the community that might be inspirational, whether they are doing unique things with styling, configuration or legends used, or integrate `keymap-drawer` into other workflows.\n\n### Tools\n\n- [YellowAfterlife's Vial To Keymap Drawer](https://yal-tools.github.io/vial-to-keymap-drawer/): Parser to convert Vial .vil files to keymap YAMLs\n- [jbarr21's `keymap-display`](https://github.com/jbarr21/keymap-display): Uses a [converter script](https://github.com/jbarr21/keymap-display/blob/main/scripts/json2yaml) to convert QMK `keymap.c` to a keymap YAML\n- [hnaderi's fork](https://github.com/hnaderi/keymap-drawer): Contains an example [Dockerfile](https://github.com/hnaderi/keymap-drawer/blob/main/Dockerfile) and publishes unofficial [Docker images](https://github.com/hnaderi/keymap-drawer/blob/main/README.md#using-docker)\n\n### Examples\n\n- [minusfive's ZMK config](https://github.com/minusfive/zmk-config): Uses an [extensive config file](https://github.com/minusfive/zmk-config/blob/main/keymap-drawer/config.yaml) for great results out of the automated drawing workflow, with plenty of SVG glyphs\n- [SethMilliken's ZMK config](https://github.com/SethMilliken/zmk-config): Another config using the automated workflow with a [nice configuration](https://github.com/SethMilliken/zmk-config/blob/main/keymap_drawer.config.yaml) and SVG glyphs\n- [englmaxi's ZMK config](https://github.com/englmaxi/zmk-config): Using key sides setting and CSS tricks to position multiple SVG glyphs in one key\n- [casuanoob's keymap](https://github.com/casuanoob/zmk-config-bkb): Many useful unicode and SVG glyphs in the [keymap YAML](https://github.com/casuanoob/zmk-config-bkb/blob/master/assets/split34_keymap_zmk.yaml)\n- [rafaelromao's keymap](https://github.com/rafaelromao/keyboards#diagram): Advanced keymap with many glyphs and a Inkscape-based PNG conversion command\n- [possumvibes's keymap](https://github.com/possumvibes/keyboard-layout): Separate layer and combo diagrams\n- [infused-kim's ZMK config](https://github.com/infused-kim/zmk-config): Defines a script to [tweak the keymap](https://github.com/infused-kim/zmk-config/blob/main/keymap_img/keymap_img_adjuster.py) between parsing and drawing\n- [crides's Fissure write-up](https://github.com/crides/fissure): Custom physical layout with non-square keys and unique SVG styling\n\nIf you use `keymap-drawer`, tag your Github repo with the [`keymap-drawer` topic](https://github.com/topics/keymap-drawer) and it will show up for anyone else searching for it!\n\n## Development\n\nThis project requires Python 3.10+ and uses [Poetry](https://python-poetry.org/) for packaging.\n\nTo get started, [install Poetry](https://python-poetry.org/docs/#installation), clone this repo, then install dependencies with the `poetry` command:\n\n```sh\ngit clone https://github.com/caksoylar/keymap-drawer.git\ncd keymap-drawer\npoetry install  # -E dev -E lsp (optional dependencies)\n```\n\nActivate a virtual environment with the `keymap_drawer` module in Python path and `keymap` executable available by running the output of `poetry env activate`.\nChanges you make in the source code will be reflected when using the module or the command.\n\nIf you prefer not to use Poetry, you can get an editable install with `pip install --editable .` inside the `keymap-drawer` folder.\n\nThe source code for the Streamlit app lives in the [`keymap-drawer-web`](https://github.com/caksoylar/keymap-drawer-web) repo.\n\n## Questions? Feedback?\n\nIf you have any questions on usage or feedback for new or existing features, please check out the [Discussions tab](https://github.com/caksoylar/keymap-drawer/discussions) and feel free to create a new one!\n\n## Related projects\n\n- [@nickcoutsos's ZMK keymap editor](https://github.com/nickcoutsos/keymap-editor)\n- [The original `keymap`](https://github.com/callum-oakley/keymap/)\n- [@jbarr21's keymap parser](https://github.com/jbarr21/keymap-display)\n- [@leiserfg's ZMK parser](https://github.com/leiserfg/zmk-config/tree/master/parser)\n- [Keymapviz](https://github.com/yskoht/keymapviz)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaksoylar%2Fkeymap-drawer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcaksoylar%2Fkeymap-drawer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcaksoylar%2Fkeymap-drawer/lists"}