Local-first, genuinely
Decks, cards and your review history live in your browser's own database. No server holds a copy, because no server is ever sent one.
Donki is a flashcard app for the browser. Cards are written in Markdown, can speak out loud, and are scheduled by the algorithm that has been carrying spaced repetition since the eighties. There is no account to make, because there is nowhere for your decks to go.
Free, installable, and it keeps working with the network off.
Everything below runs in the page you are one click away from. Nothing to install first, nothing to sign up for.
Decks, cards and your review history live in your browser's own database. No server holds a copy, because no server is ever sent one.
Cards come back on the classic SuperMemo-2 curve, counted in study sessions rather than calendar days -- so a week away doesn't bury you under a backlog the moment you return.
Self-rated recall, typed answers checked case- and accent-insensitively, and multiple choice whose wrong answers are drawn from the rest of your deck.
A @tts(...) widget reads text aloud in any voice your device
has, with optional pitch and rate -- and can hide the text entirely for
listening practice.
Export a deck and you get a single .donki JSON file with the
images and audio embedded in it. Import it anywhere, or share a link that
points at one.
Opt in and a nudge arrives at the hour you pick. The push carries no payload: your device counts what is due and writes the notification itself.
Write the face the way you would write a note. GitHub-flavoured Markdown, images and audio, plus a couple of extras Donki adds for studying.
@tts(...) for pronunciation, dictation and listening drills.How do you say **hello** in Japanese?
@tts(ใใใซใกใฏ){"lang": "ja-JP"}

{
"type": "deck",
"name": "Japanese Basics",
"urn": "urn:donki:anon:user123:deck456",
"cards": [
{
"urn": "urn:donki:anon:user123:card789",
"face": "How do you say 'Hello'?",
"prompts": [
{ "type": "typed", "answer": "Konnichiwa" }
],
"updatedAt": 1718000000000
}
]
}
Export writes plain JSON -- readable, diffable, and simple enough to generate from a script or a spreadsheet. Import merges by URN and settles conflicts by last write, so re-importing an updated deck edits it in place instead of duplicating it.
Study progress is deliberately left out of the file. A deck you hand someone carries the cards, not your schedule.
This is what the format is shaped for. A deck is one JSON document with a handful of required fields, the cards are Markdown, and every identifier is a string a model can invent โ so "make me a deck for the JLPT N5 verb list" is one response, not an integration.
@tts(...) is rendered on your device, not shipped as audio.Read https://donki.3sln.com/docs/ and write me
a .donki deck of 20 Japanese greetings.
Typed answers for the readings, @tts on every
face so I can hear them, and multiple choice
for the ones that look alike.
In your browser. Decks and reviews are stored in IndexedDB on the device you study on, and the app works with the network unplugged.
The one thing that ever reaches a server is a push subscription, and only if you switch reminders on: an anonymous endpoint your browser hands out, your time zone, and the hour you picked. Nothing about what you study. Turning reminders off deletes it.
It opens straight into an empty dashboard. Add a deck, add a card, and you
are studying -- or import a .donki file you already have.