---
name: franki-deck
description: Makes flashcard decks for Franki, the iPhone flashcard app, as a .franki file. Use when someone asks for flashcards, a study deck, vocabulary cards or quiz cards for Franki, or to turn notes, a chapter, a word list or a topic into a deck they can open in Franki.
---

# Making a Franki deck

Franki is a flashcard app for iPhone. It schedules reviews with spaced repetition, and it can also
quiz the learner with multiple-choice questions. This skill writes a deck as a `.franki` file: JSON
that Franki opens with a tap.

Your job is to write **good cards** and, for every card, **good wrong answers** (`choices`) for the
quiz. Wrong answers are what make a quiz worth taking, so take as much care over them as over the
cards.

## What to produce

One UTF-8 JSON file named after the deck, ending in `.franki`, for example `Spanish Basics.franki`.
Give it to the person as a file. They send it to their iPhone (AirDrop, Messages, Mail or Files) and
tap it, or choose it in Franki under **+ → Import → Choose File**. Franki shows the deck, and adds it
when they tap **Add to Franki**.

If you can't make files, put the JSON in one code block and tell the person to save it as
`<deck name>.franki`.

## The format

```json
{
  "format": "franki-deck",
  "formatVersion": 1,
  "name": "Spanish Basics",
  "details": "Everyday words for beginners.",
  "symbol": "character.bubble",
  "frontLanguage": "es",
  "backLanguage": "en",
  "cards": [
    {
      "front": "la casa",
      "back": "the house",
      "reverse": true,
      "choices": ["the street", "the room", "the city"],
      "reverseChoices": ["la calle", "la habitación", "la ciudad"],
      "tags": ["home"]
    }
  ]
}
```

### Deck fields

| Field | Required | What it is |
|---|---|---|
| `format` | recommended | Always `"franki-deck"`. |
| `id` | no | A UUID that names this deck across versions of the file, such as `"6F9619FF-8B86-D011-B42D-00C04FC964FF"`. Make one when you first write the deck and keep it when you revise it: opening the revised file then adds only the new cards to the deck the person already has. Leave it out for a one-off deck. |
| `formatVersion` | recommended | Always `1`. |
| `name` | **yes** | The deck's name, up to 100 characters. Short and plain: "Spanish Basics", "Cell Biology". |
| `details` | no | One line on what the deck covers, and any credit a source needs. |
| `symbol` | no | An SF Symbol name for the deck's icon; leave it out if you aren't sure one exists. For example `globe.europe.africa`, `character.bubble`, `atom`, `leaf`, `heart`, `function`, `book`, `music.note`, `brain.head.profile`. An unknown name gets the default icon. |
| `frontLanguage`, `backLanguage` | no | BCP 47 codes for each side's language (`en`, `es`, `ja`, `zh-Hans`, `hi`). Franki uses them to read cards aloud. |
| `cards` | **yes** | The cards, in the order they should be learned. |

### Card fields

| Field | Required | What it is |
|---|---|---|
| `kind` | no | `"basic"` (the default), `"typeIn"` or `"cloze"`. See below. Writing `"basic"` out is fine. |
| `front` | **yes** | The question side. |
| `back` | yes, except cloze | The answer side. For cloze, optional extra notes shown after the answer. |
| `reverse` | no | `true` also makes a back-to-front card. For vocabulary, not for questions. Never on cloze. |
| `choices` | strongly recommended | Three wrong answers to the front, for the quiz. See "Writing wrong answers". |
| `reverseChoices` | when `reverse` is true | Three wrong answers to the reverse card, whose answer is the **front**. |
| `tags` | no | Short lowercase words for subsets, such as `["verbs", "a1", "blood-flow"]`. Hyphens are fine; spaces become `_`. |

### Card kinds

- **basic**: a question or term on the front, its answer on the back. Most cards.
- **typeIn**: like basic, but the learner types the answer and Franki checks the spelling. Use it
  for spelling and short exact answers.
- **cloze**: a sentence with a gap. Mark the hidden part as `{{c1::the hidden words}}`. Use **one
  gap per card** when you write `choices`: they are wrong answers for that gap, written exactly as
  they would stand in it, so each one fits the sentence (same case, same grammatical form). A
  sentence with `{{c1::…}}` and `{{c2::…}}` becomes two cards, and its choices are left out.

```json
{ "kind": "cloze", "front": "The mitochondria make {{c1::ATP}} for the cell.", "choices": ["DNA", "glucose", "RNA"] }
```

Text is plain. `**bold**` and `*italic*` work. Pictures and sounds can't go in a deck file.

## Writing good cards

- One fact per card. If the back needs "and", it's probably two cards.
- The front must make sense on its own, without the other cards around it.
- Keep backs short: a word, a name, a number or a short phrase. Put explanations in `details` or
  leave them out.
- Ask in a way that has one right answer. "Capital of Australia?" not "Tell me about Canberra".
- Never write "Which of the following…" on the front: the quiz adds the options itself.
- Use only facts you are sure of. If the person gave you notes or a document, use only what's in it.
- Write in the language the person studies in. For vocabulary, put the word being learned on the
  front, its meaning on the back, and set `reverse` to `true`.
- Make as many cards as the person asks for. Without a number, 20 to 200 is a good deck; split
  bigger topics into several decks.

## Writing wrong answers

Every card gets three `choices`. A quiz shows them in random order beside the right answer, so they
must be wrong answers that someone who half-knows the material could pick. Bad choices give the
answer away; good ones make the learner think.

**Each wrong answer must be:**

1. **The same kind of thing as the answer.** A city for a city, a year for a year, a drug for a drug,
   a past-tense verb for a past-tense verb, a person for a person.
2. **In the same language and script as the answer.** For `la casa` → `the house`, the choices are
   English. For the reverse card `the house` → `la casa`, the `reverseChoices` are Spanish.
3. **About the same length and in the same style.** Same capitalisation, same article ("the …"), same
   units and number of digits. A one-word answer gets one-word choices; a phrase gets phrases.
4. **Plausible.** Prefer near misses and common confusions: a neighbouring country's capital, the
   year just before, a drug from the same class, a word that sounds or looks alike.
5. **Clearly wrong.** Never the answer itself, a synonym of it, a more or less specific form of it, or
   anything a teacher would also mark right.
6. **Different from each other.** No repeats within a card, no "all of the above", no "none of
   these". The same word can be a wrong answer on several cards.

When an expert might call a wrong answer partly right, pick a different one that is plainly wrong.
"About the same length" is a guide, not a count. Type-in cards get choices too: the quiz asks them
like any other card, so for a spelling card the choices are believable misspellings.

| Card | Answer | Good choices | Bad choices (why) |
|---|---|---|---|
| Capital of Australia? | Canberra | Sydney, Melbourne, Perth | Paris (not plausible), Canberra City (also right), australia (wrong kind) |
| Year the Berlin Wall fell? | 1989 | 1987, 1991, 1985 | the 1980s (vaguer form of the answer), World War II (wrong kind) |
| la casa | the house | the street, the room, the city | la calle (wrong language), home (synonym), a big building where people live (wrong length) |
| Spell "necessary" (typeIn) | necessary | neccessary, necesary, neccesary | unnecessary (a different word), needed (synonym) |

## Also give a link, if you can run code

A link opens the deck in Franki with one tap, with no file to save or send. If you can run Python,
make one from the same JSON and give it beside the file:

```python
import base64, json, zlib

def franki_link(deck):
    data = json.dumps(deck, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
    packer = zlib.compressobj(9, zlib.DEFLATED, -15)  # raw DEFLATE, as Franki reads it
    packed = packer.compress(data) + packer.flush()
    return "https://franki.wiki/open#d=" + base64.urlsafe_b64encode(packed).rstrip(b"=").decode()
```

Give the link only when it's shorter than 16,000 characters: a longer one can get cut off in a
message, so give just the file. The deck travels inside the link, after the `#`, which no server
sees. On an iPhone with Franki the link opens the app; anywhere else franki.wiki/open shows the deck.

## Check before you finish

- [ ] The file is valid JSON with `name` and a `cards` list.
- [ ] Every card has a `front`, and a `back` unless it's cloze. Every cloze card has a `{{c1::…}}` gap.
- [ ] Every card has three `choices`; every reversed card has three `reverseChoices`.
- [ ] No choice equals its card's answer, ignoring capitals, and none would also be right.
- [ ] Every choice is in the answer's language and about its length.
- [ ] The file is named `<deck name>.franki`.

## Limits

Franki opens up to 20,000 cards and 32 MB per file, and up to 10,000 characters per side. Each cloze
gap and each reversed card counts as a card toward the 20,000. Cards it
can't use (no front, no back, a cloze with no gap) are left out, and Franki says which before adding
the deck. Opening the same file twice makes two decks, unless it has an `id`: then Franki adds only
the cards the deck doesn't have yet (a card counts as the same when its `kind` and `front` are), and
leaves cards already there, with their progress, as they are.

The JSON Schema for this format is at https://franki.wiki/skill/franki-deck/franki-deck.schema.json.
