⌨️ TypeKata
Learn touch typing on the code you already have open — without ever changing it.

English · 简体中文
A kata is a form you repeat until it becomes muscle memory. Most typing trainers hand you a word
list; TypeKata turns your current file into the exercise, and shows you a live keyboard with two
hands on it so you learn which finger presses which key instead of hunting and pecking.

Install
code --install-extension Dickens-Shaw.typekata
Or search for TypeKata in the Extensions view.
Why this one
|
|
| 👐 Finger guidance, not just a word list |
A full keyboard with both hands rendered on top. The target key lights up, the correct finger reaches for it, and the toolbar spells it out: "Press i with your right middle finger." |
| 🔒 Your file is never modified |
Progress is drawn with editor decorations. Typing, backspace, delete, paste and cut are all intercepted before they reach the document. Close the session and every character is exactly where you left it. |
| 📄 Practice real code |
Select a block to drill it, or practice the whole file. No copy-paste into a separate window, no leaving your editor. |
| 🀄 IME-aware |
Chinese and other composed input work. Composition is buffered and only scored once it commits, so half-finished candidates never land in your file. |
| 📊 Live stats that fit the panel |
Speed, accuracy, elapsed time, progress and error count as cards flanking the keyboard, plus a keystroke-rate sparkline. |
| 🔥 Knows what you keep getting wrong |
Every keystroke is recorded per key and per syntax token, so => missed inside = and > still shows up as =>. The report turns that into a keyboard heatmap and a weak-spot ranking. |
| 🎯 Practice sources beyond the current file |
Your uncommitted Git diff, a daily challenge that is the same for everyone that day, a drill built from your own project, or one aimed squarely at your weakest keys. |
Quick start
- Open any text or code file.
- Select the block you want to drill, or select nothing to practice the whole file.
- Right-click → Enable typing practice, or click Enable typing practice in the
Practice keyboard panel at the bottom.
- Start typing. Focus returns to the editor automatically — there is no separate "start" step.
Only a correct character advances the cursor. A wrong key flashes red and holds you in place, so
you cannot outrun your accuracy.
When the passage is done the panel swaps the hands for an error heatmap and shows your score next
to it — including how this run compares to your last one, and how many days in a row you have
practised. From there you can retry the same passage, pull a fresh one, or open the full report.
Where to practice from
Beyond the current file, every source below opens as a read-only typekata: document, so there is
never a real file to accidentally save.
| Source |
Command |
What you get |
| Current file or selection |
typekata.start / typekata.practiceSelection |
What you already have open |
| Git diff |
typekata.practiceGitDiff |
The lines you added — uncommitted, or across the last 1 or 5 commits |
| Daily challenge |
typekata.practiceDaily |
A fixed passage seeded by today's date, so it is stable all day and changes at midnight |
| Targeted drill |
typekata.practiceDrill |
Weak-spot lines, real lines sampled from your workspace, or a built-in corpus by language |
Finishing the daily challenge marks the day done and extends your streak; stopping halfway does not.
Your report
The chart icon in the panel toolbar opens your report at any time — during a session, between
sessions, or before you have ever started one. It is also on the editor's right-click menu and in
the command palette as TypeKata: Show practice report (typekata.showReport). The report
collects everything so far:
- Error heatmap on the keyboard — redder keys are the ones you miss most.
- Weakest keys / weakest syntax / slowest keys — ranked by error rate, with the sample count
shown so you can judge how much to trust each row. Entries below the sample threshold are left
out entirely rather than reported as a misleading 100%.
- Last 7 days — average WPM per day, with days you skipped drawn as empty bars instead of being
interpolated away.
Everything is stored locally under the extension's global storage — nothing is uploaded. TypeKata:
Clear practice history wipes it.
The panel
The Practice keyboard view lives in the bottom panel next to Problems and Terminal.
- Left cards — speed in WPM, accuracy, and a sparkline of your keystroke rate over the last
40 samples.
- Center — the keyboard with both hands. The target key is tinted with its finger's color.
- Right cards — elapsed time, progress with a bar and a
typed / total count, and errors.
- Toolbar — the action buttons, plus a globe (panel language) and a palette (accent color).
Below 720px the stat cards fold away so the keyboard keeps its space. Characters with no key on a
US layout — CJK, emoji — leave the keyboard unlit, keep the hands neutral, and switch the hint to
"Use your input method to enter X".
Commands
| Command |
ID |
Default key |
| Enable typing practice |
typekata.start |
— |
| Disable typing practice |
typekata.stop |
— |
| Toggle typing practice |
typekata.toggle |
Ctrl/Cmd+Alt+T |
| Reset practice |
typekata.reset |
Ctrl/Cmd+Alt+R |
| Practice selection |
typekata.practiceSelection |
— |
| Practice Git diff |
typekata.practiceGitDiff |
— |
| Daily challenge |
typekata.practiceDaily |
— |
| Targeted drill |
typekata.practiceDrill |
— |
| Show practice report |
typekata.showReport |
— |
| Copy last result |
typekata.copyResult |
— |
| Clear practice history |
typekata.clearHistory |
— |
| Show practice keyboard |
typekata.showKeyboard |
— |
| Pick panel language |
typekata.pickLanguage |
— |
| Pick accent color |
typekata.pickAccent |
— |
Only the two toggles are bound by default. To bind another, add to keybindings.json:
{ "key": "ctrl+alt+g", "command": "typekata.practiceGitDiff" }
Settings
| Setting |
Values |
Default |
Description |
typekata.language |
auto, en, zh-cn |
auto |
Language of this extension's panel, status bar and notifications. Independent of the editor's display language. |
typekata.accentColor |
auto, blue, green, purple, orange, pink |
auto |
Drives the stat numbers, sparkline, progress bar and target badge. auto follows your color theme. |
typekata.strictMode |
boolean |
false |
Turn off suggestions, inline completions and Copilot for the duration of a session, then put your settings back. |
typekata.sessionMode |
full, timed, count |
full |
Whether a session ends when the passage is done, when the clock runs out, or after a set number of characters. |
typekata.timeLimitSeconds |
15–3600 |
60 |
Session length in timed mode. The clock starts on your first keystroke, not when you enable the mode. |
typekata.charLimit |
20–100000 |
300 |
How much of the passage to use in count mode. |
typekata.backspace |
block, allow |
block |
Whether Backspace is ignored or steps back one character. Either way it never edits the document, and stepping back does not undo an error you already made. |
Strict mode
typekata.strictMode writes to your global settings — editor.quickSuggestions,
editor.inlineSuggest.enabled, github.copilot.enable and a few neighbours — and restores them
when the session ends. Because a crash mid-session would otherwise leave your completions switched
off for good, the original values are written to disk before they take effect, and the extension
checks for and undoes any leftovers every time it activates.
Languages
Practice content works with any script. Composed input goes through compositionStart /
replacePreviousChar / compositionEnd, which are intercepted alongside type, so nothing is
written to the document until the IME commits. Characters are compared by code point, so an emoji
counts as one character rather than two UTF-16 units.
Interface language is controlled by typekata.language — the globe button in the toolbar
is its shortcut. Switching takes effect immediately with no window reload, and does not touch the
editor's own display language.
One limit worth knowing: command palette titles and settings descriptions are resolved by VS Code
from package.nls.*.json, so those always follow the editor language. The setting covers the
panel, the status bar and notifications.
How your document stays untouched
Three layers, because type alone is not enough:
type and the composition commands are overridden while a session is active, so keystrokes
are scored instead of inserted.
- Destructive commands are rebound to a no-op — backspace, shift+backspace, delete, paste, cut
and delete-line, all scoped to
typekata.active && editorTextFocus.
onDidChangeTextDocument is a tripwire. If the document changes anyway — another extension,
a format-on-save, anything — the session stops immediately and tells you, rather than quietly
letting your file drift.
Known limitations
- Once you drag the panel view somewhere else, VS Code remembers that position and it overrides the
default.
View: Reset View Locations puts it back.
- Multi-cursor editing is not supported during a session.
- Practicing a whole large file is possible but unwieldy; selecting a block is usually better.
- Command palette titles and settings descriptions follow the editor language, not
typekata.language.
Ideas
Not built yet, in rough order of appeal: alternative keyboard layouts, per-language leaderboards,
and drills generated from the code your AI assistant writes most often.
Development
npm install
npm run build # bundle out/extension.js
npm run watch # rebuild on change
npm run package # produce the .vsix
Press F5 from the repository root (the workspace containing plugin/) to launch an Extension
Development Host with the Run TypeKata Extension configuration.
npm run preview renders the panel in a plain browser without launching VS Code — useful for
checking layout. It writes out/preview/index.html (mid-session) and out/preview/idle.html
(not started), and takes --lang=en|zh-cn.
The hand and keyboard artwork is generated from ../html/. After editing hand-both.svg:
cd ../html && node build-hand-both.mjs
cd ../plugin && npm run sync-media
Notes for contributors
vscode.l10n binds to env.language and cannot be overridden at runtime, so src/shared/i18n.ts
adds a lookup layer: auto delegates back to vscode.l10n.t, a specific language reads
l10n/bundle.l10n.<lang>.json directly. Call t() rather than vscode.l10n.t().
- To add a language, drop in
l10n/bundle.l10n.<lang>.json and extend both SUPPORTED_LANGUAGES
in i18n.ts and the typekata.language enum in package.json.
- Panel strings are injected into the webview through a
data-strings attribute; the webview
contains no hard-coded language. Changing the language rebuilds the page, and the ready message
pushes the target key and stats back so no state is lost.
- Decorations collapse to three ranges — correct, cursor, pending — rather than one per character,
which is what keeps large files responsive.
- Every practice source implements
PracticeSource (src/sources/). Virtual ones return a
read-only typekata: document from open(), so TypingSession never needs to know whether it is
driving a real file.
TypingSession takes the text from document.getText(range) rather than from the source, so the
content check that guards against outside edits can never trip on a line-ending mismatch.
- The heatmap's char-to-key mapping is computed on the extension side with
getVirtualKeyId(); the
webview receives key IDs, so there is only one keyboard layout table in the codebase.
- Sample-size thresholds in
src/stats/analysis.ts exist to stop a single miss out of two attempts
from being reported as a 100% error rate. Raise them, don't remove them.
- Corpora are plain JSON in
media/corpora/. Adding a language is a new file — nothing else needs
to change.
License
MIT