Skip to content

About

A typing trainer where you type the assistant side of a coding session, character by character, with no completion. 614 sessions across 10 languages, in Japanese and English.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

You are LLM

You are LLM

You type the LLM's side of a coding session. No completion. No shortcuts.

Open the trainer Deploy

Status

The trainer runs end to end. 614 sessions cover ten languages of code and two natural languages, graded from Easy to Expert+. AZIK is not implemented yet.

Commands

Command What it does
pnpm dev Start the dev server
pnpm build Typecheck, then build into dist/
pnpm test Run the tests
pnpm lint Lint with type-aware rules
pnpm check:material Check session JSON without running the suite
pnpm typecheck Typecheck only

How a session runs

Pick a session, then type the assistant blocks one at a time. Every block is one run of the engine. A block ends only when the whole target is typed.

The stage holds one block at a time. A finished block moves into a folded log rather than stacking below the next one, so the page keeps its height and a small screen stays playable.

A hard Rust session in progress, with the combo at 700 and the kana target half typed

You see You type
The user prompt Nothing. It is context
Japanese prose Its kana reading, which an IME turns into the kanji
Code and shell commands The characters as they stand

Enter produces a newline, and Tab produces one step of indent. A key the engine rejects costs the combo and nothing else.

Indent steps are measured from the session itself, so two space code takes one Tab per level and four space code takes one Tab per level too. The spaces still work if you would rather type them. Tab keeps moving focus everywhere else on the page, so it is only taken when an indent is actually due.

The display tracks the run while it happens.

Tile What it counts
Combo Accepted keys in a row. It turns gold past 25 and resets on a mistake
Best The longest combo of the run
Keys / min Accepted keys against elapsed time
Accuracy Accepted keys against every press

A finished session is graded from S down to D. Speed alone does not earn a rank, because each tier has an accuracy floor as well.

The result panel showing an S rank, the run's figures and the share buttons

The result carries a share row. X and Bluesky get the rank and the figures with the link, Facebook takes the link alone because it accepts nothing else, and Copy puts both on the clipboard.

Cues are synthesised through Web Audio rather than loaded, so they cost nothing to ship and fire with no delay. The key click climbs in pitch with the combo. Sound on in the header turns the lot off, and the choice is remembered in the browser.

Each line carries who said it. The prompt sits behind a person, the block being typed behind a robot, and the robot's line shows a spinner and a word that keeps changing while the block runs. It is a nod to what every coding agent puts on screen while it works, in this project's own words.

Note

Every animation is dropped under prefers-reduced-motion, and the spinner and its words stop changing as well.

Social preview

scripts/og.html is the one template both preview images come from. docs/social-preview.md holds the two commands and says where each image goes.

Image Size Used by
public/og.png 1200 by 630 The og:image tag on the site
docs/social-preview.png 1280 by 640 The repository preview, uploaded by hand

The input engine

TypingSession keeps every possible spelling alive at once. The typist never declares a reading. The engine narrows the options as keys arrive.

Target Keys it accepts
し si, shi, ci
きゃ kya, kixya, kilya
じゃ zya, ja, jya, zixya
きって kitte, kixtute, kiltute
にほん nihonn, nihoxn, nihon'

Three rules do most of the work.

Rule Holds Fails
A bare n needs a consonant next kanzi for かんじ kiniro for きんいろ
っ doubles any consonant but n kitte for きって anna for あっな
A digraph never takes a single kana's spelling syi for しぃ shi for しぃ

Characters outside the table are typed as themselves. That is what makes source code work as material.

Note

Alternative layouts such as AZIK plug in through the Layout interface in src/engine/types.ts. The engine holds no table of its own.

Material

Sessions are static JSON under src/materials/sessions/. Adding a file adds a session. Nothing registers it. Every session is validated on load, so a bad field fails fast and names its position.

Each session sits on three axes.

Axis Values
Language ja, en
Difficulty easy, normal, hard, expert, expertplus
Code language C, C++, C#, Go, HTML/CSS, Java, PHP, Python, Rust, TypeScript

Difficulty is measured, not chosen. scripts/typing-load.mjs scores every session across the whole set rather than within one language, so Rust mostly lands at Hard or above.

Difficulty Score Sessions
Easy under 11 84
Normal 11 to 16 166
Hard 16 to 22 206
Expert 22 to 34 152
Expert+ over 34 6

The score is how hard a session is per keystroke, stretched a little by how much of it there is.

Hardness is the share of keys that need Shift, times the number of distinct symbol shapes the session asks for. Shapes are what separate Rust from PHP. PHP types more symbols, but $ and -> are most of them, learned once. Rust spends the same weight across &mut, ::, <'a>, ? and a dozen others.

Length counts symbol keystrokes rather than all of them. A session is not harder for spelling out htmlspecialchars, which is the easiest kind of key there is.

Rust mostly comes out at Hard or above. The exceptions are attributes on a type or one library call. Java mostly comes out at Hard or below, and the exceptions are the ones whose sed is dense with escapes or whose test setup is long. Expert+ is the Rust transaction that takes a closure, and a few short sessions that ask for a new symbol shape on nearly every line.

The front page filters on all three, and a filtered view is a shareable URL. It opens on Japanese, because that is what most of the material is for. All shows both languages and says so in the address.

The front page, with a line typing itself and the session list filtered by three axes

src/materials/FORMAT.md is the authoring guide. Read it before writing a session.

Important

A Japanese text block needs a reading in kana. The suite fails when a Japanese target holds a character no keyboard can produce, because no romaji sequence reaches it.

Deployment

A push to main builds the site and publishes it through GitHub Pages. The workflow lints, tests and builds before it deploys, so a red suite never reaches the site.

Piece Where
Workflow .github/workflows/deploy.yml
Base path BASE in vite.config.ts
Deep links 404.html and one page per session, from the static-pages plugin

Every session also gets a real page written at build time, under both /sessions/<id> and /sessions/<id>/, carrying its own title and description. A shared link used to fall through to 404.html, and a crawler handed a 404 shows no preview at all.

Note

The domain comes from mpyw/mpyw.github.io, which owns mpyw.me. Project sites under the same account are served below it automatically. This repository holds no CNAME file.

TypeScript 7 and linting

The app runs on TypeScript 7 only. Linting uses oxlint with oxlint-tsgolint for type-aware rules.

Package Role
typescript Compiles and typechecks the app
oxlint Runs the lint rules, set in .oxlintrc.json
oxlint-tsgolint Runs type-aware rules such as no-floating-promises on typescript-go

typescript-eslint needs the JavaScript compiler API, which TypeScript 7 does not ship. tsgolint is built on the Go compiler itself, so it needs no second TypeScript install.

The rule set mirrors the old typescript-eslint strictTypeChecked and stylisticTypeChecked presets, plus the React Hooks and React Refresh rules.

About

A typing trainer where you type the assistant side of a coding session, character by character, with no completion. 614 sessions across 10 languages, in Japanese and English.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Used by

Contributors

Languages