Keymap SVG Syntax reference

JSON in, SVG out.

Layouts describe the physical grid. Layers describe the key labels. Prefixes add color, visibility, and state without changing the layout shape.

Basic Layout

Non-split boards use a rectangular keys matrix on each layer. Repeated adjacent labels merge into wider keys.

{
  "layout": {
    "split": false,
    "rows": 4,
    "columns": 12
  },
  "layers": {
    "base": {
      "keys": [
        ["tab", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "bspc"],
        ["esc", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'"],
        ["shift", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "shift"],
        ["ctrl", "alt", "gui", "lower", "space", "space", "space", "raise", "left", "down", "up", "right"]
      ]
    }
  }
}
  • rows and columns must match every layer matrix.
  • Use empty strings or null for intentionally blank key labels.
  • Layer order follows the order in the JSON object.
  • Labels can contain spaces; they render as stacked words.

Prefixes

Prefixes are written before a label and separated with ::. They can be composed.

"blue::enter"
"current::lower"
"standalone::current::blue::raise"
"embedded::orange::esc"
  • current:: underlines the key label.
  • standalone:: shows a label only in standalone mode.
  • embedded:: shows a label only in embedded mode.
  • Color prefixes select a named palette color.

Split Boards

Split layouts define left and right matrices per layer. Thumb keys and inner columns are optional.

{
  "layout": {
    "split": true,
    "rows": 3,
    "columns": 6,
    "thumbs": 3,
    "thumb_offset": 1,
    "inner_columns": {
      "left": { "rows": 2, "offset": 0.5 },
      "right": { "rows": 2, "offset": 0.5 }
    }
  },
  "layers": {
    "base": {
      "left": [
        ["q", "w", "e", "r", "t", "tab"],
        ["a", "s", "d", "f", "g", "esc"],
        ["z", "x", "c", "v", "b", "shift"]
      ],
      "right": [
        ["y", "u", "i", "o", "p", "bspc"],
        ["h", "j", "k", "l", ";", "'"],
        ["n", "m", ",", ".", "/", "shift"]
      ],
      "inner": {
        "left": ["ctrl", "gui"],
        "right": ["up", "down"]
      },
      "thumbs": {
        "left": ["alt", "lower", "space"],
        "right": ["enter", "raise", "gui"]
      }
    }
  }
}

When inner_columns is present, each layer may provide matching inner.left and inner.right arrays. Missing inner labels render as blanks.

Layer Embeds

Embedded mode can draw one layer as small overlay labels on another layer.

{
  "layers": {
    "base": {
      "keys": [["q", "w", "e"]]
    },
    "lower": {
      "embed": {
        "layer": "base",
        "position": "down-left",
        "color": "blue"
      },
      "keys": [["1", "2", "3"]]
    }
  }
}
  • layer names the target layer that receives overlays.
  • position can be down-left, down-right, up-left, up-right, or center.
  • color selects the overlay accent.
  • Standalone mode ignores embeds and renders each layer normally.

Colorschemes

A colorscheme can override dark and light theme values. CSS values are intentionally restricted for safe public rendering.

{
  "dark": {
    "base": {
      "background_color": "#101518",
      "rect_fill": "#273236",
      "text_fill": "#edf7f5",
      "layer_fill": "#b9cbc7"
    },
    "colors": {
      "blue": {
        "rect_fill": "#1d4f91",
        "text_fill": "#eff6ff",
        "embed_text_fill": "#9cc7ff"
      }
    }
  }
}
red orange lime teal blue violet slate zinc

Public Limits

The hosted app has bounded uploads and render sizes so arbitrary public input stays manageable.

  • Upload body: 256 KiB by default.
  • Layers: up to 24 by default.
  • Rows: up to 8 and columns up to 14 by default.
  • Total key slots: up to 1500 by default.
  • Label length: up to 80 characters by default.

Server operators can tune these with KEYMAP_MAX_BODY_BYTES, KEYMAP_MAX_LAYERS, KEYMAP_MAX_TOTAL_KEYS, and the other KEYMAP_* environment variables documented in the README.