Personal Project · Design + Engineering

Keystroke

Solo · 2026 · Vanilla JavaScript, Web Audio API, CSS

Live demo ↗
Keystroke interface

Context

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.

Concept

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.

Technical decisions

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.

What I’d do differently

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.

Outcome

A working tool I actually use. Live at github.com/lemur-cpu/Keystroke.