new config store (config.json, gitignored, kept separate from progress so
wiping stats never loses setup) backs a settings page and several preferences:
- lesson toggles: flip individual skills or whole categories on/off from an
apple-settings-style page. an off skill never schedules and never drags the
belt, but still shows in the curriculum as off
- escape aliases (jk/jj -> Esc), injected per interactive drill and folded back
to a single keystroke in the count, so the comfort mapping is free of any
efficiency penalty
- blind sub-choice: start blind on recall-known skills, or cold on everything
- motion target highlight in learn/practice, off for blind
- most-missed panel on top of the curriculum view
menu, lessons page, and curriculum pager now move like a vim buffer:
relativenumber gutter, {count}j/k, gg, {count}G, and / search with n/N on the
lessons list.
goal pane now appears on motion drills too (learn/practice/grind), reading
"go to the highlighted place" with the same cheat block underneath. blind stays
bare. cursor grading still reads the edit window through the split, verified end
to end. _goal_window_script grew a motion_target variant for this.
content: rewrote the weak-but-correct example buffers so each one actually
motivates its technique, and pruned filler and off-skill pool instances. every
challenge re-verified through real vim.
docs: readme progression section explaining the one shared mastery model across
modes, plus a star history chart.
bump to 0.3.0 for release. tests: grader 28, engine 21.
|
||
|---|---|---|
| .github/workflows | ||
| img | ||
| packaging | ||
| src/vimhjkl | ||
| tests | ||
| .gitignore | ||
| .python-version | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
⚔ vimhjkl
The Vim techniques vimtutor never taught you — drilled in real vim/nvim, graded on your actual keystrokes.
⭐ Star it if it makes you faster — it helps a lot!
The dot command, operator + motion grammar, text objects, registers, macros, ex
commands (:g, :normal, ranges), and substitution — 61 lessons, 563
challenges, every one replayed through real vim so the "optimal" it shows you
actually works. While you edit, the goal sits in a pane beside the buffer, so you
practise the move instead of remembering it.
Contents
Install
macOS / Linux (Homebrew)
brew install S-Sigdel/tap/vimhjkl
Arch Linux (AUR)
paru -S vimhjkl # or: yay -S vimhjkl
From source
Needs uv and vim or nvim on PATH — no other
dependencies.
git clone https://github.com/S-Sigdel/vimhjkl && cd vimhjkl
uv sync && uv run vimhjkl
Usage
vimhjkl # interactive menu (from source: uv run vimhjkl)
vimhjkl --drill # Learn: read the move, then drill it
vimhjkl --practice # retry the skills you keep missing
vimhjkl --reps 6 # Grind: one skill, 6× back-to-back
vimhjkl --review # no-editor flashcards
vimhjkl --list # curriculum, mastery, belt
| Mode | What it does |
|---|---|
| Learn | Shows the technique and idiomatic move before you edit |
| Blind | Before/after only — recall the move yourself |
| Practice | Your weakest skills, retry until you pass |
| Grind | One skill, N times back-to-back (--reps N) |
| Review | Read-only flashcards, self-rated, no editor |
How it works
You edit in real vim, not an emulator, with the goal pinned in a read-only pane beside the buffer:
Keystrokes are logged with -W and scored on correctness and efficiency
against a verified par. Command drills (:s, :g, :normal) require an actual
ex command — you can't hand-edit your way to the goal. Mastery is tracked per
skill with Leitner spaced repetition and a belt rank that unlocks harder material
as your boxes fill.
Progression
There is one mastery model, shared by every mode. Learn, Blind, Practice, Grind, and even the no-editor Review flashcards all write to the same boxes — the mode only changes how much help you see before you edit, never whether the result counts. You don't "level up from Blind only"; a clean solve in Learn counts exactly the same.
What moves the needle is committing a passing attempt: correct and efficient (no more than 2× the verified par in keystrokes). Quitting a buffer drill without saving is an abstain — it leaves your mastery untouched, so stopping early never costs you.
Mastery has two axes:
- Leitner box (1 → 5) — do you know the move? A pass bumps the box up one (a fail knocks it down one), filling in after ~3–4 good reps. The box drives how soon a skill comes back, your belt rank, and which new skills unlock.
- Reps toward grooved (25) — have you drilled it into muscle memory? A
box-maxed skill keeps resurfacing on the normal schedule until it has 25 clean
reps; only then is it
✦ groovedand moves to a rare maintenance schedule. One later fail drops the box and pulls it straight back into active review.
New material is gated by difficulty: harder skills unlock only once the tier below them is mastered, so the curriculum opens up as your boxes fill rather than dumping everything at once.
| Mode | Recording |
|---|---|
| Learn | One outcome per attempt |
| Blind | One outcome per attempt |
| Practice | One outcome per skill (best of your retries — no thrash) |
| Grind | Every rep counts (depth toward the 25) |
| Review | Self-rated: j promote · f demote · k skip |
Contributing
Adding a technique is a data change, not an engine change. See CONTRIBUTING.md for the setup, the challenge schema, and how to run the tests.



