210 lines
8.2 KiB
Markdown
210 lines
8.2 KiB
Markdown
# keydr
|
||
|
||
A terminal typing tutor with adaptive learning, a skill-tree progression
|
||
system, and live statistics — built in Rust on [ratatui]. Heavily inspired by
|
||
[keybr.com], extended for code practice and the terminal.
|
||
|
||
Warning: still very much a WIP and is heavily vibe-coded so there may be bugs.
|
||
Backwards compatibility is not guaranteed in this phase of development.
|
||
|
||
## What makes it different
|
||
|
||
Most TUI typing apps either drop you on a fixed word list or randomize from a
|
||
dictionary. keydr keeps a model of _your_ typing: per-key timing, per-bigram
|
||
error rates, and a confidence score for every key on the keyboard. The text it
|
||
generates for you is shaped by that model — words bias toward the keys you're
|
||
slowest at, new keys unlock only when the keys you already have are solid, and
|
||
the difficulty grows with you.
|
||
|
||
## Features
|
||
|
||
### Adaptive engine
|
||
|
||
- **Per-key confidence model.** Every keystroke updates an exponential moving
|
||
average of your per-key time. Your `confidence` for a key is your target
|
||
speed divided by that filtered time — a key with `confidence >= 1.0` is at
|
||
or above your target speed.
|
||
- **Gradual letter unlocking.** You start with 6 letters in English-frequency
|
||
order (`e t a o i n …`). A new letter unlocks only when every letter you
|
||
already have is confident, so you're never thrown into the full alphabet at
|
||
once.
|
||
- **Focused-key biasing.** Whichever included key has the lowest confidence
|
||
becomes your "focused" key. The generator searches its Markov chain for
|
||
states containing the focused letter and starts pseudo-words from there, so
|
||
drills naturally pile up practice on your weak spots.
|
||
- **Phonetic pseudo-word generation.** Words are generated from a Markov
|
||
transition table (the same approach as keybr) so they're pronounceable and
|
||
language-shaped, not random consonant noise.
|
||
- **N-gram error tracking.** Beyond single keys, keydr tracks bigrams and
|
||
trigrams with Laplace-smoothed error rates and a redundancy formula that
|
||
separates _genuine_ transition difficulties (e.g. awkward same-finger
|
||
bigrams) from errors that are just proxies for a single weak key. Hard
|
||
bigrams get folded into drill selection.
|
||
|
||
### Skill tree
|
||
|
||
Once you've mastered the lowercase alphabet, you don't just keep grinding
|
||
prose — five sibling branches unlock at once and you pick what to drill next:
|
||
|
||
- **Capitals** (A–Z, 3 levels) — sentence-start and proper-noun rules
|
||
- **Numbers** (0–9, 2 levels)
|
||
- **Prose punctuation** (`. , ' " ? !` …, 3 levels)
|
||
- **Whitespace** (Tab, Enter, …, 2 levels)
|
||
- **Code symbols** (`{ } [ ] ( ) ; : = + - * /` …, 4 levels)
|
||
|
||
Each branch tracks its own current level and its own focused key. You can have
|
||
multiple branches "in progress" at once, and drills can be scoped globally
|
||
(everything you've unlocked) or to a single branch.
|
||
|
||
### Three drill modes
|
||
|
||
- **Adaptive** — the default. Generated text from the phonetic model, biased
|
||
by your skill-tree scope and focused key.
|
||
- **Code** — language-specific syntax practice. Bundled snippets for Rust,
|
||
Python, JavaScript, and Go, with optional opt-in downloads of real code
|
||
samples from GitHub for more variety. Configurable per-language, with an
|
||
onboarding screen on first use and a download progress screen.
|
||
- **Passage** — type real prose from public-domain books (Project
|
||
Gutenberg). Opt-in downloads, configurable paragraphs-per-book limit, falls
|
||
back to bundled content when offline.
|
||
|
||
### Statistics dashboard
|
||
|
||
A multi-tab dashboard with everything the engine has learned about you:
|
||
|
||
- **Dashboard** — current WPM, accuracy, confident-key count, level/streak
|
||
- **History** — recent drills with WPM/accuracy
|
||
- **Activity** — a GitHub-style heatmap of drilling activity over time
|
||
- **Accuracy** — per-key accuracy heatmap laid out on the keyboard
|
||
- **Timing** — per-key timing heatmap
|
||
- **N-grams** — your worst bigrams/trigrams, redundancy scores, watchlist of
|
||
emerging weak transitions, and what's currently driving drill focus
|
||
|
||
### Visual keyboard
|
||
|
||
A live keyboard diagram colors each key by the finger that should press it,
|
||
highlights your focused key, and (in terminals that support the Kitty keyboard
|
||
protocol) lights up modifier keys as you press them. A separate **Keyboard
|
||
Explorer** screen lets you click around the layout to inspect any key's
|
||
stats.
|
||
|
||
### Theming
|
||
|
||
14 built-in themes: Catppuccin (Mocha/Latte), Dracula, Gruvbox (Dark/Darkest),
|
||
Kanagawa (Wave/Dragon/Lotus), Nord, One Dark, Solarized Dark, Tokyo Night,
|
||
Farout, plus an ANSI-safe `terminal-default` that respects your terminal's
|
||
own colors.
|
||
|
||
### Internationalization
|
||
|
||
- **UI translated into 21 languages** (`en`, `de`, `es`, `fr`, `it`, `pt`,
|
||
`nl`, `sv`, `da`, `nb`, `fi`, `pl`, `cs`, `ro`, `hr`, `hu`, `lt`, `lv`,
|
||
`sl`, `et`, `tr`).
|
||
- **Dictionaries for the same 21 languages**, sourced from
|
||
[keybr-content-words](https://github.com/aradzie/keybr.com).
|
||
- **Keyboard layout profiles**: QWERTY, Dvorak, Colemak, German QWERTZ,
|
||
French AZERTY — with per-layout finger maps so the diagram stays accurate.
|
||
- Unicode-normalized (NFC) input matching, so composed and decomposed forms
|
||
of accented characters compare equal.
|
||
|
||
### Import / export
|
||
|
||
Back up everything — config, profile, key stats, ranked stats, drill history
|
||
— to a single timestamped JSON file from the Settings page, and restore it on
|
||
another machine. Machine-local paths (download directories) are preserved
|
||
from the target machine on import. Versioned format with a clear error if
|
||
schemas don't match.
|
||
|
||
### Other niceties
|
||
|
||
- Atomic JSON writes (temp file → fsync → rename) so a crash mid-save can't
|
||
corrupt your stats.
|
||
- Auto-continue between drills with a brief input lock so a trailing
|
||
keystroke doesn't start the next drill prematurely.
|
||
- Mouse support for menus, tabs, and the keyboard explorer.
|
||
|
||
## Build and run
|
||
|
||
keydr is a regular Cargo project. You need a recent Rust toolchain (Rust
|
||
edition 2024, i.e. a 2026-era stable compiler).
|
||
|
||
```sh
|
||
git clone <repo-url> keydr
|
||
cd keydr
|
||
cargo run --release
|
||
```
|
||
|
||
Or build once and run the binary:
|
||
|
||
```sh
|
||
cargo build --release
|
||
./target/release/keydr
|
||
```
|
||
|
||
### CLI flags
|
||
|
||
```sh
|
||
keydr [--theme <name>] [--layout <layout>] [--words <n>]
|
||
```
|
||
|
||
- `--theme, -t` — pick a theme by name for this run (e.g. `dracula`,
|
||
`nord`, `catppuccin-mocha`)
|
||
- `--layout, -l` — pick a keyboard layout: `qwerty`, `dvorak`, `colemak`,
|
||
`de_qwertz`, `fr_azerty`
|
||
- `--words, -w` — number of words per drill
|
||
|
||
Everything else is set from inside the app, on the Settings screen.
|
||
|
||
### Features
|
||
|
||
The `network` Cargo feature (on by default) pulls in `reqwest` and enables the
|
||
optional GitHub code download and Project Gutenberg passage download flows. To
|
||
build a fully offline binary:
|
||
|
||
```sh
|
||
cargo build --release --no-default-features
|
||
```
|
||
|
||
### Files on disk
|
||
|
||
- Config: `~/.config/keydr/config.toml`
|
||
- Profile, key stats, drill history: `~/.local/share/keydr/*.json`
|
||
- Downloaded passages: `~/.local/share/keydr/passages/`
|
||
- Downloaded code samples: `~/.local/share/keydr/code/`
|
||
|
||
(`dirs` is used to resolve these, so the exact paths follow XDG/macOS/Windows
|
||
conventions on your platform.)
|
||
|
||
### Tests and benchmarks
|
||
|
||
```sh
|
||
cargo test
|
||
cargo bench # n-gram benchmarks in benches/
|
||
```
|
||
|
||
## Terminal requirements
|
||
|
||
keydr works in any reasonably modern terminal. For the best experience —
|
||
modifier-key highlighting on the keyboard diagram, unambiguous key
|
||
disambiguation, and per-key release events — use a terminal that supports the
|
||
[Kitty keyboard protocol] (Kitty, WezTerm, foot, recent Ghostty, recent
|
||
Alacritty). keydr falls back gracefully on terminals that don't (tmux, mosh,
|
||
SSH to older hosts) using timer-based heuristics.
|
||
|
||
A true-color terminal is recommended so the bundled themes render as
|
||
intended; the `terminal-default` theme is provided for ANSI-only setups.
|
||
|
||
## License and attribution
|
||
|
||
keydr is licensed under the GNU Affero General Public License v3.0 only
|
||
(AGPL-3.0-only) — see [LICENSE](LICENSE).
|
||
|
||
It incorporates content and ideas from [keybr.com] (dictionaries, the core
|
||
adaptive algorithm). See [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) for
|
||
attribution and [docs/license-compliance.md](docs/license-compliance.md) for
|
||
the compliance process.
|
||
|
||
[ratatui]: https://ratatui.rs/
|
||
[keybr.com]: https://www.keybr.com/
|
||
[Kitty keyboard protocol]: https://sw.kovidgoyal.net/kitty/keyboard-protocol/
|