Initial build: typo, a typing test built from your own code
No backend, no build step -- static HTML/CSS/JS, themed identically to
flit/wisp (same CSS vars, same "> " title prefix, same dark/mono/green
aesthetic). Snippets are real, shipped code pulled from six repos in
this family (flit, wisp, keep, stash, delve-term, goonk) rather than
generic pangrams.
Stats: WPM = (correct chars / 5) / minutes elapsed, timing from first
keystroke not page load. Accuracy = correct keystrokes / total
keystrokes tracked at the keydown level (comparing the pressed key
against the exact next expected character before it's inserted), so
backspaced-over mistakes still count against it rather than only
diffing the final text. Keys/sec updates live via a 200ms tick.
Tabs in source are rendered as two spaces so players never need to
press Tab -- sidesteps a browser default-Tab-moves-focus fight
entirely rather than fighting it with preventDefault.
Verified via simulated typing sessions (puppeteer), not just static
review -- both an artificially fast pass (confirms the math is
internally consistent: 308 correct/310 total keystrokes -> 99%,
matches displayed) and a realistic ~60wpm-paced pass (confirms no
unit-conversion bug that only a slow, deliberate typist would hit
tests-at-lightspeed wouldn't surface). That process caught two real
bugs before they'd have hit a real player:
1. A stray `tabindex="0"` on the code display let the browser's
native click-to-focus behavior steal focus away from the hidden
textarea before our own focus() call ran -- typing silently did
nothing. Fixed by removing the tabindex and switching to a
mousedown+preventDefault handler instead of click.
2. The help modal's CSS set `display: flex` unconditionally, which
(author CSS always beats the UA stylesheet) overrode the `hidden`
attribute's default `display: none` -- the modal was invisibly
covering the entire viewport and intercepting every click, at all
times, whether or not it had been opened. Fixed with an explicit
`.modal-overlay:not([hidden])` rule.
Also verified the actual Docker image builds and serves correctly
(nginx, no build stage needed since there's nothing to compile).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 14:12:44 +02:00
|
|
|
# typo
|
|
|
|
|
|
|
|
|
|
A typing test built from your own code. Every snippet is real, shipped
|
|
|
|
|
code pulled from real repos — flit, wisp, keep, stash, delve-term, goonk
|
|
|
|
|
itself — not generic pangrams or Lorem Ipsum.
|
|
|
|
|
|
|
|
|
|
No backend, no build step — plain HTML/CSS/JS served statically, with
|
|
|
|
|
snippets baked into `snippets.json`.
|
|
|
|
|
|
|
|
|
|
## Stats
|
|
|
|
|
|
|
|
|
|
- **WPM** — (correct characters / 5) / minutes elapsed, the standard
|
|
|
|
|
typing-test formula. Timing starts on the first keystroke, not page load.
|
|
|
|
|
- **Accuracy** — correct keystrokes / total keystrokes, including ones you
|
|
|
|
|
backspaced over. Tracked at the keydown level (comparing the pressed key
|
|
|
|
|
against the exact next expected character), not just diffed after the
|
|
|
|
|
fact.
|
|
|
|
|
- **Keys/sec** — total keystrokes / elapsed seconds, live.
|
|
|
|
|
|
|
|
|
|
Mistakes are highlighted in place rather than blocking progress — you can
|
|
|
|
|
backspace to fix them or keep going, same as most real typing tests.
|
|
|
|
|
Tabs in the original source are shown as two spaces so you never need to
|
|
|
|
|
press Tab.
|
|
|
|
|
|
|
|
|
|
## Adding snippets
|
|
|
|
|
|
|
|
|
|
Edit `snippets.json` — each entry is `{ repo, file, lang, code }`. Keep
|
|
|
|
|
snippets short (10-20 lines), self-contained, and free of exotic
|
|
|
|
|
Unicode in comments (em dashes etc. are typeable but annoying) if you
|
|
|
|
|
want them pleasant to type.
|
|
|
|
|
|
|
|
|
|
## Local development
|
|
|
|
|
|
2026-07-15 14:33:54 +02:00
|
|
|
Run with npm:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npm install
|
|
|
|
|
npm run dev
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This serves the app on `http://localhost:8850`.
|
|
|
|
|
|
|
|
|
|
Any static file server still works, e.g.:
|
Initial build: typo, a typing test built from your own code
No backend, no build step -- static HTML/CSS/JS, themed identically to
flit/wisp (same CSS vars, same "> " title prefix, same dark/mono/green
aesthetic). Snippets are real, shipped code pulled from six repos in
this family (flit, wisp, keep, stash, delve-term, goonk) rather than
generic pangrams.
Stats: WPM = (correct chars / 5) / minutes elapsed, timing from first
keystroke not page load. Accuracy = correct keystrokes / total
keystrokes tracked at the keydown level (comparing the pressed key
against the exact next expected character before it's inserted), so
backspaced-over mistakes still count against it rather than only
diffing the final text. Keys/sec updates live via a 200ms tick.
Tabs in source are rendered as two spaces so players never need to
press Tab -- sidesteps a browser default-Tab-moves-focus fight
entirely rather than fighting it with preventDefault.
Verified via simulated typing sessions (puppeteer), not just static
review -- both an artificially fast pass (confirms the math is
internally consistent: 308 correct/310 total keystrokes -> 99%,
matches displayed) and a realistic ~60wpm-paced pass (confirms no
unit-conversion bug that only a slow, deliberate typist would hit
tests-at-lightspeed wouldn't surface). That process caught two real
bugs before they'd have hit a real player:
1. A stray `tabindex="0"` on the code display let the browser's
native click-to-focus behavior steal focus away from the hidden
textarea before our own focus() call ran -- typing silently did
nothing. Fixed by removing the tabindex and switching to a
mousedown+preventDefault handler instead of click.
2. The help modal's CSS set `display: flex` unconditionally, which
(author CSS always beats the UA stylesheet) overrode the `hidden`
attribute's default `display: none` -- the modal was invisibly
covering the entire viewport and intercepting every click, at all
times, whether or not it had been opened. Fixed with an explicit
`.modal-overlay:not([hidden])` rule.
Also verified the actual Docker image builds and serves correctly
(nginx, no build stage needed since there's nothing to compile).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 14:12:44 +02:00
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
python3 -m http.server 8850
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Status
|
|
|
|
|
|
|
|
|
|
Built and verified via simulated typing sessions (not just static
|
|
|
|
|
review): focus handling, live character-by-character highlighting,
|
|
|
|
|
newline handling for multi-line snippets, and the WPM/accuracy/KPS math
|
|
|
|
|
all confirmed against both artificially fast and realistic human-speed
|
|
|
|
|
input. Caught and fixed two real bugs in the process — a focus-stealing
|
|
|
|
|
issue caused by a stray `tabindex` on the code display, and a modal
|
|
|
|
|
overlay that was invisibly covering the whole page and intercepting
|
|
|
|
|
every click because its CSS unconditionally overrode the `hidden`
|
|
|
|
|
attribute.
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
MIT.
|