FlashReader
Reader that shows a text file one word at a time at a pace you set and remembers where you stopped.
- Released
- Data collected
- None
- Price
- Free
About
FlashReader opens a local .txt file and shows it one word at a time in the middle of the screen, every 500 ms by default. The reader sets the interval, letter size, letter colour and background colour. The whole text and the word position stay on the device, so after a restart the same file reopens at the same word.
This page describes the web version at flashreader.fun: one HTML page with inline JavaScript. The script makes no network requests and has no analytics. The Android app on Google Play is a separate build whose source is not covered here.
The engineering is small and specific: a timer that can change pace without losing the word, storage that survives a restart, and settings that are applied and saved the moment they change.
FlashReader · focused reading
what was solved
Word loop
in the productWhat it givesThe user picks a text file and reads it word by word at an even pace, and can change the speed mid-text without losing their place.
- Problem
- Words must change at an even, user-set interval, and the interval must be changeable in the middle of a text without losing the current word.
- Solution
One interval timer moves an index through a word array. A speed change stops that timer and starts a new one from the same index.
- Stack
Turn a picked text file into a sequence of wordsRead the file as UTF-8 with FileReader and split it on spaces into an array
The file comes from a standard file input limited to .txt, so the page needs no file system access. action_load_file() reads it with readAsText(file, 'UTF-8') and splits the result on single spaces; punctuation stays with its word. The raw text is also handed to saveFileContent() for the next session.
Show one word per tick and never run two timers at onceread() exits if a timer is already running; each tick shows a word, saves the next index
read() refuses to start without loaded text ('Load text file to read!') and returns early when is_going is set, so pressing play twice cannot start a second interval. Each tick writes text[position] into #text-zone and saves position + 1. togglePlayPause() switches between read() and pause() and updates the play button.
A speed change in the middle of reading must apply at onceStop and restart the interval with the new period, keeping the word index
setInterval cannot change its period. updateReadingSpeed() and the speed field's change handler call pause() and then read() when reading is active. The index lives on the reader object, so the restarted timer continues with the next word. A typed value below 1 is reset to the 500 ms default.
End of text: stop cleanly or start overAt the end either stop with 'THE END!' and reset to word 0, or wrap to word 0
The tick checks for an undefined word at the current index. With Loop off it clears the timer, shows 'THE END!', saves position 0 and flips the play button back. With Loop on it sets the index to 0 and keeps going. The Loop choice is saved like the other settings.
Resume after restart
in the productWhat it givesClose the app and come back later: the same text opens at the same word, with the same letter size and speed, all kept on the device.
- Problem
- The whole text, the word position and the display settings must survive closing the page or the app, with no server.
- Solution
The text goes to IndexedDB, the position and settings to localStorage, and both are read back at startup.
- Stack
A whole book does not belong in localStorageStore the raw text in IndexedDB under one fixed key; keep small values in localStorage
saveFileContent() puts the text into the 'files' store of database 'flashreader' (version 2) with id 'flashreader_last_text', so a new file replaces the old one. onupgradeneeded creates the store only if it is missing, so opening over an older version does not fail.
Position, colours, size, speed, loop and the file name stay in localStorage, where reads at startup are synchronous.
Reopen the last file at the word where reading stoppedSave the index on every shown word; at startup reload the text and that index
set_position() writes the index to localStorage (fr_position) on every tick, so a closed or killed app loses at most one word. The constructor reads the index first; on DOMContentLoaded getFileContent() loads the text from IndexedDB, splits it again and shows 'The last file, <name>, has been loaded' with a prompt to press play.
Stored values can be missing or brokenRestore each value on its own with fallbacks: position 0, size 48 px, speed 500 ms
Each key is read and applied separately, so one bad value does not block the rest. A non-numeric position becomes 0, a font size that parses to 0 falls back to 48 px, a speed that parses to 0 falls back to 500 ms. Colours are saved without '#' and restored with it, then applied to the text and the page background.
Display and controls
in the productWhat it givesLetter size and colours change while reading, keyboard shortcuts control playback in a browser, and the reader can step back ten words or jump to any word.
- Problem
- Letter size and colours must change while reading, and in a desktop browser playback should be controllable from the keyboard.
- Solution
Toolbar fields apply and save each change at once; in the browser, keyboard shortcuts call the same reader methods.
- Stack
Letter size and colours must apply at once and persistChange handlers set the style directly and save the value; size below 8 px becomes 8
The font colour handler sets the text colour of #text-zone, the background handler sets the body background, and the size handler sets font-size in px with a floor of 8. Each handler writes its value to localStorage in the same step, so there is no separate save action.
In the browser, keyboard control must not scroll the page while readingSpace, F, Up and Down call reader actions and cancel the browser default
In the browser version, Space toggles play and pause, F toggles full screen, Up makes words faster by 10 ms with a 50 ms floor, Down slower by 10 ms. preventDefault() stops the browser from scrolling or pressing a focused control. Speed changes go through updateReadingSpeed(), so a running timer restarts at the new pace.
The reader missed a few words and wants to go backLeft arrow (browser) steps back 10 words, clamped at 0; the position field jumps to any word
skipBackwards() moves the index back by 10, never below 0, shows that word at once and saves the position. The position field in the toolbar accepts any word number; negative values become 0.
Full screen works differently across browsers and app shellsTry standard and prefixed Fullscreen APIs, then a Cordova Fullscreen plugin if the page finds one
enterFullscreen() and exitFullscreen() walk through the standard, moz, webkit and ms variants. When a global Fullscreen object exists, as with a Cordova full-screen plugin, Fullscreen.show() is called too. The button and the F key share the same check of all four fullscreenElement variants.
Numbers
from the product- Default pace 500 ms per word 120 words per minute.
- Fastest pace 50 ms per word Up to 1,200 words per minute from the keyboard.
- Speed step 10 ms Up and Down arrow keys.