Repository navigation
feat: add the thokr.jrnxf.co website, where every line is a thokr test you can type - #40
Merged
Merged
Conversation
… can type The page lives in web/ and is left out of the crate. Its tests run on thokr's own Rust: web/engine compiles src/ (the test loop, the screen and the word lists) to WebAssembly in the build step, so the page cannot drift from thokr. - Each block is a screen of its own, with no trailing period to type. A finished block hands the keyboard to the next one; after the last, the install footer grows. DM Mono only, self-hosted with its OFL notice. - Mashing keys no longer resets blocks: after a test, thokr reads r and n as "again" and "new words", so a fast typist running past the end restarted the block. Keys after the end now carry on into the next block; the arrow keys still start over or get new words. - CI builds the site, checks the engine and kit/chart.js against the insta snapshots, and types through the page in Chromium, mashing included. - wrangler.jsonc and build.sh are ready for Cloudflare Workers Builds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds thokr.jrnxf.co: one page where every line is a thokr typing test, run by thokr's own Rust compiled to WebAssembly.
For you: review and merge (about 10 min), then set up the deploy once (about 5 min). Nothing on Cloudflare exists yet:
jrnxf/thokr, with root directoryweb../build.shand the deploy command tonpx wrangler deploy(it installs Rust itself, about 1 min).thokr-webWorker and attachesthokr.jrnxf.cofromwrangler.jsonc. If the domain does not appear, add it under the Worker's Domains & Routes.Check after the first deploy (2 min):
Fixed on the way: mashing keys after the end of a block reset it instead of moving on, because thokr reads r and n there as "again" and "new words". Keys after the end now carry on into the next block. A Playwright test mashes past a sentence and fails without the fix.
Evidence: before and after mashing past the first line, then the built site, dark desktop and light phone.
Risk: two-way door. Blast radius: a new subdomain only; the crate and the TUI do not change (
webis excluded from the package).Intent
About thokr: thokr (github.com/jrnxf/thokr, Rust TUI, on crates.io and brew) is a sleek typing test in the terminal with visualized results (WPM chart) and historical logging. It has no landing page or logo yet.
The owner wrote: "could you prototype a landing page for creative fsrx and thokr landing page using the same prompt and ultimate creativity we used for building the ones for drip and okfs"
The prompt those used, for context: the okfs site leaned into its logo's retro-80s "snowbird" feel (80s travel posters, motel signage, sun-faded print, early computer catalogue) and the owner picked "Catalogue" - "super dope, I love it"; the drip site's "Instrument" direction drew the product as a physical device with its real engine inside (Archivo and Martian Mono, one orange, cream paper) - "honestly in love with instrument". Both put the real product running in the page. The owner said "NO AI FLUFF. be creative"; they found gradient-blob/glass "Aurora" pages "AI vibe coded"; they want plain, specific copy with no hype. Live references: https://okfs.jrnxf.co and https://drip.jrnxf.co.
Is it possible to use WebAssembly in the actual Docker binary using WebAssembly or something? I like D and B the best. More like that, please
i like one line the best, but i don't like that i have to click into things for the interactivity to start. can you fix that and give me more like one line? i do like the dots look but it's a lie that thokr does anything with the braille look right?
i like one-line, but it's a bit text heavy, and I'm not sure of the font
i actually also really like the moving text on ticker. curious if we could amke that an option on thokre to test out?
using the shaders and stuff is it possible ta hev the the ticker move the text slowly? also ticker should ahve text starting in the middle i think
can i get a preview of cell level fades?
i think bc we can't smooth the movement of the chars i'm okay to just not do the ticker and keep what we have. where does that leave us?
on thokr, when i'm done typing can it scroll me to the next block ready to keep going
let the typing bits on thokr actualy go full page, and no periods at the end., also don't make them type the brew part. just have a clean footer for install instructions
thokr...
[screenshot: the hero typing block, text wrapping at about 60% of the width with a words/limit/pace bar under it] is not full width
don't show the font picker DM mono is it
when teh user types the last char in the last block the install instructions should grow to be a bit bigger and more prominent
thokr
looks good! when i spammed keys some sections din't progress and just reset. fix that and then get this work started!
What Changed
web/site for thokr.jrnxf.co.web/enginecompiles thokr's ownsrc/(the test loop, the screen and the word lists) to WebAssembly (wasm32-wasip1) behind a small C ABI (tk_key,tk_tick,tk_render,tk_state).web/publicis a single DM Mono page. Every line on it is a full-width thokr prompt that takes keys right away. When a block is finished, the page scrolls to the next one. Fast typing carries keys into the next block instead of resetting the finished one. After the last block, the install footer (brew and cargo, with copy buttons) grows larger.web/build.shbuildsweb/dist. It installs a pinned rustup (checked against its sha256) and Rust 1.99.1 when they are missing, and names the wasm by its content hash._headerscaches that file as immutable.wrangler.jsoncservesdistas static assets on thethokr.jrnxf.cocustom domain.webCI job in.github/workflows/build.ymlrunsnpm ci,./build.shandnpm test. The tests check the engine andkit/chart.jsagainst thokr's insta snapshots, and type through the page in Chromium with Playwright, including a key-mashing burst test.Cargo.tomlnow excludeswebfrom the crates.io package.Risk Assessment
✅ Low: The fix round only changes when the scroll hold ends (it now also ends on a 1s timeout, a wheel or a touch). The hold can no longer stay set forever, and the hold still keeps keys on the next block while the scroll moves past the finished one. The rewritten test checks the Backspace and the ArrowLeft in separate steps, so each check now proves its own claim.
Testing
I built the site with build.sh on a machine with no Rust. rustup-init installed under its own name, so the earlier error is gone, and the wasm build succeeded. In Chromium the 4 burst tests and 10 snapshot tests pass, including the new Backspace and ArrowLeft steps for r2-2. A disposable live driver then checked: - Typing with no click, and a full-width 1200px hero in DM Mono with no font picker. - Sentences with no trailing periods and no brew command to type. - Auto-scroll to the next block after the hero. - A one-burst mash through every block with smooth scroll on: all 4 sentences finished at 100% and none reset. - The install footer growing from 17px to 40px after the last key. I simulated Safari by blocking scrollend registrations. The keyboard hold let go after about 1s when the page was moved without a wheel, and at once on a wheel event. Screenshots and logs are in the evidence directory. I removed the build outputs, node_modules and the temporary toolchains afterwards.Evidence: Live driver transcript
Evidence: Live driver script
Evidence: Hold release with no scrollend (Safari-like)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed (2) ✅
web/public/kit/engine.js:186- While the page smooth-scrolls to the next block, the scroll handler can hand the keyboard back to the block that just finished. moveOn() focuses the next textarea, and its focus listener makes the next block active. But the next scroll event runs pick(), and for the first half of the scroll the finished block is still nearest the middle of the window. activate() then focuses the finished block again (web/public/kit/engine.js:186-189 and 196). Keys pressed in that window go to the finished block. Characters are still passed on through afterFinish/carryOn. Backspace is dropped: WasmTyper.press returns when wasDone && k === "Backspace" (engine.js:116). ArrowLeft/ArrowRight restart the finished block instead of acting on the block being typed. Concrete case: the user finishes sentence 1, keeps typing into sentence 2, mistypes, and presses Backspace within about 300-500ms. The Backspace is swallowed, so the next correct key lands after the error. The same class applies to the hero-to-first-sentence move (index.html moveOn/advance). The mash test in web/test/burst.test.mjs does not catch this: it types with delay 0 before any scroll event fires, and the full-run test uses reducedMotion. Fix at the shared boundary in autoType: while a programmatic scroll started by moveOn is running, pick() should not take focus away (for example, set a flag until scrollend), or pick() should only activate a block on scrolls the user starts.🔧 Fix applied.
3 issues (1 warning, 2 infos) still open:
web/public/kit/engine.js:186- While the page smooth-scrolls to the next block, the scroll handler can hand the keyboard back to the block that just finished. moveOn() focuses the next textarea, and its focus listener makes the next block active. But the next scroll event runs pick(), and for the first half of the scroll the finished block is still nearest the middle of the window. activate() then focuses the finished block again (web/public/kit/engine.js:186-189 and 196). Keys pressed in that window go to the finished block. Characters are still passed on through afterFinish/carryOn. Backspace is dropped: WasmTyper.press returns when wasDone && k === "Backspace" (engine.js:116). ArrowLeft/ArrowRight restart the finished block instead of acting on the block being typed. Concrete case: the user finishes sentence 1, keeps typing into sentence 2, mistypes, and presses Backspace within about 300-500ms. The Backspace is swallowed, so the next correct key lands after the error. The same class applies to the hero-to-first-sentence move (index.html moveOn/advance). The mash test in web/test/burst.test.mjs does not catch this: it types with delay 0 before any scroll event fires, and the full-run test uses reducedMotion. Fix at the shared boundary in autoType: while a programmatic scroll started by moveOn is running, pick() should not take focus away (for example, set a flag until scrollend), or pick() should only activate a block on scrolls the user starts.web/public/kit/engine.js:193- The round-1 fix addsheld, and only two things clear it: pick() finding the held block nearest the middle, or ascrollendevent. Safari has noscrollendup to at least 18.x. Concrete case in Safari: the user finishes a sentence, moveOn calls hold(next) and starts the smooth scroll, then the user turns the wheel or swipes the other way beforenextreaches the middle.heldnever clears. Every later pick() returns early, so.tk-activeand the keyboard stay on a block that is off screen. This lasts until the user scrolls back past that block or clicks a prompt. It can also happen in any browser when scrollIntoView needs no scroll at all: no scroll event fires,heldstays set, and the next manual scroll does not update the active block until it ends. Smallest fix: also clearheldon input the user starts (wheel,touchstart, scroll keys), or after a short timeout set in hold().web/test/burst.test.mjs:115- Round-1 test: the assertion message says "the Backspace undid the mistake", but the test presses ArrowLeft on block 1 right after the Backspace. In the engine, ArrowLeft always restarts the test (engine/src/lib.rs:143 KEY_LEFT => app.restart()). That restart wipes the wrong key whether or not the Backspace reached block 1, so the['c','c','c']check does not prove the Backspace was routed correctly. Only the ArrowLeft half (block 0 stays finished) and the focus check carry evidence. Fix: check block 1's marks after the Backspace and before the ArrowLeft, or test the two keys in separate steps.🔧 Fix applied.
✅ Re-checked - no issues remain.
web/build.sh:30- On a machine with no rustup, build.sh failed with "error: unknown proxy name: 'tmp'". It saved rustup-init under a mktemp name (tmp.XXXX), and rustup-init reads its own file name. The README says that is the Cloudflare Workers Builds deploy path. GitHub CI passes only because its runners already have rustup. I fixed it in the worktree: mktemp -d, save the file as $tmp/rustup-init, and remove the directory on exit. The full build then passed.CARGO_HOME=/tmp/nm-thokr/cargo RUSTUP_HOME=/tmp/nm-thokr/rustup ./build.sh(fresh rustup install; failed before the build.sh fix, passed after)env -u LD_LIBRARY_PATH node --test test/burst.test.mjs(4/4: mashing past the end of a sentence, mashing past the end of the test at the top, typing every block with no clicks, keys typed during the smooth scroll)node --test test/snapshots.test.mjs(the WebAssembly engine and kit/chart.js against thokr's insta snapshots, 10/10)node evidence/drive.mjs: page load with no click, hero full width, no font picker, prompts have no periods and no brew, hero mash, mash with r/n through all 4 sentences, install footer grows, mobile and dark screenshotsnode evidence/drive-hold.mjs: keyboard stays on the next block mid smooth-scroll; no scrollend plus the page jumping away, released by the 1s timeoutnode evidence/drive-wheel.mjs: one user wheel tick releases the hold before the 1s timeout (scrollend stubbed out)🔧 Fix applied.
1 info still open:
web/public/index.html:220- A wheel or scroll during the pause after a block finishes (before moveOn fires, about 700ms for sentences and 1400ms for the hero) still leads to an auto-scroll back down to the next block once the pause ends. This matches the requested 'scroll me to the next block' behavior. It may surprise a user who scrolls up right after finishing.CARGO_HOME=/tmp/... RUSTUP_HOME=/tmp/... ./build.shon a host with no rustup (installs rustup-init 1.29.2 and builds wasm into dist)env -u LD_LIBRARY_PATH node --test test/burst.test.mjs test/snapshots.test.mjs(Chromium in a disposable PLAYWRIGHT_BROWSERS_PATH)node drive.mjs: live Playwright driver against dist served on 127.0.0.1 (scenarios S1-S7, screenshots)node trace.mjs: per-frame trace of scrollY and the active block during auto-scroll and wheel input✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.