This app uses a simplified spaced repetition system inspired by SM-2. Cards are scheduled for review at increasing intervals based on successful recall.
There are 10 interval levels (0-9):
| Level | Interval | Description |
|---|---|---|
| 0 | 1 minute | Initial / Reset after wrong answer |
| 1 | 10 minutes | First success |
| 2 | 1 hour | Second success |
| 3 | 1 day | Third success |
| 4 | 3 days | Fourth success (considered "mastered") |
| 5 | 7 days | Fifth success |
| 6 | 14 days | Sixth success |
| 7 | 30 days | Long-term retention |
| 8 | 60 days | Extended retention |
| 9 | 90 days | Maximum interval |
successCountintervalIndex by 1 (max 9)nextReview = now + interval for new levelNote: With adaptive difficulty, fast responses advance by +2 levels, and hint usage prevents advancement.
failCountintervalIndex to 0nextReview = now + 1 minuteCards are selected for review using the "Review First, Learn Second" principle:
Cards where nextReview > 0 AND nextReview <= now
Why first? These cards have been started but need review. Missing reviews wastes previous learning effort and causes forgetting. Spaced repetition ONLY works if you review before forgetting.
Selection: Same-session wrong cards first (if any are due), then random from remaining past due reviews.
Same-session preference: Cards answered wrong earlier in this session get priority when they become due again. This reinforces corrections while the context is fresh, without bypassing SRS intervals — the 1-minute wait still applies.
Cards where nextReview === 0 (never attempted)
Why second? Expand vocabulary only after clearing reviews. Prevents the "perpetual beginner" problem of surface-level exposure without mastery.
Selection: Random from all new cards
Cards where nextReview > now (future reviews)
Why last? These aren't due yet. Only shown when no past due or new cards remain.
Selection: Soonest due card first
This follows proven SRS best practices used by Anki and SuperMemo. Reviews always take precedence over new material to ensure retention and prevent review backlog.
Each card has independent progress for READ and WRITE modes:
progress[word] = {
read: {
intervalIndex: 0, // Current level (0-9)
nextReview: timestamp, // When card is due
successCount: 0, // Total correct answers
failCount: 0, // Total wrong answers
lapseCount: 0, // Times failed after reaching level 2+
avgResponseTime: null, // Rolling average response time (ms)
difficultyScore: 1.0 // Card difficulty (0.5-2.0)
},
write: {
intervalIndex: 0,
nextReview: timestamp,
successCount: 0,
failCount: 0,
lapseCount: 0,
avgResponseTime: null,
difficultyScore: 1.0
}
}
This means:
A card is considered "mastered" when intervalIndex >= 4 (3+ days interval). This is displayed in the homepage stats.
As you progress with a card, hints are gradually removed to ensure true recall:
| Level | READ Mode | WRITE Mode |
|---|---|---|
| 0-1 | "Show hanyupinyin" button available | "Show hint" button available |
| 2+ | No pinyin hint — must recall pronunciation | No hint button — must recall characters |
Why? At levels 0-1, you're still learning the card and hints help reinforce memory. By level 2, you've succeeded twice — now it's time to prove you can recall without aids. If you fail at level 2+, you reset to level 0 and hints become available again.
For new cards (no progress data):
nextReview defaults to 0, meaning immediately dueBeyond simple correct/wrong tracking, the app measures implicit difficulty signals to adapt intervals per-card. This provides gradation without requiring extra button clicks.
Three implicit signals determine how well you know a card:
| Signal | What It Measures | How It's Captured |
|---|---|---|
| Response Time | Speed of recall — fast = strong memory | Timer from card display to answer |
| Hint Usage | Whether you needed help to recall | "Show pinyin" / "Show hint" button clicks |
| Outcome | Whether you got it right | Correct / Wrong answer |
Combining these signals creates a spectrum of memory strength:
| Time | Hint | Result | Interpretation | Interval Adjustment |
|---|---|---|---|---|
| Fast | No | Correct | Strong recall — truly mastered | +2 levels (skip ahead) |
| Slow | No | Correct | Weak but recalled — needs reinforcement | +1 level (normal) |
| Fast | Yes | Correct | Recognized after hint — partial knowledge | +0 levels (stay same) |
| Slow | Yes | Correct | Struggled even with hint — barely known | +0 levels, mark struggling |
| Fast | No | Wrong | Complete blank — not learned | Reset to 0 |
| Slow | No | Wrong | Tried but failed — interference or decay | Reset to 0 |
| Fast | Yes | Wrong | Hint didn't help — never learned properly | Reset to 0, mark struggling |
| Slow | Yes | Wrong | Struggled and failed — potential leech | Reset to 0, increment leech counter |
What counts as "fast" or "slow" adapts to each user:
// Per-user rolling average (updated each review)
avgResponseTime = avgResponseTime * 0.8 + thisResponseTime * 0.2
// Thresholds relative to user's average
FAST = responseTime < avgResponseTime * 0.7 // 30% faster than usual
SLOW = responseTime > avgResponseTime * 1.5 // 50% slower than usual
Why adaptive? A 5-second response might be fast for a complex sentence but slow for a simple word. User-relative thresholds account for individual pace and card complexity.
Using a hint indicates incomplete recall, even if you get the answer right:
| Hint Button | Mode | Impact on "Correct" Answer |
|---|---|---|
| "Show hanyupinyin" | READ | Correct with hint — don't advance interval |
| "Show hint" (blur) | WRITE | Correct with hint — don't advance interval |
| "Show English" | READ | No penalty (translation lookup is acceptable) |
Key insight: If you needed the pinyin hint to pronounce it, or needed to peek at the characters to write them, you haven't truly memorized the card yet. The interval should stay the same rather than advance.
Each card tracks a difficulty score (0.5 to 2.0) that adjusts intervals:
Example: A 7-day base interval becomes 14 days for an easy card (score 0.5) or 3.5 days for a hard card (score 2.0).
| Scenario | Level Change | Difficulty Change |
|---|---|---|
| Fast + No hint + Correct | +2 levels (skip ahead) | × 0.9 (easier) |
| Normal + No hint + Correct | +1 level | No change |
| Slow + No hint + Correct | +1 level | × 1.05 (slightly harder) |
| Any + Hint + Correct | +0 levels (stay same) | × 1.1 (harder) |
| Any + Any + Wrong | Reset to 0 | × 1.2 (harder) |
For implementation details, see Developer Guide: Adaptive Difficulty Implementation.
A "leech" is a card that consumes review time without being learned. These cards need special attention.
A card is flagged as a leech when either:
Leech cards will be marked with visual indicators:
When a card is flagged as a leech, suggested actions:
For implementation details, see Developer Guide: Leech Detection.
The adaptive system creates a virtuous cycle:
This means your study time automatically focuses on cards that need it most, without requiring you to manually rate difficulty.