Personal Project · Design + Engineering

I started writing seriously in 2020 and have used everything from Google Docs to Ulysses to actual paper. The problem with most tools is that they make it too easy to go back. You edit the sentence you just wrote instead of writing the next one. Keystroke is my answer to that problem.
The UI is a vintage typewriter. Every constraint of a real typewriter is a deliberate feature: backspace is disabled in Flow and Purge modes, the paper runs out at 300 words per sheet, keys make sound via Web Audio API, and a carriage indicator moves as you type.
I kept the architecture flat: one JS file per concern, no build step, no bundler. The trickiest part was the carriage indicator — it reads actual rendered character widths from a hidden element after fonts load, so the position tracks real pixels rather than estimates. Sound comes from the Web Audio API on each keypress rather than audio files, which keeps the bundle at zero. Session replay works by logging each character with a timestamp, then playing them back at the same intervals.
The CSS architecture grew messier than I’d like. I’d introduce a stricter naming convention earlier. The localStorage persistence model also needs a migration strategy before I add new data shapes.
A working tool I actually use. Live at github.com/lemur-cpu/Keystroke.