Application Layer¶
Business logic and processing components.
Keymap Generator¶
keymap_generator ¶
Main orchestration module for keymap image generation.
This module provides the primary entry point for generating Svalboard keymap visualization images. It coordinates the loading of configuration and keymap files, transformation of keycodes to display labels, rendering of SVG drawings, and export to image files.
The generation pipeline follows these steps: 1. Load configuration (with gradient generation for layer colors) 2. Load keymap from file or stdin 3. Transform keycodes to renderable target keys 4. Draw SVG images for requested layers 5. Export drawings to output directory
Example
>>> from pathlib import Path
>>> from skim.data.cli import InputFiles, OutputFiles, KeymapGeneratorTargets
>>> from skim.application.keymap_generator import generate_keymap
>>> inputs = InputFiles(keymap=Path("keymap.kbi"))
>>> outputs = OutputFiles(output_dir=Path("./images"), output_format="png")
>>> targets = KeymapGeneratorTargets(all_layers=True, overview=True)
>>> generate_keymap(inputs, outputs, targets)
logger
module-attribute
¶
Module-level logger for keymap generation operations.
generate_keymap ¶
generate_keymap(
inputs: InputFiles,
outputs: OutputFiles,
targets: KeymapGeneratorTargets,
show_special_keys_legend: bool = True,
show_symbol_legend: bool = True,
symbol_legend_flow: str | None = None,
symbol_legend_columns: int | None = None,
macros_scale: float | None = None,
tap_dances_scale: float | None = None,
symbols_scale: float | None = None,
title: str | None = None,
copyright_text: str | None = None,
double_south: bool = False,
width: float | None = None,
adjust_lightness: float | None = None,
adjust_saturation: float | None = None,
) -> None
Generate keymap visualization images.
Main entry point for the keymap generation pipeline. Loads configuration and keymap data, transforms keycodes to display labels, renders SVG drawings, and exports them to the specified output directory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inputs
|
InputFiles
|
Configuration for input files (keymap path, config path, stdin flag). |
required |
outputs
|
OutputFiles
|
Configuration for output (directory, format, overwrite flag). |
required |
targets
|
KeymapGeneratorTargets
|
Specification of which layers and views to generate. |
required |
Raises:
| Type | Description |
|---|---|
SystemExit
|
If the output directory path exists but is not a directory. |
Note
The output directory is created if it doesn't exist. Existing files may be overwritten depending on the outputs.force_overwrite setting.
Source code in src/skim/application/keymap_generator.py
Config Generator¶
config_generator ¶
Configuration generator for creating skim config YAML files.
Provides :class:ConfigGenerator which can produce default configuration
templates or extract metadata from Keybard (.kbi) files to generate
pre-populated configuration files.
Example
Generate default config::
generator = ConfigGenerator()
print(generator.generate_default())
Generate from Keybard file::
generator = ConfigGenerator()
yaml_config = generator.generate_from_keybard(
Path("layout.kbi").read_text(),
adjust_lightness=0.31,
)
Path("skim-config.yaml").write_text(yaml_config)
ConfigGenerator ¶
Generates skim configuration YAML from defaults or source files.
generate_default ¶
Generate YAML from SkimConfig defaults.
Returns:
| Type | Description |
|---|---|
str
|
YAML string containing the default skim configuration. |
Source code in src/skim/application/config_generator.py
generate_from_keybard ¶
generate_from_keybard(
keybard_content: str,
adjust_lightness: float | None = None,
adjust_saturation: float | None = None,
) -> str
Generate config YAML by extracting metadata from a Keybard file.
Parses the .kbi JSON to extract layer colors, layer names, and custom keycode definitions. Optionally applies color adjustments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
keybard_content
|
str
|
JSON string from a .kbi file. |
required |
adjust_lightness
|
float | None
|
Target lightness (0.0-1.0) for extracted colors. |
None
|
adjust_saturation
|
float | None
|
Max saturation (0.0-1.0) for extracted colors. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
YAML string containing the generated skim configuration. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If keybard_content is not valid JSON. |
Source code in src/skim/application/config_generator.py
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | |
generate_from_keymap ¶
Generate config YAML from a Vial or c2json keymap file.
Detects the keymap format, counts layers to create default layer
entries with auto-generated colors, scans for non-standard
keycodes to populate overrides, and emits keycodes.macros and
keycodes.tap_dances populated from the parsed keymap.
For Keybard files, delegates to generate_from_keybard() which extracts richer metadata (layer names, colors, custom keycodes).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
JSON string from a keymap file (.vil or .json). |
required |
Returns:
| Type | Description |
|---|---|
str
|
YAML string containing the generated skim configuration. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If content is not valid JSON or format is unknown. |
Source code in src/skim/application/config_generator.py
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 | |
macro_preview ¶
macro_preview(
macro: SvalboardMacro[str], adapter: KeycodeLabelAdapter
) -> str
Format a macro as a single-line preview string.
" | "-separated actions. Keys inside an action are resolved
through the keycode-label adapter and joined with ",". Text and
delay actions use raw NerdFont markers (resolved to glyphs at TUI
display time).
Source code in src/skim/application/config_generator.py
tap_dance_preview ¶
tap_dance_preview(
tap_dance: SvalboardTapDance[str],
adapter: KeycodeLabelAdapter,
) -> str
Format a tap dance as a single-line preview string.
Initials in fixed order (t:, h:, dt:, th:), space
joined, omitting fields whose value is None. The tapping term
is not shown.
Source code in src/skim/application/config_generator.py
macro_to_config_entry ¶
macro_to_config_entry(
macro: SvalboardMacro[str], adapter: KeycodeLabelAdapter
) -> Macro | None
Convert a parsed macro into a config-ready Macro model.
Returns None when macro.actions is empty so the bootstrap
can skip placeholder rows that source formats reserve.
Source code in src/skim/application/config_generator.py
tap_dance_to_config_entry ¶
tap_dance_to_config_entry(
tap_dance: SvalboardTapDance[str],
adapter: KeycodeLabelAdapter,
) -> TapDance | None
Convert a parsed tap dance into a config-ready TapDance model.
Returns None when all four key fields are None so the
bootstrap can skip placeholder rows.
Source code in src/skim/application/config_generator.py
Loaders¶
loaders ¶
Data loading modules for keymaps, configuration, and assets.
This package provides loaders for: - Keymap files (C2JSON, Vial, Keybard) - Skim configuration (YAML) - Keycode mappings - Nerd Font glyphs
__all__
module-attribute
¶
load_keycode_mappings
cached
¶
load_keycode_mappings(
keycodes_config: Keycodes,
) -> KeycodeMappings
Load and merge keycode mappings.
Loads the bundled keycode-mappings.yaml file and applies any user-provided pre-processing and override mappings from the skim configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
keycodes_config
|
Keycodes
|
The keycode overrides from the skim configuration (SkimConfig.keycodes). |
required |
Returns:
| Type | Description |
|---|---|
KeycodeMappings
|
Dictionary containing merged keycode mappings with keys: |
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
KeycodeMappings
|
|
Source code in src/skim/application/loaders/keycode_mappings_loader.py
load_keymap ¶
load_keymap(
file_path: Path | None,
layer_indices: list[int] | None = None,
) -> SvalboardKeymap[str]
Load a complete keymap from file or stdin.
Source code in src/skim/application/loaders/keymap_loader.py
load_nerdfont_glyphs
cached
¶
Load Nerd Font glyph mappings from the bundled JSON file.
Reads the nerd_glyphnames.json file from the assets directory and transforms it into a dictionary mapping prefixed glyph names to their corresponding Unicode characters.
The function uses lru_cache to cache the loaded mappings, ensuring
the JSON file is only read once per process lifetime.
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dictionary mapping glyph names (prefixed with "nf-") to their |
dict[str, str]
|
corresponding Unicode characters. For example: |
dict[str, str]
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the nerd_glyphnames.json file is not found in the assets/data directory. |
Example
Source code in src/skim/application/loaders/nerdfont_glyphs_loader.py
load_skim_config ¶
load_skim_config(
config_path: Path | None = None,
) -> SkimConfig
Load skim configuration from a YAML file.
Loads and validates configuration from the specified YAML file. If no path is provided or the path doesn't point to an existing file, returns a default SkimConfig with all default values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config_path
|
Path | None
|
Optional path to a YAML configuration file. If None or if the file doesn't exist, returns default configuration. |
None
|
Returns:
| Type | Description |
|---|---|
SkimConfig
|
A validated SkimConfig instance, either loaded from the file or |
SkimConfig
|
with default values. |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If the YAML content doesn't match the expected configuration schema. |
YAMLError
|
If the file content is not valid YAML. |
Example
Source code in src/skim/application/loaders/skim_config_loader.py
Render¶
render ¶
Rendering module for generating keymap visualizations.
This package owns every image entry point — the draw_* functions
that take a config + keymap and return a drawsvg.Drawing. Each
one builds a :class:RenderContext, constructs the corresponding
document composable inside it, and hands the result to
:func:render. Composable modules (keymap_layer.py,
keymap_overview.py, macros.py, tap_dance.py,
symbols.py, etc.) own only the composables themselves; the
entry-point shims live here.
Public surface:
- :func:
draw_keymap— top-level orchestrator. Picks which images to render based on :class:KeymapGeneratorTargetsand dispatches to the per-image entry points below. - :func:
draw_overview— multi-layer overview image. - :func:
draw_macros_image— standalone macros image. - :func:
draw_tap_dances_image— standalone tap-dances image. - :func:
draw_special_keys_image— combined macros + tap-dances. - :func:
draw_symbols_image— standalone symbols image.
__all__
module-attribute
¶
__all__ = [
"draw_keymap",
"draw_macros_image",
"draw_overview",
"draw_special_keys_image",
"draw_symbols_image",
"draw_tap_dances_image",
"make_gradient",
]
make_gradient ¶
Generate a 6-color gradient with base color at specified index.
Creates a gradient that interpolates from dark to light colors, with the base color appearing at the specified index position.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_color
|
str
|
The base color in hexadecimal format. |
required |
base_index
|
int
|
Position (0-5) where base color should appear. Colors before this index will be darker, colors after will be lighter. Default: 2 |
2
|
Returns:
| Type | Description |
|---|---|
tuple[str, str, str, str, str, str]
|
List of 6 hexadecimal color strings forming a gradient. |
Examples:
>>> grad = make_gradient("#347156", base_index=2)
>>> len(grad)
6
>>> gradient[2] # Base color at index 2
'#347156'
Source code in src/skim/application/render/styling.py
draw_overview ¶
draw_overview(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
raw_keymap: SvalboardKeymap[str] | None = None,
keycode_mappings: KeycodeMappings | None = None,
selected_layers: set[int] | None = None,
) -> Drawing
Render the multi-layer overview image.
Resolves every section's contents up-front so the document composable receives ready-to-paint data: all macros / tap-dances sorted, plus the union of symbol entries across the rendered layers.
selected_layers, when not None, restricts the overview to
that subset of QMK layer indices (matching the per-layer image
filter behavior of -l/--layer). None keeps the legacy
"render every configured layer present in the keymap" behavior.
Source code in src/skim/application/render/__init__.py
draw_macros_image ¶
draw_macros_image(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
) -> Drawing
Render the standalone macros image.
Body-scale is read from
config.output.style.legend_tables.macros.scale (the CLI
--macros-scale flag updates that field upstream). Body chips
and pills scale by this factor; the chrome (title, footer, outer
padding) stays at the unscaled per-image size.
Source code in src/skim/application/render/__init__.py
draw_tap_dances_image ¶
draw_tap_dances_image(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
) -> Drawing
Render the standalone tap-dances image.
Body-scale is read from
config.output.style.legend_tables.tap_dances.scale (the CLI
--tap-dances-scale flag updates that field upstream).
Source code in src/skim/application/render/__init__.py
draw_special_keys_image ¶
draw_special_keys_image(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
) -> Drawing
Render the combined special-keys image (macros left, tap-dances right).
Source code in src/skim/application/render/__init__.py
draw_symbols_image ¶
draw_symbols_image(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
entries: list[SymbolLegendEntry],
) -> Drawing
Render the standalone symbols image from a pre-collected entry set.
Caller is expected to gate on entries being non-empty (and on
raw_keymap / keycode_mappings availability) — this entry
point doesn't surface "skipping" warnings of its own. The
sibling :func:draw_keymap orchestrator does that gating for
the bundled-image case.
Body-scale is read from
config.output.style.legend_tables.symbols.scale (the CLI
--symbols-scale flag updates that field upstream).
Source code in src/skim/application/render/__init__.py
draw_keymap ¶
draw_keymap(
config: SkimConfig,
keymap: SvalboardKeymap[SvalboardTargetKey],
targets: KeymapGeneratorTargets,
raw_keymap: SvalboardKeymap[str] | None = None,
keycode_mappings: KeycodeMappings | None = None,
) -> dict[str, Drawing]
Top-level dispatch: render every image the targets request.
Returns a {filename_stem: Drawing} dict the caller writes to
disk. Per-image gating logic (skip when there are no macros to
render, etc.) lives here so the per-image entry points stay
config → Drawing without None-returning paths.
Source code in src/skim/application/render/__init__.py
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | |
Exporter¶
exporter ¶
Image exporter with support for Playwright and Cairo backends.
is_playwright_available ¶
is_cairo_available ¶
get_available_export_formats ¶
get_available_render_engines ¶
get_available_render_engines() -> list[RenderEngine]
save_drawings ¶
save_drawings(
outputs: OutputFiles,
drawings: dict[str, Drawing],
render_engine: RenderEngine | None = None,
)
Source code in src/skim/application/exporter/__init__.py
Doctor¶
doctor ¶
Doctor command logic to verify system environment and installation integrity.
CheckResult
dataclass
¶
check_installation_integrity ¶
check_installation_integrity() -> CheckResult
Verify that all bundled assets are present.
Source code in src/skim/application/doctor.py
check_render_engines ¶
check_render_engines() -> Generator[
CheckResult, None, None
]
Check availability of render engines.
Source code in src/skim/application/doctor.py
check_system_fonts ¶
check_system_fonts() -> Generator[CheckResult, None, None]
Check for presence of specific system fonts.
Source code in src/skim/application/doctor.py
check_textual_available ¶
Check if textual TUI library is available.
run_doctor_checks ¶
run_doctor_checks() -> Generator[CheckResult, None, None]
Run all doctor checks.