First release

This commit is contained in:
Roni Laukkarinen
2026-02-01 16:17:41 +02:00
commit f3a297dd9a
10 changed files with 3329 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
# Dependencies
node_modules/
# Build output
dist/
# Environment files
.env
.env.local
.env.*.local
.claude
# Editor directories and files
.idea/
.vscode/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
npm-debug.log*
# Local config
*.local
+24
View File
@@ -0,0 +1,24 @@
## Commits and code style
- 2 space indents
- Always commit build and asset files
- One logical change per commit
- Keep commit messages concise (one line), use sentence case
- Update CHANGELOG.md after each change
- Use present tense in commits and CHANGELOG.md
- Use sentence case for headings (not Title Case)
- Never use bold text as headings, use proper heading levels instead
- Always add an empty line after headings
- No formatting in CHANGELOG.md except `inline code` and when absolute necessary
- Use `*` as bullets in CHANGELOG.md
- Never use Claude watermark in commits (FORBIDDEN: "Co-Authored-By")
- No emojis in commits or code
- Keep CHANGELOG.md date up to date when adding entries
## Claude Code workflow
- Always add tasks to the Claude Code to-do list and keep it up to date. Show todo list to user.
- Review your to-do list and prioritize before starting.
- If new tasks come in, don't jump to them right away—add them to the list in order of urgency and finish your current work first. Use FIFO (First in First out) in order.
- Do not ever guess features, always proof them via looking up official docs, GitHub code, issues, if possible.
- When looking things up, do not use years in search terms like 2024 or 2025.
+89
View File
@@ -0,0 +1,89 @@
# Speed reader
A web-based speed reading tool using Rapid Serial Visual Presentation (RSVP) with Optimal Recognition Point (ORP) alignment.
## What is RSVP?
RSVP (Rapid Serial Visual Presentation) is a reading technique that displays text one word at a time at a fixed focal point. This eliminates saccades (eye movements) that normally slow down reading, allowing for significantly faster reading speeds.
## The science behind it
### Optimal Recognition Point (ORP)
When reading normally, your eyes don't land at the center of words. Research shows that fixations tend to occur slightly left of center, at what's called the Optimal Viewing Position (OVP) or Optimal Recognition Point (ORP). This position allows for fastest word recognition.
The ORP position follows the Spritz algorithm:
- 1 character: 1st letter
- 2-5 characters: 2nd letter
- 6-9 characters: 3rd letter
- 10-13 characters: 4th letter
- 14+ characters: 5th letter
### Fixed focal point
Traditional RSVP displays center each word, requiring small eye adjustments. This implementation aligns each word's ORP at the exact same screen position, so the highlighted letter never moves. Your eyes stay completely still while words flow around the focal point.
### Variable timing
The display time for each word is adjusted based on:
- Word length (longer words get more time)
- Punctuation (sentence-ending punctuation triggers a longer pause)
This mimics natural reading rhythm where comprehension requires variable processing time.
### Research findings
Studies have shown that RSVP reading can achieve speeds of 500+ words per minute, though comprehension tends to decrease above 350-400 WPM for complex texts. The technique works best for:
- Light reading and familiar content
- Skimming and preview reading
- Building reading speed gradually
Note: Extended RSVP reading can cause visual fatigue. Take breaks.
## Features
- Adjustable reading speed (50-1500 WPM)
- ORP highlighting with fixed focal point (Spritz algorithm)
- Variable word timing based on length and punctuation
- EPUB and TXT file support
- Progress tracking with position memory per text
- Keyboard shortcuts
- Adjustable side opacity
- Dark theme optimized for reading
- Settings persisted to localStorage
## Running locally
```bash
npm install
npm run dev
```
Then open http://localhost:5173
## Building for production
```bash
npm run build
```
Output will be in the `dist` folder.
## Inspiration and similar projects
- [Original RSVP Speed Reader](https://snowfluke.github.io/rsvp-speed-reader/)
- [Spritz](https://spritz.com/) - The commercial product that popularized ORP-based RSVP
- [OpenSpritz](https://github.com/Miserlou/OpenSpritz) - Open source Spritz implementation
- [speedread](https://github.com/pasky/speedread) - Terminal-based Spritz-alike in Perl
- [rsvp-reading](https://github.com/thomaskolmans/rsvp-reading) - Svelte-based RSVP reader with PDF/EPUB support
- [LetoReader](https://github.com/Axym-Labs/LetoReader) - Self-hostable speed reader with chunking and highlighting
- [tspreed](https://github.com/n-ivkovic/tspreed) - Terminal RSVP reader in POSIX shell
## Scientific references
- Masson, M. E. J. (1983). Conceptual processing of text during skimming and rapid sequential reading. _Memory & Cognition_, 11(3), 262-274.
- Rayner, K., Schotter, E. R., Masson, M. E., Potter, M. C., & Treiman, R. (2016). So much to read, so little time: How do we read, and can speed reading help? _Psychological Science in the Public Interest_, 17(1), 4-34.
- Benedetto, S., Carbone, A., Pedrotti, M., Le Fevre, K., Bey, L. A. Y., & Baccino, T. (2015). Rapid serial visual presentation in reading: The case of Spritz. _Computers in Human Behavior_, 45, 352-358.
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>RSVP Speed Reader</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
+1883
View File
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
{
"name": "rsvp-speed-reader",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"jszip": "^3.10.1",
"lucide-react": "^0.460.0",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.3.4",
"vite": "^6.0.0"
}
}
+1203
View File
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Inter", sans-serif;
background-color: #0a0a0a;
color: #ffffff;
min-height: 100vh;
overflow-x: hidden;
}
.mono {
font-family: "JetBrains Mono", monospace;
}
#root {
min-height: 100vh;
}
textarea:focus,
button:focus {
outline: none;
}
button {
background-color: transparent;
}
button:focus,
button:focus-visible,
button:active {
outline: none;
background-color: transparent;
}
.icon-btn:hover {
color: #ccc !important;
}
.wpm-control:hover .wpm-value {
color: #fff !important;
}
.wpm-btn:hover {
color: #ccc !important;
}
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
+6
View File
@@ -0,0 +1,6 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})