Drill is a local-first study application for spaced-repetition review, multiple-choice quizzes, flashcards, and generated math exercises. It uses ts-fsrs for scheduling and stores card state in an IndexedDB-backed SQLite database.
The application runs in the browser and does not require an account or application server.
npm install
npm run devOpen http://localhost:3000. Pick a built-in project from the Review tab or drop a JSON file onto the dashboard.
| Command | Description |
|---|---|
npm run dev |
Vite dev server (port 3000, HMR) |
npm run build |
TypeScript check + production build |
npm run preview |
Serve the production build locally |
The landing screen with four tabs:
- Review: select a project to study, view recent projects, see deck stats (new / learning / due)
- Stats: cross-project review history, retention charts, streak tracking
- Create: build new study projects from source material (supports Gemini API for AI-assisted question generation)
- Parameters: tune FSRS settings (desired retention, new cards per session, leech threshold, max interval)
- MCQ quizzes: multiple choice with instant feedback, explanations, and image lookup
- Passage-based quizzes: reading comprehension with shared context passages
- Flashcards: 3D flip cards with Again/Hard/Good/Easy rating (FSRS scheduling)
- Math drills: randomly generated problems with step-by-step solutions (conversion, average, percent, decimal)
Cards are scheduled using the FSRS algorithm (Free Spaced Repetition Scheduler). Key concepts:
- New cards are introduced up to a daily limit (default: 20 per session)
- Learning/Review cards appear when due based on FSRS scheduling
- Leech detection flags cards that repeatedly fail (configurable threshold)
- Cram mode reviews all cards in a section by weakest stability, ignoring due dates
- Easy mode auto-rates cards as Good for faster review sessions
- Activity chart: per-section or combined review history with cumulative score graph
- Glossary: context-aware term panel with relevance scoring and search filtering
- AI assistant: insights, targeted review suggestions, and question generation (requires local Claude CLI)
- Notes: quick timestamped notes per project (press
/)
- Offline-first: SQLite database runs in a Web Worker (wa-sqlite with IndexedDB backing). No server required
- Customizable keybinds: rebind any keyboard shortcut from the Keys panel
- Zen mode: hides score bar and progress indicators for distraction-free study
- Backup/restore: export and import project data as JSON
- PWA support: installable as a standalone app with offline caching
All shortcuts can be rebound via the Keys button in the header.
| Default Key | Action |
|---|---|
1-4 |
Select answer / Rate card |
D |
Skip (double-tap) / Next |
Z |
Undo last action |
S |
Suspend card |
B |
Bury card (skip until tomorrow) |
R |
View image |
A |
Go back to previous question |
| Default Key | Action |
|---|---|
Space / F |
Flip card |
1-4 |
Rate (Again / Hard / Good / Easy) |
D |
Flip or rate Good |
| Default Key | Action |
|---|---|
Enter |
Submit answer |
D |
Skip / Next problem |
| Default Key | Action |
|---|---|
/ |
Open quick note |
Create a .json file following the format in projects/README.md, then either:
- Drop it onto the dashboard
- Use "Open Project File" in the Review tab
See projects/README.md for the required JSON shape. Custom projects are stored in localStorage. For guidance on generating projects with LLMs, see GENERATING_PROJECTS.md.
src/
├── App.tsx # Root: dashboard or study phase
├── main.tsx # Entry point
├── index.css # @import per-feature CSS + theme tokens + responsive rules
├── core/ # Shared infrastructure
│ ├── store/app.ts # Phase, active project/tab, toggles
│ ├── store/sections.ts # sectionHandlers Map + keyboard routing
│ ├── hooks/ # useWorker, useKeyboard, useTimer, useLatex
│ └── workers/ # db.worker.ts (SQLite+FSRS), protocol.ts
├── features/ # Self-contained feature folders
│ ├── dashboard/ # Landing screen: review, stats, create, parameters
│ ├── launcher/ # Project loading logic, recent projects, file drop
│ ├── quiz/ # MCQ + flashcard (shared session/score/cram)
│ ├── math/ # Math mode with categories + KaTeX
│ ├── activity/ # Sidebar chart + stats widget
│ ├── glossary/ # Terms dropdown with relevance scoring
│ ├── ai/ # AI assistant panel (Claude CLI bridge)
│ ├── notes/ # Note input (/ key)
│ ├── settings/ # FSRS settings, keybinds, tips
│ ├── backup/ # Backup/restore, autosave
│ └── export/ # Project data export
├── components/ # Shared display components
│ ├── LatexText.tsx # LaTeX math rendering via KaTeX
│ └── layout/ # StudyApp shell, Header, TopToggles, SectionsContainer
├── projects/ # Data types, loader, registry, built-in projects
├── data/ # Math problem generators
└── utils/ # shuffle, formatting helpers
- Two-phase UI:
appPhasesignal switches between'launcher'(dashboard) and'study': no router needed - Worker-based persistence: All database operations run in a Web Worker via wa-sqlite. Messages are serialized through a promise chain to prevent race conditions
- Session factories:
createQuizSession()andcreateMathSession()produce independent signal bundles per section, stored in asectionHandlersMap for keyboard routing - Module-level state: Stores export signals directly rather than using context providers: simpler for a single-page app with no nested routing
- Feature folders: Each feature is self-contained with its own component(s), store, and CSS. Adding or modifying a feature means touching only its folder
| Library | Purpose |
|---|---|
| SolidJS | Reactive UI framework |
| ts-fsrs | FSRS spaced repetition algorithm |
| wa-sqlite | SQLite compiled to WASM (IndexedDB VFS) |
| KaTeX | LaTeX math rendering |
| Vite | Build tool + dev server |
Requires a modern browser with Web Worker, SharedArrayBuffer, and IndexedDB support. The dev server sets the required COOP/COEP headers automatically via vite.config.ts.
For production hosting, you need to set these headers on your server:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp