rsvpreader
A Spritz-style rapid serial visual presentation reader for plain-text books. It shows one chunk of one to three words at a time with a fixed pivot letter pinned to the center of the screen, or one full sentence at a time, and remembers where you stopped in every book.
Install and run
Requires Python 3.10 or newer with Tk.
On macOS, Homebrew's Python ships without Tk; uv installs a Python that has it.
From PyPI:
uv tool install rsvpreader # or: pipx install rsvpreader, pip install rsvpreader
rsvpreader # fullscreen, reads ./book
rsvpreader --windowed # normal window
rsvpreader ~/Books # a different book folder
From a checkout:
uv sync
uv run rsvpreader --windowed
python rsvpreader.py works as a launcher from a checkout without installing.
Put .txt files, in any folder structure, under book/ next to where you run the command, or point RSVPREADER_BOOK_ROOT or the positional argument at another folder.
Controls
| Where | Input | Action |
|---|---|---|
| Browser | Click, Enter, Space, Right | Open folder or book |
| Browser | Up, Down | Move selection |
| Browser | Backspace, Left | Back one folder |
| Reader | Click, Right, Space | Next chunk or sentence |
| Reader | Secondary click, Left | Previous chunk or sentence |
| Reader | Hold click 2 s | Autoplay while held, ramping up to the max WPM over 5 s |
| Reader | p | Toggle autoplay (same ramp) |
| Reader | Up, Down | Max WPM plus or minus 10 |
| Reader | Home, End | First or last unit |
| Reader | Hold secondary click 3 s | Open settings |
| Anywhere | s or the gear icon | Toggle settings |
| Anywhere | Esc | Close settings, else back one level, else leave fullscreen |
| Anywhere | q | Quit |
Autoplay speed is true words per minute: a three-word chunk is shown three times as long as a single word, and a sentence for as long as its word count implies.
Settings
Chunk size (1, 2 or 3 words), max autoplay WPM, font family and size, brightness, text color (native color picker) and sentence mode.
Changes apply live, rebuild the current book without losing your place, and persist to settings.json in the user config directory:
| Platform | Location |
|---|---|
| macOS | ~/Library/Application Support/rsvpreader/ |
| Linux | $XDG_CONFIG_HOME/rsvpreader/ or ~/.config/rsvpreader/ |
| Windows | %APPDATA%\rsvpreader\ |
Override with --config-dir or RSVPREADER_CONFIG_DIR.
On first run, settings and reading positions are imported from the directory the 1.0.x releases used (RSVP_READER_CONFIG_DIR if set, otherwise rsvp-reader in the same locations), then from a legacy rsvp_settings.json in the working directory.
Reading positions live in progress.json in the same directory, keyed by the book's absolute path.
How text is chunked
- Regular punctuation (comma, semicolon, colon, apostrophe, dashes) attaches to its word and never forces a break.
- A sentence terminator (
.!?) closes the chunk on the word carrying it. - An opening double quote (straight or curly) closes the previous chunk, so the quoted word starts a new one.
- A closing double quote closes the chunk on the word carrying it.
Text pasted without spaces is repaired first: forth,The becomes forth, The and it."Believe becomes it. "Believe, while 0.99365, 1,000, e.g. and 7.25p.m. stay intact.
Straight double quotes alternate open and close by parity.
A token with no letters or digits, such as a spaced en dash, glues to the previous word so it never occupies a chunk of its own.
The pivot word is the middle word of a three-word chunk, the word with more letters in a two-word chunk (tie goes to the first), or the only word.
The pivot letter is the middle letter counting letters only, rounding left for an even count (Bull highlights u); a word with no letters falls back to its digits.
To inspect the units for any file without opening the GUI:
uv run rsvpreader --dump-chunks "book/selfhelp/some book.txt" --chunk-size 3
uv run rsvpreader --dump-chunks "book/selfhelp/some book.txt" --sentences
Development
uv sync
uv run pytest # unit tests plus Tk smoke tests (skipped without a display)
uv run ruff check src tests
uv run ruff format src tests
uv build # sdist and wheel under dist/
CI runs lint and tests on Linux, macOS and Windows for every push and pull request, and builds the wheel on Linux.
Releasing
The package version lives only in __version__ in src/rsvpreader/__init__.py.
To release: bump it, merge, then publish a GitHub release whose tag is v<version> (for example v1.0.1).
The publish workflow builds the distributions, checks that the tag matches the version, and uploads to PyPI through trusted publishing; no API token is stored anywhere.
Layout under src/rsvpreader/:
| Module | Role |
|---|---|
text.py |
Normalization, tokenization, chunk and sentence building, file decoding |
pivot.py |
Pivot word and letter selection |
session.py |
Reading cursor over units; position survives mode and chunk-size changes |
autoplay.py |
WPM ramp and due-time logic driven by an external clock |
layout.py |
Pivot box and flow-text geometry |
settings.py, progress.py, storage.py, paths.py, colors.py |
Validated settings, per-book resume, atomic JSON, config locations, hex color helpers |
library.py |
Folder listing |
app.py, browser_view.py, reader_view.py, settings_panel.py, theme.py |
Tk shell and views |
cli.py |
Argument parsing and entry point |
Everything outside the Tk modules is pure and unit tested; the Tk smoke tests drive a real window and assert the rendered pivot geometry from Tk's own bounding boxes.
Metadata
Release files for rsvpreader 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rsvpreader-1.1.0.tar.gz | 30.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rsvpreader-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.3 kB
Release files / rsvpreader-1.1.0.tar.gz
| Download URL | rsvpreader-1.1.0.tar.gz |
|---|---|
| Size | 30.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a42c57aa8f107dc9318f907a97fe8163164b21821a6ae90942f6e1cff530a63e
|
|
BLAKE2b-256 checksum How to use checksums |
d7f45518738534e3bab2a7648708a39b65f754eb254dafa31e27aeb597a3da84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / rsvpreader-1.1.0-py3-none-any.whl
| Download URL | rsvpreader-1.1.0-py3-none-any.whl |
|---|---|
| Size | 29.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2f19d815d1933fc8488258ce0c4a37a056a4b8dec4759a706e65ae3930b46289
|
|
BLAKE2b-256 checksum How to use checksums |
f17e47a4ed28da70863852a33f5646a48fe0f3339db421e04396d9b555483dc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|