Skip to main content

Lesson 1: Introduction

Why keyboard shortcuts matter and how duck-vim approaches the problem.

Why keyboard shortcuts?

Keyboard shortcuts aren't just for power users. They serve three audiences:

Power users want to stay on the keyboard. Every time they reach for the mouse, they lose flow. Apps like VS Code, Figma, and Notion thrive because they offer comprehensive keyboard interfaces.

Accessibility requires keyboard navigation. Users who can't use a mouse depend on keyboard shortcuts. WCAG 2.1 guideline 2.1 requires all functionality to be operable through a keyboard.

Efficiency is measurable. Studies consistently show that keyboard shortcuts reduce task completion time by 30-50% for repetitive operations.


The problem with naive approaches

Most developers start with something like this:

// Don't do this
document.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === 'k') {
    openPalette()
  }
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault()
    save()
  }
  // ... 50 more if-statements
})
// Don't do this
document.addEventListener('keydown', (e) => {
  if (e.ctrlKey && e.key === 'k') {
    openPalette()
  }
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault()
    save()
  }
  // ... 50 more if-statements
})

How duck-vim solves this

duck-vim uses a registry pattern. Instead of imperative event handlers, you declare bindings:

registry.register('ctrl+k', {
  name: 'Open Palette',
  execute: () => openPalette(),
})
registry.register('ctrl+k', {
  name: 'Open Palette',
  execute: () => openPalette(),
})

Architecture at a glance

duck-vim is split into small, focused modules:

@gentleduck/vim
├── platform/   -> OS detection, Mod key resolution
├── parser/     -> Parse "ctrl+shift+s" into structured data
├── matcher/    -> Does this KeyboardEvent match this binding?
├── command/    -> Registry + KeyHandler (the core system)
├── sequence/   -> Multi-step sequence matching
├── recorder/   -> Record key combos for settings UIs
├── format/     -> Format bindings for display ("Cmd+S")
└── react/      -> Provider + hooks
@gentleduck/vim
├── platform/   -> OS detection, Mod key resolution
├── parser/     -> Parse "ctrl+shift+s" into structured data
├── matcher/    -> Does this KeyboardEvent match this binding?
├── command/    -> Registry + KeyHandler (the core system)
├── sequence/   -> Multi-step sequence matching
├── recorder/   -> Record key combos for settings UIs
├── format/     -> Format bindings for display ("Cmd+S")
└── react/      -> Provider + hooks

What we'll build in this course

  1. Register and manage keyboard shortcuts in any JavaScript application.
  2. Build multi-key Vim-style sequences.
  3. Integrate shortcuts into React with providers and hooks.
  4. Display shortcuts with platform-aware formatting.
  5. Build a key recorder for shortcut customization UIs.
  6. Build a command palette powered by the registry.
  7. Handle edge cases: scoped bindings, conflict detection, input elements.

Let's start.