Teleprompter-style continuous scrolling toggled from the View menu
(Shift+A), available only in scrolled mode. A PacedScroller drives
whole-pixel forward steps at a constant, user-adjustable velocity;
the speed (25-500 percent, persisted as autoScrollSpeed) is tuned
from a floating control pill that also offers pause/resume and exit,
and fades away while scrolling to keep the mode immersive.
Tapping the page pauses and resumes instead of turning pages or
toggling the bars; manual wheel or drag input simply composes with
the paced scrolling. Escape or leaving scrolled mode ends the
session. When forward progress stalls the session hops to the next
section (single-section scroll mode) or stops with a toast at the
end of the book. Vertical-writing books scroll along the horizontal
axis with the sign convention foliate uses for scrolled offsets.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a Contrast stepper to the reader View menu for fixed-layout
(PDF/CBZ) documents. It increases and decreases page contrast via a
CSS filter on the rendered page images, applies to the whole book,
and is stored per-book (local to the current document).
The filter is built in applyFixedlayoutStyles by combining any
dark-mode invert with the contrast amount into a single filter
declaration. Persisted with skipGlobal so it never touches global
view settings, and added to FoliateViewer's effect dependencies so
the change re-applies across all rendered pages.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- #4478: add a configurable pre-start countdown (Off / 1s / 2s / 3s, default
3s) that now ticks at honest one-second intervals and applies to start,
resume, and page loads; Off starts instantly.
- #4476: add manual next/previous word controls (buttons flanking Play plus the
"," / "." keys) that pause playback and step exactly one word.
- #4475: allow selecting text in the context panel to look it up in the
dictionary (anchored popup on desktop, bottom sheet on small screens),
reusing the reader's dictionary view; auto-scroll/seek are suppressed during
selection and an outside click dismisses the popup.
- #4473: add a Speed Reading keyboard shortcut (Shift+V), shown on the View
menu item; ignore repeat triggers while a session is active.
Adds i18n strings for the new UI across all locales.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- ensureSharedBookLocal helper makes sure the local library has both the
Book entry and the bytes on disk after /import succeeds; navigating
into the reader before this lands on "Book not found"
- ShareLanding navigates via navigateToReader (path form on web) so the
reader actually renders instead of hitting the App Router stub and
going blank
- Loading + progress UI on the landing page while bytes stream in;
Open-in-app disabled mid-import to avoid races
- UserInfo header: vertically center avatar with name/email, tighter
mobile gap, and a fillContainer prop on UserAvatar so a parent can
size the box via classes without the inline style fighting back
- Rename "Share current page" -> "Share reading progress" (and matching
post-generation hint) and shrink the dialog from 480 to 460px
- Drop the unused Reload Page menu item from SettingsMenu
- Translate the two new i18n keys across 31 locales
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Direct file download from the public share landing carries rights /
abuse risk. Replace the Download button with the Open-in-app deep link
in both the logged-in flow (now: Add to library + Open in app) and the
anonymous flow (now: Open in app + Get Readest footnote).
The /api/share/[token]/download route is left intact so re-enabling
the button later is a one-file UI change.
* feat: add RSVP speed reading feature
Implements Rapid Serial Visual Presentation (RSVP) speed reading mode:
- Display words one at a time with ORP (Optimal Recognition Point) highlighting
- Adjustable WPM speed (100-1000) with keyboard/button controls
- Punctuation pause settings (25-200ms)
- Progress tracking with chapter navigation
- Context panel showing surrounding text when paused
- Keyboard shortcuts (Space, Escape, arrows) and touch gestures
- Chapter selector for quick navigation
- Respects current theme colors
- Persists settings (WPM, pause duration, position) per book
New files:
- services/rsvp/RSVPController.ts - Main controller with playback logic
- services/rsvp/types.ts - TypeScript interfaces
- components/rsvp/RSVPOverlay.tsx - Full-screen RSVP reader UI
- components/rsvp/RSVPControl.tsx - Integration component
- components/rsvp/RSVPStartDialog.tsx - Start position selection
Closes#3111
* test(rsvp): add Playwright e2e tests for RSVP feature
- Set up Playwright test infrastructure with config
- Add comprehensive e2e tests for RSVP speed reading:
- Opening RSVP from View menu
- Start dialog options
- Play/pause toggle
- Speed adjustment
- Skip navigation
- Keyboard shortcuts
- Progress bar
- Chapter navigation
- Accessibility tests
- Add test data attributes and ARIA labels to RSVPOverlay
- Add test scripts to package.json
* refactor: remove test files, unsure of use case for now
* chore: remove Playwright e2e test scripts from package.json
- Deleted e2e test scripts related to Playwright from package.json as they are no longer needed.
- Removed Playwright as a dev dependency to streamline the project.
* chore: sync pnpm-lock.yaml after removing @playwright/test
* fix: lint errors and timezone-aware date formatting
* fix(rsvp): restore correct position when exiting RSVP mode
Fix bug where exiting RSVP after changing speed would navigate to wrong
position (several pages backwards). The issue was that Range objects
become stale if the document re-renders, and the position recovery used
global word index instead of per-document index.
- Add docWordIndex to track word position within each document
- Add docTotalWords to RsvpStopPosition for accurate recovery
- Validate Range before using it, recreate from current DOM if stale
- Use same word extraction logic as RSVPController for consistency
* fix(rsvp): prevent arrow keys from changing chapter dropdown
Arrow keys during RSVP mode were inadvertently navigating the chapter
dropdown instead of controlling RSVP speed. Fixed by using capture phase
for keyboard events and stopping propagation to prevent native elements
from receiving the events.
* chore: remove playwright-mcp screenshots from repo
* chore: update gitignore
* fix(i18n): wrap all RSVP overlay strings with translation function
Restore missing translation wrappers for all user-facing strings:
- Close RSVP button labels and tooltips
- Select Chapter dropdown
- WPM display
- Context panel header
- Ready state text
- Chapter Progress label
- Words count and time remaining
- Reading progress slider
- Pause/punctuation label
- Skip back/forward buttons
- Play/Pause button
- Speed control buttons
* fix(rsvp): use CFI-based position tracking for accurate page positioning
- Add CFI generation for each extracted word during RSVP processing
- Implement CFI path and character offset comparison for precise position matching
- Update startFromCurrentPosition to use CFI matching instead of word index
- Add extractFullDocPathWithOffset to handle CFI character offsets
- Simplify RSVPControl by removing unused helper functions
- Remove word index from RsvpPosition in favor of CFI-only tracking
* fix(ViewMenu): re-enable Speed Reading Mode in production environment
* refactor(ViewMenu, RSVPController): clean up code formatting and improve readability
* refactor(ViewMenu): remove unused IoSpeedometer import
* refactor(RSVPController): streamline CFI handling and improve section comparison
- Removed redundant logic and re-using CFI util functions for CFI operations
* refactor(RsvpPosition): remove legacy wordIndex field for cleaner type definition
* feat: add RSVP speed reading feature
Implements Rapid Serial Visual Presentation (RSVP) speed reading mode:
- Display words one at a time with ORP (Optimal Recognition Point) highlighting
- Adjustable WPM speed (100-1000) with keyboard/button controls
- Punctuation pause settings (25-200ms)
- Progress tracking with chapter navigation
- Context panel showing surrounding text when paused
- Keyboard shortcuts (Space, Escape, arrows) and touch gestures
- Chapter selector for quick navigation
- Respects current theme colors
- Persists settings (WPM, pause duration, position) per book
New files:
- services/rsvp/RSVPController.ts - Main controller with playback logic
- services/rsvp/types.ts - TypeScript interfaces
- components/rsvp/RSVPOverlay.tsx - Full-screen RSVP reader UI
- components/rsvp/RSVPControl.tsx - Integration component
- components/rsvp/RSVPStartDialog.tsx - Start position selection
Closes#3111
* fix(rsvp): use portal to fix overlay stacking context issue
- Render RSVP overlay and start dialog via React Portal to document.body
- This ensures the overlay appears above all other content regardless of
parent component CSS transforms or stacking contexts
- Add fallback colors for theme values to ensure solid background
* fix(rsvp): improve UX with progress sync, sentence highlight, and better dialogs
- Fix start dialog transparency by using solid opaque background with proper
fallback colors for both light and dark modes
- Increase context words from 50 to 100 words before/after current word
- Add progress sync on RSVP exit - navigates reader to the last word position
- Add temporary bright green sentence underline on exit (5 second duration)
to easily locate where reading left off
- Helper function to expand word range to full sentence boundaries
* fix(rsvp): store full BookNote for proper annotation removal
The addAnnotation API requires the full BookNote object (including CFI)
when removing annotations, not just the ID. Changed tempHighlightIdRef
to tempHighlightRef to store the complete BookNote object.
* test(rsvp): add Playwright e2e tests for RSVP feature
- Set up Playwright test infrastructure with config
- Add comprehensive e2e tests for RSVP speed reading:
- Opening RSVP from View menu
- Start dialog options
- Play/pause toggle
- Speed adjustment
- Skip navigation
- Keyboard shortcuts
- Progress bar
- Chapter navigation
- Accessibility tests
- Add test data attributes and ARIA labels to RSVPOverlay
- Add test scripts to package.json
* fix(rsvp): clarify start dialog option labels
Update the RSVP start dialog to use clearer language:
- "From Beginning" → "From Chapter Start" (since it starts from chapter beginning)
- "From Current Position" → "From Current Page" (starts from visible page)
* fix(rsvp): use correct theme colors from themeCode
The RSVP components were using incorrect palette key names (camelCase
like `base100` instead of hyphenated like `base-100`), causing the
fallback colors to always be used instead of the reader's actual theme.
Fix by using themeCode.bg, themeCode.fg, and themeCode.primary directly,
which are already resolved from the palette with correct keys.
* fix(rsvp): use theme accent color for sentence underline and persist until page change
- Change underline color from hardcoded green (#22c55e) to theme accent
color (themeCode.primary), matching the ORP focal point highlight
- Remove 5-second timeout that auto-removed the underline
- Add cleanup on page navigation, new RSVP session start, and unmount
- Add removeRsvpHighlight helper function for consistent cleanup
* fix(rsvp): transition to next chapter when reaching end of section
When RSVP reached the end of a chapter, it would restart the current
chapter instead of moving to the next one. This happened because RSVP
extracts ALL words from the current section via renderer.getContents(),
so when words run out, the entire chapter is done.
- Always use view.renderer.nextSection() when RSVP exhausts words
- This moves to the next chapter instead of staying in the current one
* refactor: remove test files, unsure of use case for now
* chore: remove Playwright e2e test scripts from package.json
- Deleted e2e test scripts related to Playwright from package.json as they are no longer needed.
- Removed Playwright as a dev dependency to streamline the project.
* fix(rsvp): ensure CFI retrieval occurs before navigation
- Updated comments to clarify the necessity of obtaining CFI for both the navigation and sentence highlight before invoking the goTo() method, as it may re-render the document and invalidate Range objects.
- Introduced a new variable for sentence text to enhance readability and maintainability of the code.
* chore: sync pnpm-lock.yaml after removing @playwright/test
* style: format RSVP components
* fix: lint errors and timezone-aware date formatting
* i18n: support CJK text and add translations
---------
Co-authored-by: Huang Xin <chrox.huang@gmail.com>
This option is hard to understand and explain. Most hardcoded color
in dark mode that affects readability has already been fixed in the
reader so there is no necessity to have this option.