kanji-buddy

SRS engine

Spaced repetition, unlocking, and grading an answer. The three pieces that make it a trainer rather than a dictionary.

Stages

An item sits at a stage from 0 to 9. Answer correctly and it moves up one, waiting longer each time; answer wrongly and it falls back. Reach stage 9 and it is burned — learned, never asked again.

StageNameThen wait
0Locked / lesson
1–4Apprentice4h · 8h · 23h · 47h
5–6Guru1 week · 2 weeks
7Master1 month
8Enlightened4 months
9Burnednever again

Those intervals are read from the spaced_repetition_systems table, not hard-coded. There are two systems — the standard one and an accelerated one for levels 1–2 — and the engine simply uses whichever the subject names.

The penalty formula

lib/srs.ts
new_stage = current − ceil(incorrect / 2) × penalty
  penalty = 2 when current ≥ passing stage, else 1
  floored at the starting stage

Getting something wrong twice costs the same as getting it wrong once — ceil(2/2) = 1 — but a third mistake costs another step. And once an item has reached Guru, every step back costs double: the further you have come, the more a lapse means you had not actually learned it.

This is documented, not guessed

It is published on knowledge.wanikani.com. I initially wrote in a comment that the formula was undocumented and reverse-engineered; that was wrong, and the comment now carries the source. Worth stating because the alternative — an SRS whose arithmetic nobody can check — is a bad thing to have in a learning tool.

Unlocking

radical passed (Guru) └──▶ unlocks the kanji that use it └──▶ unlocks the vocabulary that uses those kanji 90% of a level's kanji passed └──▶ next level unlocks

This is what makes the ordering feel earned rather than arbitrary: you meet a kanji only once you know its parts. It lives in lib/progression.ts, runs inside the same transaction as the review that triggered it, and is also what bootstraps a brand-new account — otherwise you would sign in to an app with nothing to study.

Grading an answer

Three verdicts, not two. lib/answer.ts:

VerdictWhenEffect
correctExact match, an accepted synonym, or close enoughAdvances
incorrectWrong, or a blacklisted near-synonymCounts against the stage
retryNot an attempt — nudged insteadNothing at all

Meanings tolerate typos; readings do not. A learner shouldn’t lose a stage to “grond”, but accepting a near-miss kana would teach the wrong word. The distance is Damerau-Levenshtein, which scores swapped adjacent letters as one edit rather than two — transposition being the commonest typing slip, and two edits putting it beyond every tolerance allowed.

Tolerance scales with length: three characters or fewer must be exact, or “no” would match “go”.

Retry covers the cases that are neither right nor wrong: typing the reading when asked for the meaning, giving a valid kun’yomi when the on’yomi was wanted, or romaji that never converted to kana. None of them costs a stage — you knew something, just not the thing being asked.

The review queue

An item leaves the queue only when every aspect is correct. Radicals have one question (meaning); kanji and vocabulary have two (meaning and reading), asked back to back. A wrong answer sends the item to the back to be asked again later in the session.

The rule is a pure function in lib/quiz.ts, which is why it can be tested at all — it lived inside the component until a bug that re-asked the same radical three times made the case for pulling it out. See Web app & quiz.

A consequence worth knowing

Because a result is only written once every aspect is correct, leaving mid-item discards it — and that includes the mistake. Bailing out before finishing a kanji dodges the penalty. WaniKani behaves the same way; it is a known quirk rather than an oversight here.