From 4ba784c37edcc5d740c508c2065a400727fc9e1c Mon Sep 17 00:00:00 2001 From: Vitaly Vasiltsov <9380195@gmail.com> Date: Fri, 29 May 2026 22:33:41 +0300 Subject: [PATCH 1/2] Add HHKB Pro (60%) keyboard geometry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the Happy Hacking Keyboard Professional 60% geometry as a selectable option for EN_US, EN_UK and RU_RU layouts. HHKB has distinctive physical features that don't fit existing ANSI/ISO/Matrix geometries: - Control key on home row (where CapsLock usually sits) - Backquote/Tilde in top-right corner (not top-left) - Backspace labeled 'Delete', on row 1 right of ']' - No dedicated arrow cluster — Fn-layer instead - Split bottom row: Alt and Meta (Diamond) keys around wide Space Layout follows HHKB Pro Hybrid Mac mode (Apple-style bottom row: Diamond/Command closer to Space, Alt farther out). --- packages/keybr-keyboard/lib/geometry.ts | 7 + packages/keybr-keyboard/lib/geometry/hhkb.ts | 367 +++++++++++++++++++ packages/keybr-keyboard/lib/layout.ts | 3 + packages/keybr-keyboard/lib/load.ts | 2 + 4 files changed, 379 insertions(+) create mode 100644 packages/keybr-keyboard/lib/geometry/hhkb.ts diff --git a/packages/keybr-keyboard/lib/geometry.ts b/packages/keybr-keyboard/lib/geometry.ts index da2b6fb5..a0694dc8 100644 --- a/packages/keybr-keyboard/lib/geometry.ts +++ b/packages/keybr-keyboard/lib/geometry.ts @@ -102,6 +102,12 @@ export class Geometry implements EnumItem { "staggered", ZoneMod.ALL, ); + static readonly HHKB = new Geometry( + "hhkb", // + "HHKB Pro (60%)", + "staggered", + ZoneMod.ALL, + ); static readonly MATRIX = new Geometry( "matrix", // "Matrix/Ergonomic", @@ -120,6 +126,7 @@ export class Geometry implements EnumItem { Geometry.BRAZILIAN_104_FULL, Geometry.JAPANESE_106, Geometry.JAPANESE_106_FULL, + Geometry.HHKB, Geometry.MATRIX, ); diff --git a/packages/keybr-keyboard/lib/geometry/hhkb.ts b/packages/keybr-keyboard/lib/geometry/hhkb.ts new file mode 100644 index 00000000..25e0c679 --- /dev/null +++ b/packages/keybr-keyboard/lib/geometry/hhkb.ts @@ -0,0 +1,367 @@ +import { type GeometryDict } from "../types.ts"; + +/** + * Happy Hacking Keyboard Professional (HHKB Pro) — US ANSI layout. + * + * Compact 60% form factor with these distinctive features: + * - Control key is on the home row (where CapsLock usually sits). + * - Backspace ("Delete" on HHKB) is on row 1, right of `]`. + * - No dedicated arrow / navigation cluster — Fn-layer instead. + * - Split bottom row: two Meta + two Alt keys around a wide Space. + * - Backquote/Tilde lives in the top-right corner, not top-left. + * + * Total board width: 15 units, height: 5 rows. + * + * Targets the classic HHKB Pro 2 / Pro Hybrid layout (60-key). + */ +export const HHKB: GeometryDict = { + // ─── Row 0 (digit row) — Esc + 13 keys + Backquote ──────────────────────── + Escape: { + x: 0, + y: 0, + labels: [{ text: "Esc" }], + zones: ["pinky", "left", "digit"], + }, + Digit1: { + x: 1, + y: 0, + zones: ["pinky", "left", "digit"], + }, + Digit2: { + x: 2, + y: 0, + zones: ["ring", "left", "digit"], + }, + Digit3: { + x: 3, + y: 0, + zones: ["middle", "left", "digit"], + }, + Digit4: { + x: 4, + y: 0, + zones: ["leftIndex", "left", "digit"], + }, + Digit5: { + x: 5, + y: 0, + zones: ["leftIndex", "left", "digit"], + }, + Digit6: { + x: 6, + y: 0, + zones: ["rightIndex", "right", "digit"], + }, + Digit7: { + x: 7, + y: 0, + zones: ["rightIndex", "right", "digit"], + }, + Digit8: { + x: 8, + y: 0, + zones: ["middle", "right", "digit"], + }, + Digit9: { + x: 9, + y: 0, + zones: ["ring", "right", "digit"], + }, + Digit0: { + x: 10, + y: 0, + zones: ["pinky", "right", "digit"], + }, + Minus: { + x: 11, + y: 0, + zones: ["pinky", "right", "digit"], + }, + Equal: { + x: 12, + y: 0, + zones: ["pinky", "right", "digit"], + }, + Backslash: { + x: 13, + y: 0, + zones: ["pinky", "right", "digit"], + }, + Backquote: { + x: 14, + y: 0, + zones: ["pinky", "right", "digit"], + }, + + // ─── Row 1 (top row) — Tab + QWERTY + brackets + Delete (Backspace) ─────── + Tab: { + x: 0, + y: 1, + w: 1.5, + h: 1, + labels: [{ text: "Tab" }], + zones: ["pinky", "left", "top"], + }, + KeyQ: { + x: 1.5, + y: 1, + zones: ["pinky", "left", "top"], + }, + KeyW: { + x: 2.5, + y: 1, + zones: ["ring", "left", "top"], + }, + KeyE: { + x: 3.5, + y: 1, + zones: ["middle", "left", "top"], + }, + KeyR: { + x: 4.5, + y: 1, + zones: ["leftIndex", "left", "top"], + }, + KeyT: { + x: 5.5, + y: 1, + zones: ["leftIndex", "left", "top"], + }, + KeyY: { + x: 6.5, + y: 1, + zones: ["rightIndex", "right", "top"], + }, + KeyU: { + x: 7.5, + y: 1, + zones: ["rightIndex", "right", "top"], + }, + KeyI: { + x: 8.5, + y: 1, + zones: ["middle", "right", "top"], + }, + KeyO: { + x: 9.5, + y: 1, + zones: ["ring", "right", "top"], + }, + KeyP: { + x: 10.5, + y: 1, + zones: ["pinky", "right", "top"], + }, + BracketLeft: { + x: 11.5, + y: 1, + zones: ["pinky", "right", "top"], + }, + BracketRight: { + x: 12.5, + y: 1, + zones: ["pinky", "right", "top"], + }, + Backspace: { + x: 13.5, + y: 1, + w: 1.5, + h: 1, + labels: [{ text: "Delete" }], + zones: ["pinky", "right", "top"], + }, + + // ─── Row 2 (home row) — Control (HHKB feature!) + ASDFGHJKL + ; ' + Return + ControlLeft: { + x: 0, + y: 2, + w: 1.75, + h: 1, + labels: [{ text: "Control" }], + zones: ["pinky", "left", "home"], + }, + KeyA: { + x: 1.75, + y: 2, + zones: ["pinky", "left", "home"], + }, + KeyS: { + x: 2.75, + y: 2, + zones: ["ring", "left", "home"], + }, + KeyD: { + x: 3.75, + y: 2, + zones: ["middle", "left", "home"], + }, + KeyF: { + x: 4.75, + y: 2, + zones: ["leftIndex", "left", "home"], + homing: true, + }, + KeyG: { + x: 5.75, + y: 2, + zones: ["leftIndex", "left", "home"], + }, + KeyH: { + x: 6.75, + y: 2, + zones: ["rightIndex", "right", "home"], + }, + KeyJ: { + x: 7.75, + y: 2, + zones: ["rightIndex", "right", "home"], + homing: true, + }, + KeyK: { + x: 8.75, + y: 2, + zones: ["middle", "right", "home"], + }, + KeyL: { + x: 9.75, + y: 2, + zones: ["ring", "right", "home"], + }, + Semicolon: { + x: 10.75, + y: 2, + zones: ["pinky", "right", "home"], + }, + Quote: { + x: 11.75, + y: 2, + zones: ["pinky", "right", "home"], + }, + Enter: { + x: 12.75, + y: 2, + w: 2.25, + h: 1, + labels: [{ text: "Return" }], + zones: ["pinky", "right", "home"], + }, + + // ─── Row 3 (bottom row) — Shift + ZXCVB NM ,./ + Shift + Fn ─────────────── + ShiftLeft: { + x: 0, + y: 3, + w: 2.25, + h: 1, + labels: [{ text: "Shift" }], + zones: ["pinky", "left", "bottom"], + }, + KeyZ: { + x: 2.25, + y: 3, + zones: ["pinky", "left", "bottom"], + }, + KeyX: { + x: 3.25, + y: 3, + zones: ["ring", "left", "bottom"], + }, + KeyC: { + x: 4.25, + y: 3, + zones: ["middle", "left", "bottom"], + }, + KeyV: { + x: 5.25, + y: 3, + zones: ["leftIndex", "left", "bottom"], + }, + KeyB: { + x: 6.25, + y: 3, + zones: ["leftIndex", "left", "bottom"], + }, + KeyN: { + x: 7.25, + y: 3, + zones: ["rightIndex", "right", "bottom"], + }, + KeyM: { + x: 8.25, + y: 3, + zones: ["rightIndex", "right", "bottom"], + }, + Comma: { + x: 9.25, + y: 3, + zones: ["middle", "right", "bottom"], + }, + Period: { + x: 10.25, + y: 3, + zones: ["ring", "right", "bottom"], + }, + Slash: { + x: 11.25, + y: 3, + zones: ["pinky", "right", "bottom"], + }, + ShiftRight: { + x: 12.25, + y: 3, + w: 1.75, + h: 1, + labels: [{ text: "Shift" }], + zones: ["pinky", "right", "bottom"], + }, + Fn: { + x: 14, + y: 3, + w: 1, + h: 1, + labels: [{ text: "Fn" }], + zones: ["pinky", "right", "bottom"], + }, + + // ─── Row 4 (thumb row) — split Meta/Alt around wide Space ───────────────── + // Layout: 1.5U gap, Meta(1U), Alt(1.5U), Space(7U), Alt(1.5U), Meta(1U), 1.5U gap + MetaLeft: { + x: 2.5, + y: 4, + w: 1.5, + h: 1, + labels: [{ text: "◆" }], + zones: ["thumb", "left", "bottom"], + }, + AltLeft: { + x: 1.5, + y: 4, + w: 1, + h: 1, + labels: [{ text: "Alt" }], + zones: ["thumb", "left", "bottom"], + }, + Space: { + x: 4, + y: 4, + w: 7, + h: 1, + labels: [{ text: "Space" }], + zones: ["thumb", "left", "bottom"], + }, + AltRight: { + x: 12.5, + y: 4, + w: 1, + h: 1, + labels: [{ text: "Alt" }], + zones: ["thumb", "right", "bottom"], + }, + MetaRight: { + x: 11, + y: 4, + w: 1.5, + h: 1, + labels: [{ text: "◆" }], + zones: ["thumb", "right", "bottom"], + }, +}; diff --git a/packages/keybr-keyboard/lib/layout.ts b/packages/keybr-keyboard/lib/layout.ts index bc457740..a2c1c906 100755 --- a/packages/keybr-keyboard/lib/layout.ts +++ b/packages/keybr-keyboard/lib/layout.ts @@ -28,6 +28,7 @@ export class Layout implements XEnumItem { Geometry.ANSI_101_FULL, Geometry.ISO_102, Geometry.ISO_102_FULL, + Geometry.HHKB, Geometry.MATRIX, ), ); @@ -168,6 +169,7 @@ export class Layout implements XEnumItem { Geometry.ISO_102_FULL, Geometry.ANSI_101, Geometry.ANSI_101_FULL, + Geometry.HHKB, Geometry.MATRIX, ), ); @@ -542,6 +544,7 @@ export class Layout implements XEnumItem { Geometry.ISO_102_FULL, Geometry.ANSI_101, Geometry.ANSI_101_FULL, + Geometry.HHKB, Geometry.MATRIX, ), ); diff --git a/packages/keybr-keyboard/lib/load.ts b/packages/keybr-keyboard/lib/load.ts index 513c18bb..6d9b7cf3 100755 --- a/packages/keybr-keyboard/lib/load.ts +++ b/packages/keybr-keyboard/lib/load.ts @@ -3,6 +3,7 @@ import { ANSI_101 } from "./geometry/ansi_101.ts"; import { ANSI_101_FULL } from "./geometry/ansi_101_full.ts"; import { BRAZILIAN_104 } from "./geometry/brazilian_104.ts"; import { BRAZILIAN_104_FULL } from "./geometry/brazilian_104_full.ts"; +import { HHKB } from "./geometry/hhkb.ts"; import { ISO_102 } from "./geometry/iso_102.ts"; import { ISO_102_FULL } from "./geometry/iso_102_full.ts"; import { JAPANESE_106 } from "./geometry/japanese_106.ts"; @@ -227,6 +228,7 @@ const geometries = new Map([ [Geometry.JAPANESE_106_FULL, JAPANESE_106_FULL], [Geometry.KOREAN_103, KOREAN_103], [Geometry.KOREAN_103_FULL, KOREAN_103_FULL], + [Geometry.HHKB, HHKB], [Geometry.MATRIX, MATRIX], ]); From 120d9d1492e5e853c83f4b9d231b97276acdc3e1 Mon Sep 17 00:00:00 2001 From: Vitaly Vasiltsov <9380195@gmail.com> Date: Fri, 29 May 2026 22:48:22 +0300 Subject: [PATCH 2/2] Color Alt as pinky zone (green) instead of thumb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On HHKB Pro the Alt key is conventionally pressed with the pinky (same as on full-size keyboards). Only Space and Meta (◆) stay in the thumb zone — Meta because on 60% boards it's natural to press with the thumb for ⌘+C/V/Z shortcuts. --- packages/keybr-keyboard/lib/geometry/hhkb.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/keybr-keyboard/lib/geometry/hhkb.ts b/packages/keybr-keyboard/lib/geometry/hhkb.ts index 25e0c679..d80a5096 100644 --- a/packages/keybr-keyboard/lib/geometry/hhkb.ts +++ b/packages/keybr-keyboard/lib/geometry/hhkb.ts @@ -338,7 +338,7 @@ export const HHKB: GeometryDict = { w: 1, h: 1, labels: [{ text: "Alt" }], - zones: ["thumb", "left", "bottom"], + zones: ["pinky", "left", "bottom"], }, Space: { x: 4, @@ -354,7 +354,7 @@ export const HHKB: GeometryDict = { w: 1, h: 1, labels: [{ text: "Alt" }], - zones: ["thumb", "right", "bottom"], + zones: ["pinky", "right", "bottom"], }, MetaRight: { x: 11,