Case · Web app · TypeScript
flashcards-sm2: "Cards", a flashcard box with SM-2 spaced repetition
A concept app on Vue 3: decks of cards and review by the SM-2 algorithm, offline and with no backend, data in IndexedDB. CSV/TSV import detects the delimiter and encoding itself (UTF-8, UTF-16 by BOM, Windows-1251), export is protected from CSV injection, and there is a full JSON backup with strict validation. SVG statistics: a 30-day forecast, card maturity, retention.
- Vue 3
- TypeScript
- Vite
- IndexedDB
- PWA
- SM-2
- fast-check
- vitest
- axe
- Cloudflare Pages
- GitHub Actions
01 · How it looks
Screenshots


02 · About
What it is and why
The task: an offline flashcard box whose review schedule does not break when the time zone or daylight saving changes, and whose import of foreign CSVs does not require guessing the encoding.
The solution: Vue 3 + TypeScript, the SM-2 algorithm as pure logic with no DOM, data in IndexedDB. "Today" is the device calendar date, the schedule is stored as dates, not timestamps.
Limitations
A concept: no sync between devices, no images or audio.
Reverse cards are not created automatically.
Data is tied to the browser and profile: clearing site data deletes it, hence the JSON backup.
What is inside
- SM-2 as in the SuperMemo-2 description: EF from 1.3, start 2.5, intervals of 1 and 6 days, then max(prev+1, round(prev·EF)), a cap of 3650 days; differences from the original are in the README
- CSV/TSV import: quotes and line breaks in cells, delimiter and encoding (UTF-8, UTF-16 by BOM, Windows-1251) detected automatically; limits 1 MB, 5,000 rows
- CSV export protected from CSV injection and a full JSON backup with strict validation on load
- SVG statistics: a 30-day review forecast, card maturity, retention, a 26-week heatmap
- 30 vitest tests + fast-check; a card flip in pure CSS, keyboard (space, 1 to 4), axe 0
- Deployed on Cloudflare Pages, the PWA works offline
03 · How to run
Run it locally
git clone <repository on request> flashcards-sm2
cd flashcards-sm2
npm ci
npm run dev04 · Code
The repository is private
The source is in a private repository. Message me on Telegram and I will open access.
Request the code