keymap-drawer

repository·main·Indexed 23 days ago

https://github.com/caksoylar/keymap-drawer

A module and CLI tool (v0.23.0) for parsing QMK and ZMK keymap files and rendering them into high-quality SVG vector graphics. It supports complex layouts including layers, hold-taps, and combos, and allows for customization via configuration files, environment variables, and SVG glyphs from remote sources like Material Design Icons and Font Awesome. It includes a reusable GitHub Action for automating ZMK keymap drawing.

Tokens
11.5K
Snippets
16
Records
57
Agent score
79%

What's inside keymap-drawer

  1. Structure of a Keymap YAML file

    main

    A keymap representation used by keymap draw is defined in YAML format. It consists of four primary root fields:

    • layout: Physical layout specifications (optional if provided via CLI).
    • layers: An ordered mapping of layer names to their key contents.
    • combos: A list of combo specifications (optional).
    • draw_config: Configuration overrides for the drawing process (optional).

    Note: If physical layout parameters are provided both in the command line for keymap draw and within the layout section of the YAML, the CLI arguments take precedence.

    layout:      # physical layout specs, optional if used in CLI
      ...
    layers:      # ordered mapping of layer name to contents
      layer_1:   # list of (lists of) key specs
        - [Q, W, ...]
        ...
      layer_2:
        ...
    combos:      # list of combo specs, optional
      - ...
    draw_config: # config overrides for drawing, optional
      ...
  2. Use extra_layouts for custom or improved QMK layouts

    main

    The extra_layouts/ directory contains QMK layout definitions in a simplified info.json format. These are used when:

    1. A layout is not present in the official QMK keyboards API.
    2. An improved version of an existing layout is desired (e.g., corne_rotated for rotated thumb keys).

    Priority and Naming:

    • Definitions in extra_layouts/ take priority over those fetched from the official QMK API.
    • Naming Convention: File names must match the QMK keyboard name, but forward slashes / must be replaced with @ (e.g., keyboard/name becomes keyboard@name.json).
  3. Understand QMK keyboard mapping overrides

    main

    The qmk_keyboard_mappings.yaml file allows for mapping one qmk_keyboard value to another. This is used to force the tool to prefer specific physical layout definitions over the QMK defaults.

    Matching Rules:

    • Prefix Match: If a key or field ends with a trailing slash /, it matches as a prefix.
    • Exact Match: Otherwise, it requires an exact match.

    This replacement happens transparently during the keymap draw process and cannot be disabled by the user. For example, it can be used to ensure all Corne variants use the extra_layouts/corne_rotated.json definition instead of the standard crkbd/rev1 layout.

  4. Understand how ZMK physical layouts are mapped

    main

    The keymap-drawer tool uses zmk_keyboard_layouts.yaml to map ZMK keyboard names (derived from the .keymap filename) to physical layout specifications.

    When running keymap parse on a ZMK keymap, the tool looks for a layout selected under a chosen node in the Devicetree, specifically using zmk,physical-layout or zmk,matrix-transform.

    Mapping Logic:

    1. keymap parse identifies the selected layout (e.g., &layout_ortho_4x12_2x2u).
    2. It outputs a physical layout spec like {zmk_keyboard: planck, layout_name: LAYOUT_ortho_4x12}.
    3. keymap draw then uses this spec to look up the corresponding entry in zmk_keyboard_layouts.yaml to find the actual physical layout definition.
    4. If layout_name is omitted in the parsed output (common if no layout is explicitly selected in the keymap), keymap draw defaults to the first entry defined for that keyboard in the YAML file.
    / {
        chosen {
            zmk,physical-layout = &layout_ortho_4x12_2x2u;
    
            // or, equivalently:
            // zmk,matrix-transform = &layout_2x2u_transform;
        };
        ...
    };
  5. Generate layouts using `cols_thumbs_notation`

    main

    The cols_thumbs_notation option (CLI flag -n or --cols-thumbs-notation) uses a specialized string syntax to describe ortholinear layouts. This is more flexible than ortho_layout for complex arrangements.

    Syntax Rules

    • Digits: Represent the number of keys in a column.
    • Spaces/Underscores: Separate halves in a split keyboard.
    • Column Modifiers:
      • v or d: Pushes the column down by half a key height.
      • ^ or u: Pushes the column up by half a key height.
    • Thumb Modifiers:
      • > or r: Pushes a thumb row right by half a key width.
      • < or l: Pushes a thumb row left by half a key width.

    Examples

    Asymmetric 32-key split keyboard: 33333+3 2+333331

    • Left side: 5 columns of 3 keys, with a 3-key thumb cluster.
    • Right side: 1 column of 2 keys, then 5 columns (the last one having 1 key), with a 2-key thumb cluster.

    Advanced layout: 2v333+2> 3+13332^ 33

    layout: {cols_thumbs_notation: 33333+3 2+333331}
  6. Install keymap-drawer for development

    main

    To develop on keymap-drawer, you need Python 3.12+ and Poetry.

    1. Clone the repository.
    2. Install dependencies using Poetry.
    3. Activate the virtual environment to make the keymap executable and keymap_drawer module available.

    Alternatively, you can perform an editable install using pip.

    git clone https://github.com/caksoylar/keymap-drawer.git
    cd keymap-drawer
    poetry install
    # To activate the environment:
    poetry env activate
  7. Use SVG glyphs in keymap legends

    main

    You can use SVG glyphs instead of plain text in your keymap legends. There are two primary methods:

    1. Remote Sources

    Use the $$source:id$$ notation to automatically fetch icons from supported remote libraries. The height is controlled by glyph_{tap,hold,shifted}_size and the width maintains the aspect ratio.

    Supported Sources:

    • mdi: Material Design Icons (e.g., $$mdi:volume-mute$$)
    • mdil: Material Design Icons Light
    • material: Google Material Symbols (use the 'Android' tab value as id)
    • tabler: Tabler Icons (Outline style)
    • phosphor: Phosphor Icons (use <weight>/<name> as id, e.g., $$phosphor:bold/lock$$)
    • fa: Font Awesome (use <type>/<name> where type is solid, regular, or brands, e.g., $$fa:brands/apple$$)

    Note: Fetched SVGs are cached by default. Glyphs cannot be used alongside other text in the same legend field.

    2. Custom SVG Blocks

    Define your own SVGs under draw_config.glyphs. After defining a glyph, reference it using $$glyph_name$$ in your layers.

    Requirements: The provided SVG must specify a viewBox.

    draw_config:
      glyph_tap_size: 14
      glyph_hold_size: 12
      glyph_shifted_size: 10
      glyphs:
        vol_up: |
          <svg viewBox="2 3 34 33">
            <path 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.73,8.21,8.21,0,0,1,.24,14.06A1,1,0,0,1,23.41,25.25Z"/>
            <path 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"/>
            <path 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"/>
          </svg>
    layers:
      Media:
        - ["", "$$vol_up$$", "", "", ""]
  8. Automate ZMK keymap drawing with GitHub Actions

    main

    If you use a ZMK configuration repository, you can automate the parsing and drawing of keymaps using a reusable GitHub Action workflow.

    Add a workflow file at .github/workflows/draw-keymaps.yml that uses caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main.

    Configuration Options:

    • keymap_patterns: Path to the keymaps to parse (e.g., config/*.keymap).
    • config_path: Path to your keymap_drawer.config.yaml.
    • output_folder: Where to save produced SVGs and YAML files.
    • parse_args: Extra arguments for keymap parse (e.g., corne:'-l Def Lwr Rse').
    • draw_args: Extra arguments for keymap draw (e.g., corne:'-k corne_rotated').
    • commit_message: Customizes the commit message. Use [Draw] ${{ github.event.head_commit.message }} to prepend a tag to the triggering commit's message.
    • amend_commit: Set to true to amend the triggering commit instead of creating a new one (be careful with history rewriting).
    name: Draw ZMK keymaps
    on:
      workflow_dispatch:
      push:
        paths:
          - "config/*.keymap"
          - "config/*.dtsi"
          - "keymap_drawer.config.yaml"
    
    jobs:
      draw:
        uses: caksoylar/keymap-drawer/.github/workflows/draw-zmk.yml@main
        permissions:
          contents: write
        with:
          keymap_patterns: "config/*.keymap"
          config_path: "keymap_drawer.config.yaml"
          output_folder: "keymap-drawer"
          parse_args: ""
          draw_args: ""
  9. Add new layouts to extra_layouts/

    main

    To add a new layout definition to extra_layouts/:

    1. Check QMK first: Ensure the layout does not already exist in the official QMK repository. Only add to extra_layouts/ if it is missing or if you are providing an improved version.
    2. Naming: Use the QMK keyboard name, replacing / with @ (e.g., my_keyboard@rev1.json).
    3. Format: Ensure the file follows the expected schema and maintains consistent formatting with existing files in the directory.
    4. Reference: Consult the physical layouts documentation for the specific schema and creation tips.
  10. Add new keyboards to zmk_keyboard_layouts.yaml

    main

    To add support for a new ZMK keyboard:

    1. Open zmk_keyboard_layouts.yaml.
    2. Follow the existing organization and place the new keyboard entry in the appropriate section.
    3. If the keyboard uses a physical layout already defined for other keyboards, use one of the existing YAML anchors to maintain consistency.

    Example Entry Structure:

    planck:
      layout_grid_transform: { qmk_keyboard: planck/rev6, layout_name: LAYOUT_ortho_4x12 }
      layout_mit_transform: { qmk_keyboard: planck/rev6, layout_name: LAYOUT_planck_1x2uC }
      layout_2x2u_transform: { qmk_keyboard: planck/rev6, layout_name: LAYOUT_planck_2x2u }
  11. Produce an SVG from a keymap YAML

    main

    Use the keymap draw command to generate the vector graphics. The command requires a keymap YAML file that defines both the keymap (layers, combos, etc.) and the physical layout.

    If the layout was guessed during the parse step, you can tweak the layout field in the YAML according to the specification before drawing. You can also override the layout via CLI using:

    • -k/--qmk-keyboard: Provide a QMK keyboard name.
    • -l/--layout-name: Specify a layout name.
    • --ortho-layout: Provide an ortho layout using YAML syntax.
    • -n/--cols-thumbs-notation: Specify columns using thumbs notation.
    keymap draw sweep_keymap.yaml >sweep_keymap.ortho.svg
  12. Use local ZMK devicetree files

    main

    To use a custom ZMK physical layout defined in devicetree syntax, use the dts_layout option. This is equivalent to the -d or --dts-layout CLI flag.

    Tooling: You can use the ZMK physical layout converter to create these definitions.

    Note: The physical layout you specify does not have to match the firmware origin; as long as the physical layout is compatible with the keymap YAML generated by the parser, you can use QMK or ZMK definitions interchangeably.

    layout: {dts_layout: my_keyboard-layouts.dtsi}