Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RSType - Rust Typing Trainer

A fast, terminal-based typing trainer written in Rust with multiple typing modes, Wikipedia content, word salad dictionaries, and session history tracking.

Features

  • Multiple typing modes — Forward, Stop, Correct, Sudden Death, and Blind modes for varied training
  • Wikipedia content — fetch random Wikipedia paragraphs for fresh, varied typing material
  • Word salad mode — generate practice text from installable dictionaries (en-US, de-DE, fr, etc.)
  • Configurable text length — one line, short paragraph, paragraph, or long paragraph
  • Session history — every session is recorded in JSONL format with per-keystroke timing data
  • Calendar view — browse training history by month in an interactive calendar
  • In-app configuration — switch modes and settings from the Config screen
  • TUI interface — clean terminal UI built with Ratatui, with toolbar and status bar
  • Shell completions — generate completions for Bash, Zsh, Fish, PowerShell, and Elvish
  • Cross-platform — builds for Linux (x86_64, aarch64), macOS, and Windows

Quick Start

rstype wikipedia download            # Download Wikipedia paragraphs
rstype train                         # Launch the typing trainer
rstype train --mode forward          # Train in forward mode
rstype train --source word-salad     # Train with word salad text
rstype version                       # Show version and build info

Typing Modes

ModeDescription
ForwardCursor advances even on wrong key; errors shown in red
StopCursor stays on wrong key until the correct one is pressed
CorrectLike Forward but must correct all errors before finishing
Sudden DeathOne mistake resets the entire session immediately
BlindTyped characters are hidden (shown as ·); no visual feedback

Philosophy

Practice-oriented, zero-friction typing training — launch and start typing with minimal setup. Convention over configuration with sensible defaults.

Author

Mark Veltzer mark.veltzer@gmail.com

Content Sources

rstype supports multiple sources for typing practice. You can configure the default source in your config file or override it with the --source flag when running the train command.


Wikipedia

The Wikipedia source fetches random, high-quality paragraphs from a local collection. This provides varied, natural language practice on a wide range of topics.

Commands

  • rstype wikipedia download Downloads paragraphs from Wikipedia until your local collection reaches the target size (default: 1000). Use -c or --count to specify a different total count.

    rstype wikipedia download --count 5000
    
  • rstype wikipedia stats Displays statistics about your local collection, including total paragraphs and file size.

  • rstype wikipedia clear Deletes your local collection.

  • rstype wikipedia show Shows the file path where the Wikipedia collection is stored.


Word Salad (Dictionaries)

Word salad mode generates practice text by picking random words from installed dictionaries. This is excellent for drilling common words and improving raw speed without the context of natural sentences.

Commands

  • rstype dict list-remote Lists all language dictionaries available for installation from the wooorm/dictionaries collection.

  • rstype dict install <LANG> Installs a specific dictionary (e.g., en-US, de-DE, fr).

    rstype dict install en-US
    
  • rstype dict list Lists all dictionaries currently installed on your system.

  • rstype dict remove <LANG> Removes an installed dictionary.

  • rstype dict show Shows the directory path where dictionaries are stored.


Usage in Training

To use a specific source during a training session:

# Train with Wikipedia paragraphs
rstype train --source wikipedia

# Train with Word Salad (uses the first available installed dictionary)
rstype train --source word-salad

You can also specify the target length of the text:

# Possible lengths: one-line, short-paragraph, paragraph, long-paragraph
rstype train --source wikipedia --length short-paragraph

Keyboard Shortcuts

Global shortcuts (work on every screen)

KeyAction
Ctrl+CExit the application (intercepted by app to cleanly restore terminal)
Ctrl+TGo to Train screen
Ctrl+GGo to Config screen
Ctrl+HGo to History (calendar) screen
Ctrl+EExit the application cleanly
EscGo back to Train screen (from Config or History), or exit if already on Train

Train screen

KeyAction
Any character keyStart session (on first keypress), type character
BackspaceDelete last character (move cursor back)
Space / Enter / RRestart session (only when session is Done)

Config screen

KeyAction
/ Move selection between modes
EnterSave selected mode and return to Train screen

History (calendar) screen

KeyAction
Go to previous month
Go to next month

Notes

  • Ctrl+C is intercepted by the app (raw mode captures it before the OS). It exits cleanly, restoring the terminal. This is preferable to a raw SIGINT which would leave the terminal in raw mode.
  • Navigating away from the Train screen mid-session silently discards the in-progress session (it is not saved to history).

Status Bar Design

Overview

A single-row status bar is displayed at the bottom of the terminal window on all screens. It is always visible and provides authorship and branding information.


Location

The status bar occupies the last row of the terminal (area.height - 1). The usable body area (toolbar to status bar) is therefore area.height - 2 rows.

┌─────────────────────────────────────┐  ← row 0: toolbar
│                                     │
│           body content              │
│                                     │
└─────────────────────────────────────┘  ← last row: status bar

Content

rstype by Mark Veltzer <mark.veltzer@gmail.com>
  • Left-aligned
  • Padded with spaces to fill the full terminal width
  • No dynamic content — it never changes at runtime

Visual style

PropertyValue
BackgroundWhite
ForegroundBlack
Modifiernone

Matches the toolbar at the top — both are white bars, framing the black body in between. This gives the UI a consistent, symmetrical appearance.


Rationale

  • Branding — identifies the application and its author in any screenshot or recording.
  • Symmetry — the toolbar occupies the top row; a status bar at the bottom gives the UI a balanced, framed appearance common in terminal applications (vim, htop, etc.).
  • Static content — future versions could use the status bar to show transient messages (e.g. “Config saved”) without disrupting the main body layout, since the row is already reserved.

Minimum Real Estate Requirements

Overview

The app checks terminal dimensions at startup and refuses to run if the terminal is too small to render correctly. The minimums are stored in ~/.config/rstype.toml as min_cols and min_rows.


Per-screen analysis

ScreenMin widthMin heightNotes
Toolbarany1Always 1 row
Status barany1Always 1 row
Train475Text (43 chars) + box borders + blank lines
Train + progress bar478Box + progress + stats rows
Results528Fixed-size results box
Config6010Fixed-size config box
Calendar74237 cells × 10 chars + borders; 6 weeks × 3 rows + headers + borders

Overall minimum (most demanding screen: Calendar)

min_cols = 76    # 74 (calendar box) + 2 side margin
min_rows = 26    # 23 (calendar box) + 2 (toolbar + statusbar) + 1 top/bottom margin

These are the default values. They can be changed in ~/.config/rstype.toml:

mode = "forward"
min_cols = 76
min_rows = 26

Behaviour when terminal is too small

On startup, the app queries the terminal size. If either dimension is below the configured minimum, it prints an error to stderr and exits with code 1:

Error: terminal too small (current: 60×20, required: 76×26)

Rationale

  • Config option rather than hard-coded constant: allows users with small terminals to lower the minimum if they accept degraded rendering, and allows future screens with different requirements to raise it without code changes.
  • Startup check rather than per-frame: simpler, no need to handle the app being “paused” mid-session because the window was resized.

Future Mode Ideas

This chapter collects ideas for additional typing modes beyond the five currently implemented (Forward, Stop, Correct, Sudden Death, Blind). These are candidates for future implementation — not promises. They are grouped by what kind of skill or experience they target.

Current Modes (for reference)

ModeConcept
ForwardErrors are shown but don’t block progress
StopCursor blocks until you hit the correct key
CorrectErrors advance but you must backspace and fix them before finishing
Sudden DeathOne mistake resets you to the start
BlindNo visual feedback — all typed chars shown as dots

Accuracy / Penalty Modes

Rewind

A wrong key sends you back N characters (e.g. 3–5) rather than all the way to the start like Sudden Death. A middle ground between Correct and Sudden Death — the penalty hurts but isn’t catastrophic.

Three Strikes

You get N lives. Each mistake costs one. Lose them all and the session restarts. Adds tension without the brutality of Sudden Death, and gives the user a visible “health” indicator in the status bar.

Decay

Each mistake adds a time penalty (e.g. +2 seconds) to your final score. You can keep going, but errors are costly. Encourages a risk/reward calculation: is it faster to backspace-and-fix or to eat the penalty?

Speed / Pressure Modes

Countdown

You have a fixed time limit (e.g. 30s, 60s, 120s). Type as much as you can before time runs out. Measures raw throughput under pressure. This is the standard mode in most web-based typing trainers (monkeytype, 10fastfingers).

Accelerating

You must maintain a minimum WPM that gradually increases over the session. Fall below the threshold and you fail. Tests how fast you can sustain accuracy — a moving target rather than a fixed one.

Sprint

Short bursts (single words or short phrases) back-to-back, with per-word timing rather than whole-text timing. Focuses on burst speed and reaction time rather than sustained typing.

Learning / Training Modes

Mirror

The text is displayed reversed (or the keyboard mapping is flipped). A neuroplasticity challenge — forces conscious processing rather than muscle memory. Probably a novelty, but interesting.

Weighted

After a round, the app identifies your weakest keys (highest error rate or slowest reaction time) and generates the next round’s text emphasizing those characters. Targeted weakness training — makes the tool genuinely adaptive rather than just presenting fixed content.

Rhythm

A metronome or visual pulse sets the pace. You must type one character per beat. Trains consistent cadence rather than raw speed. Useful because inconsistent rhythm (fast bursts followed by pauses) is a common typing flaw even among fast typists.

No Backspace

Like Forward, but Backspace is explicitly disabled and errors are permanent. Forces you to commit and move forward — trains confidence and discourages the habit of second-guessing every keystroke.

Endurance / Challenge Modes

Marathon

An endless stream of text. No defined end — just tracks how long you can sustain a target WPM/accuracy before fatigue sets in. Good for stamina training and for observing how performance degrades over time.

Survival

Combines Countdown + Sudden Death: you have a timer, and each correct word adds time to the clock. One mistake ends the run. How long can you survive? Gamifies the session in a way that rewards both speed and accuracy simultaneously.

Zen

No timer, no error tracking, no score. Just type. For warming up or practicing without pressure. The anti-mode — a deliberate counterweight to Sudden Death.

Priority

If only a few of these are implemented, the highest-impact additions would be:

  1. Countdown — it’s the expected default in most typing trainers and would make rstype feel familiar to users coming from the web.
  2. Weighted — turns rstype into an adaptive trainer rather than a fixed content player. Biggest step up in actual pedagogical value.
  3. Zen — a cheap-to-implement complement to the high-pressure modes, and useful as a warm-up mode before a “real” session.

History Recording Design

Overview

Every completed training session is appended as a single JSON line to a log file. This allows post-hoc analysis of typing speed, accuracy trends, and per-key performance without any in-app reporting UI.


File location

~/.local/share/rstype/history.jsonl

This follows the XDG Base Directory Specification:

  • ~/.config/rstype.toml — configuration (settings the user edits)
  • ~/.local/share/rstype/history.jsonl — application data (generated by the app)

History is data accumulated by the app, not something the user configures, so ~/.local/share is the correct location by that convention.

Why ~/.local/share/rstype/? This follows the XDG Base Directory Specification for user-specific application data on Linux. It keeps training data separate from configuration (~/.config/rstype.toml) and out of the home directory root.


File format: JSONL

One JSON object per line, appended on every session completion.

Why JSONL over SQLite? SQLite would enable richer in-process queries but adds a native dependency and significantly more complexity. JSONL is append-only, requires no schema migrations, is readable with any text tool (cat, grep, jq), and can be imported into any analysis tool (Python, R, DuckDB, etc.) trivially.

Why JSONL over plain CSV? The keystrokes field is a variable-length array. CSV cannot represent nested structures cleanly without quoting hacks or splitting into multiple files.


Record structure

{
  "timestamp": "2026-04-04T15:08:00Z",
  "text": "The quick brown fox jumps over the lazy dog",
  "mode": "forward",
  "wpm": 65.3,
  "errors": 2,
  "keystrokes": [
    {"typed": "T", "offset_ms": 0},
    {"typed": "h", "offset_ms": 312},
    {"typed": "Backspace", "offset_ms": 850},
    {"typed": "h", "offset_ms": 1103}
  ]
}

Fields

FieldTypeDescription
timestampstringISO 8601 UTC timestamp of when the session completed
textstringThe target text that was trained on
modestringTyping mode: "forward" or "stop"
wpmnumberWords per minute (chars / 5 / elapsed minutes)
errorsnumberTotal wrong keypresses during the session
keystrokesarrayOrdered list of every key pressed, from first to last

Keystroke fields

FieldTypeDescription
typedstringThe key that was pressed, in W3C format (see below)
offset_msnumberMilliseconds since the first keypress of the session

Why record every keypress (not just correct ones)? Wrong keypresses, backspaces, and hesitations are precisely where skill gaps live. Recording only correct keys would discard the most valuable training signal.

Why no expected field per keystroke? It is redundant. The target text is stored in the text field, and the position of each correct keystroke in the sequence can be derived from it. Storing expected would bloat the log for no additional information.


Key name standard: W3C KeyboardEvent key values

Key names follow the W3C UI Events KeyboardEvent key Values specification.

Examples:

KeyStored as
Letter a"a"
Letter A (shifted)"A"
Space" " (literal space character)
Backspace"Backspace"
Enter"Enter"
CapsLock"CapsLock"
Left arrow"ArrowLeft"
Escape"Escape"

Why W3C key values over USB HID keycodes (numbers)? USB HID codes are more compact (1–2 digits vs. 9 characters for "Backspace") but the size difference is negligible (~2 bytes per keystroke over a 43-character exercise). W3C key strings are self-documenting, require no lookup table to interpret, and are the closest thing to a universal cross-platform string standard for key names.

CI/CD & Deployment

This project uses a modern, streamlined GitHub Actions workflow for both documentation deployment and binary releases.

Documentation Deployment

The documentation is built using mdBook and deployed directly to GitHub Pages without the need for a separate gh-pages branch.

Key Features of the Workflow

  • Stateless Deployment: The site is deployed from a temporary build artifact using the actions/deploy-pages action.
  • Root Configuration: book.toml resides in the project root for simplicity.
  • Direct Source Paths: Source files are located in docs/, and the output is generated in _site/ (which is ignored by Git).
  • Automated Builds: Any push to the master branch triggers a re-build and re-deployment of the documentation.

Workflow File

The configuration is defined in .github/workflows/docs.yml.


Binary Releases

Releases are triggered by pushing a version tag (e.g., v0.2.1).

Release Strategy

  • Platform Support: The workflow currently builds for:
    • Linux (x86_64, aarch64)
    • macOS (x86_64, aarch64)
  • Automated Assets: Binaries are automatically renamed with platform suffixes and attached to the GitHub Release.
  • Notes Generation: Release notes are automatically generated based on commit history.

Workflow File

The configuration is defined in .github/workflows/release.yml.


Versioning

This project uses cargo-release for version management.

# Example: Bump patch version and push tag
cargo release patch --execute

The release.toml file in the root directory contains the configuration for cargo-release, ensuring consistent tag formats and signing.