typecheq

get serious about your typing test; it compiles now.

Ready

Click the test area, then start typing

Key aPending aCorrect aIncorrect aRetyped aCursor
WPM0.0WPM
Accuracy0.0%
Mismatches0
Time Left30s

Live WASM State (JSON)

What am I looking at?
meta
Identifies the schema and codec versions this payload conforms to. Consumers should validate meta.schema_version before parsing.
session
The complete state of the current attempt as of this render: mode, passage, input, diff, analytics, and timer.
session.mode / session.passage.category
mode is "passage" (a fixed corpus entry, chosen by length) or "time" (randomly generated words, extended to keep ahead of the cursor for as long as the deadline allows). passage.category is "short"/"medium"/"long" for passage mode, null for time mode — dictionary text has no fixed length bucket.
session.diff.data
The per-position diff payload, encoded per the codec named in meta.codec and detailed in session.diff.encoding/session.diff.symbol_layout: each of session.diff.length positions is one 7-bit symbol — a 2-bit status code in bits 0-1, a saturated 4-bit attempt count in bits 2-5 (session.diff.attempts.max_value), and a 1-bit reflow flag in bit 6 — packed as a cross-byte bitstream per session.diff.packed_bytes, then base64-encoded per RFC 4648. Decode order matches passage order. Each position's status is a direct comparison of the typed character against the target character at that position — not an alignment, since the typed buffer can only ever grow by appending a keystroke or shrink by truncating on backspace, so there's never a real insertion or deletion to align.
session.diff.data — reflow flag (bit 6)
Historical: an earlier scoring algorithm could reinterpret which target position a keystroke belonged to well after you typed it, and this bit flagged the render where that happened. Positional scoring can no longer reinterpret anything: a position's status is fixed the moment it's typed and never changes without a corresponding keystroke at that exact position — so this bit is permanently 0. Kept in the wire format for backward compatibility.
session.diff.attempts
Historical aggregates over every passage position ever attempted: total, the single most-retried position (max/max_position), and how many positions were ever revised (revised). These raw counters survive backspacing and are distinct from the saturated, cursor-local attempt counts embedded in session.diff.data. They are mirrored into result.summary as attempts_* once finalized.
session.analytics.pace_distribution
Distributional statistics over raw pace, not overall WPM: session.analytics.pace_distribution.sampling is "non-overlapping" — the accepted-printable-keystroke stream (basis: "accepted-printable-keys") is grouped into disjoint, back-to-back segments of segment_keys (5) keystrokes each, and each completed segment yields one rate sample of 60000 / segment_elapsed_ms. Correct, incorrect, and retyped printable keys all count toward a segment; Backspace never does, but time spent correcting or pausing before the next accepted key still counts toward that key's segment. A segment whose canonical elapsed time is zero cannot produce a finite rate and is discarded into discarded rather than clamped to a floor duration — so no sample is ever manufactured, and one short interval can only ever affect the one segment it falls in, not the whole distribution. available requires at least three valid segments. These statistics are maintained online per meta.engine's accumulator and mirrored into result.summary as the pace_* fields once result.finalized is set — distinct from result.summary.wpm, which remains the authoritative correct-character overall WPM for the complete session.
session.timer
untimed is true for passage mode: there is no deadline, session_time_ms only counts up, and allowed_time_ms/time_left_ms/duration_ms are all null. For time mode (untimed: false), session_time_ms is the single capped session clock used for scoring, allowed_time_ms is its inclusive upper bound (one of 15000/30000/60000/120000), and the legacy elapsed_ms/duration_ms fields mirror those values so consumers can validate the timing contract. Finalized values are also mirrored into result.summary and covered by the result checksum.
result
result.verification is PENDING during the test, then reports the independent replay, hash-chain, Merkle, VM, and certificate-round-trip checks. The unreleased 2.0.0-dev.4 schema issues a binary TC-CERT in result.certification when verification passes; its Reed-Solomon error-correcting envelope (result.certification.ecc) remains null until Phase 6, and stable 2.0.0 is reserved for Phase 7. The old CRC32 survives only as explicitly labeled result.legacy_checksum diagnostic metadata.
result.summary.distance / result.summary.journey_distance
distance is the finalized mirror of session.diff.distance: the positional mismatch count over the final typed text. journey_distance, added in 2.0.0-dev.3, is a different and independently-computed statistic: the true edit distance (insertions and deletions included) between the complete raw keystroke log recorded in session.audit — every accepted key this session, including ones later erased by backspace — and the attempted span of the passage. It's computed once at finalization, not per keystroke, and can be nonzero even when distance is 0 (a corrected typo costs nothing against the final text, but it's still part of the journey it took to get there).