ttytype
A keyboard-first terminal typing test built with Textual. It supports word-count, timed, public-domain quote, and private custom-text tests without accounts, telemetry, or network access.
Features
- Live raw and net WPM, accuracy, time, progress, and error feedback.
- Word, timed, quote, and custom-text modes.
- Dark and light variants with redundant non-color character-state cues.
- Responsive layouts and a guarded small-terminal fallback.
- Optional local SQLite history, recent results, and personal bests.
- Linux, macOS, and Windows support through Textual and Platformdirs.
Installation
ttytype requires Python 3.14 or newer. PyPI publication is deferred for the initial release; install the tagged source with either tool:
uv tool install "ttytype @ git+https://github.com/jakeryderv/ttytype.git@v0.1.0"
# or
pipx install "ttytype @ git+https://github.com/jakeryderv/ttytype.git@v0.1.0"
Run the installed command:
ttytype
# Equivalent module entry point:
python -m ttytype
For a source checkout:
git clone https://github.com/jakeryderv/ttytype.git
cd ttytype
uv sync --locked
uv run ttytype
Controls
| Context | Key | Action |
|---|---|---|
| Everywhere | Ctrl+Q | Quit |
| Everywhere | Ctrl+T | Toggle light/dark theme |
| Home | Tab / Shift+Tab | Move focus |
| Home | Enter | Open a selection or press a button |
| Typing | Printable keys | Type the target text |
| Typing | Backspace | Remove the final typed character |
| Typing | Tab | Retry the exact target |
| Typing | Escape | Return Home |
| Results | R | Retry the exact target |
| Results | N | Generate new text with the same configuration |
| Results | H | Return Home |
| Results | Q | Quit |
Test modes
- Words: 10, 25, 50, or 100 lowercase common words.
- Timed: 15, 30, 60, or 120 seconds. Timing starts on the first printable character and ends from the monotonic clock; input at the exact deadline is rejected. More local words are generated before the visible buffer runs out.
- Quote: short, medium, or long public-domain excerpts with capitalization, punctuation, author, and work attribution preserved.
- Custom text: paste or enter plain text in the TUI. Multiline and repeated whitespace are normalized to spaces for a single terminal-friendly target. File loading is deferred; no custom text is persisted.
Scoring
- Raw WPM: all printable character keystrokes divided into standard five-character words per minute.
- Net WPM: currently correct target positions divided into five-character words per minute.
- Accuracy: correct printable keystrokes divided by all printable keystrokes. Backspace is excluded, so a corrected mistake still affects accuracy.
- Errors: incorrect character attempts remain in the total; corrected and currently uncorrected errors are reported separately.
Timing starts on the first printable character using a monotonic nanosecond clock and remains independent from the UI refresh rate.
Local history and privacy
ttytype is local-only:
- There are no accounts, network requests, synchronization, telemetry, or analytics.
- Completed sessions are saved only when Save completed tests locally is enabled.
- Home can disable future history and permanently clear existing history after confirmation.
- History stores score metadata and chart samples. It does not store target text, typed text, custom text, or individual keystrokes.
- WPM chart samples use compact JSON arrays with the shape
[elapsed_ms, raw_wpm, net_wpm, accuracy].
The SQLite database is created lazily when the application first accesses local preferences or history.
Storage locations
Paths are selected with platformdirs.user_data_path("ttytype"):
| Platform | Default database path |
|---|---|
| Linux | $XDG_DATA_HOME/ttytype/ttytype.sqlite3, normally ~/.local/share/ttytype/ttytype.sqlite3 |
| macOS | ~/Library/Application Support/ttytype/ttytype.sqlite3 |
| Windows | %LOCALAPPDATA%\ttytype\ttytype\ttytype.sqlite3 |
Environment and operating-system configuration may change these locations.
Mutable preferences and history share this database. ttytype does not currently
write a TOML configuration file. A future configuration directory is reserved
through platformdirs.user_config_path("ttytype").
Configuration and CLI
Defaults are 25 words, local history enabled, and the dark theme. Home edits mode-specific word count, duration, quote length, and history behavior. Ctrl+T changes the stored theme preference. Custom text itself is never persisted.
Configuration precedence, from lowest to highest, is:
- application defaults;
- stored SQLite preferences;
- explicit command-line overrides;
- choices made in the running TUI, which are persisted for later launches.
ttytype [--words COUNT] [--history | --no-history] [--theme dark|light]
--words opens Home in word mode at the requested count. History and theme
options override stored preferences for the running application.
Supported systems and terminals
CI runs the full Python 3.14 quality suite on current Ubuntu, macOS, and Windows GitHub-hosted runners. ttytype expects an interactive terminal with Unicode and ANSI color support. True color improves appearance but is not required because character states also use bold, reverse, underline, and dim styles.
The typing view requires at least 50 columns by 12 rows. Larger terminals receive narrow, normal, or wide responsive layouts. Common modern terminals such as Windows Terminal, iTerm2, Terminal.app, GNOME Terminal, Konsole, and Kitty should work through Textual; terminal-specific rendering differences may remain.
Textual cutover
The original curses interface and its compatibility modules have been removed. These differences are intentional:
- ttytype opens on Home rather than immediately starting a test;
- Escape returns Home, while Ctrl+Q quits globally;
- Tab retries the exact target and Results offers separate retry and new-text actions;
- scoring uses event-based raw WPM, net WPM, accuracy, and corrected errors;
--wordsconfigures Home instead of bypassing it.
Development
Install the locked development environment:
uv sync --locked --all-extras --dev
Run the complete local quality gate:
uv run ruff check .
uv run ruff format --check .
uv run mypy src tests
PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run pytest
uv build
GitHub Actions runs these checks on Linux, macOS, and Windows and uploads wheel and source-distribution artifacts. Version tags build separate release artifacts; PyPI publishing is intentionally not configured yet.
Project policy
Release notes are maintained in CHANGELOG.md. A separate contribution guide is deferred until the project receives external contribution workflow requirements. Standalone binaries are also deferred; the initial release is distributed as Python source and wheel artifacts.
License
Released under the MIT License.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ttytype-0.1.0.tar.gz.
File metadata
- Download URL: ttytype-0.1.0.tar.gz
- Upload date:
- Size: 27.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
416ad84743811ea72f808f83b4853a7be584f4c346dde6ff5ce98267ef657dd6
|
|
| MD5 |
c070de0bddb19a3eb353f84a8bf57a60
|
|
| BLAKE2b-256 |
70da77d324bf36a98fcc9226f70bf205b733763cb41e2f8075a23d091283e0d1
|
Provenance
The following attestation bundles were made for ttytype-0.1.0.tar.gz:
Publisher:
release.yml on jakeryderv/ttytype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ttytype-0.1.0.tar.gz -
Subject digest:
416ad84743811ea72f808f83b4853a7be584f4c346dde6ff5ce98267ef657dd6 - Sigstore transparency entry: 2554529023
- Sigstore integration time:
-
Permalink:
jakeryderv/ttytype@56a5036c8e27c6197b4fb5fc3115e98ebba70f33 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jakeryderv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@56a5036c8e27c6197b4fb5fc3115e98ebba70f33 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ttytype-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ttytype-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eab22af29c1f9d5ea3fac1e71c233e81555dfa1cc4a9baf5a027cddbb965fa1e
|
|
| MD5 |
3b12e7058a02d0b702b4bf873e8f3604
|
|
| BLAKE2b-256 |
96795f6a8320e99546b7816afe61d2aee46dea4a685efe11f587e27805c46bae
|
Provenance
The following attestation bundles were made for ttytype-0.1.0-py3-none-any.whl:
Publisher:
release.yml on jakeryderv/ttytype
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ttytype-0.1.0-py3-none-any.whl -
Subject digest:
eab22af29c1f9d5ea3fac1e71c233e81555dfa1cc4a9baf5a027cddbb965fa1e - Sigstore transparency entry: 2554529441
- Sigstore integration time:
-
Permalink:
jakeryderv/ttytype@56a5036c8e27c6197b4fb5fc3115e98ebba70f33 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jakeryderv
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@56a5036c8e27c6197b4fb5fc3115e98ebba70f33 -
Trigger Event:
workflow_dispatch
-
Statement type: