Warning
ankify is in alpha and under active development. Expect bugs, rough edges,
and breaking changes between releases.
Ankify lets you take notes in Typst the way you normally would and, with very little extra effort, generate an Anki flashcard for each definition, theorem, lemma — whatever you like.
The trick: you write a small helper function that both typesets an item in your notes and registers a flashcard for it. Define it once, and every definition or theorem in your document becomes a card.
The project has two parts:
- The
ankifyTypst package — providesconfigure()andnote(). Callingnote()records a flashcard as document metadata; it produces no visible output, so you call it from inside your own helpers. - The
ankifyCLI — reads a.typfile, renders each note's fields, and pushes them to Anki through the AnkiConnect add-on.
When you run ankify notes.typ, the CLI:
- queries the document for note metadata and configuration;
- renders each note field — to an image, so math and formatting survive;
- sends
addNotes/updateNoterequests to AnkiConnect; - records what it pushed in a cache (
.ankify/cache.json), so the next run only syncs notes that were added or changed.
flowchart TD
doc["Typst document:<br/>configure() + note() calls"]
subgraph cli ["ankify CLI"]
direction TB
meta["Document metadata:<br/>config + one entry per note"]
tmp["Temp render file:<br/>one page per note field"]
fields["Rendered fields:<br/>svg, png, or plain text"]
notes["Anki notes:<br/>one per note() call"]
reqs["AnkiConnect requests:<br/>addNotes / updateNote JSON"]
meta -->|generate| tmp
tmp -->|typst compile| fields
fields -->|assemble| notes
notes -->|diff against cache| reqs
end
cache[("Sync cache:<br/>.ankify/cache.json")]
anki["Anki"]
doc -->|typst query| meta
cache -.-> reqs
reqs -->|send| anki
anki -.->|record sync| cache
- Anki, running, with the AnkiConnect add-on installed.
- The Typst CLI (
typst) on yourPATH. - A Rust toolchain, to build the CLI.
Until ankify is published to the Typst Universe, install it locally so it can
be imported as @preview/ankify:0.1.0. Copy packages/ankify-typst/ into your
Typst package directory:
# macOS
DEST="$HOME/Library/Application Support/typst/packages/preview/ankify/0.1.0"
# Linux: ~/.local/share/typst/packages/preview/ankify/0.1.0
# Windows: %APPDATA%\typst\packages\preview\ankify\0.1.0
mkdir -p "$DEST" && cp -r packages/ankify-typst/* "$DEST"cargo install --path packages/ankify-cli
# or: cargo build --release -> ./target/release/ankify#import "@preview/ankify:0.1.0": note, configure
#configure(defaults: (deck: "My Course"))
#note(
"pythagoras",
data: (Front: "Pythagorean theorem?", Back: [$a^2 + b^2 = c^2$]),
)Start Anki, then run:
ankify notes.typnote() shines when wrapped in a helper that also renders the item. Define a
definition / theorem helper once, then every use of it becomes a card:
#import "@preview/ankify:0.1.0": note, configure
#configure(defaults: (deck: "Analysis", tags: ("analysis",)))
#let definition(label, term, body) = {
note(label, data: (Front: [Define: #term], Back: body))
block(inset: 8pt, stroke: 0.5pt)[*Definition (#term).* #body]
}
= Lecture 3: Continuity
#definition("def-continuity", "continuity")[
A function $f$ is continuous at $a$ if $lim_(x -> a) f(x) = f(a)$.
]Take notes as usual; each definition(...) both typesets the definition and
produces a flashcard.
A complete, runnable version of this pattern lives in demo/ — a short
lecture that compiles to a PDF and syncs to Anki.
| Parameter | Meaning | Default |
|---|---|---|
| label (positional) | Unique identifier; the sync key for the card. | — |
data |
Dictionary of Anki field name → content/string. | — |
deck |
Target Anki deck. | "Default" |
model |
Anki note type. | "Basic" |
tags |
Array of tag strings. | () |
format |
How fields render: "png", "svg", or "plain". |
"svg" |
other |
Extra metadata passed through to AnkiConnect. | none |
render |
Function transforming each field before it is rendered (advanced). | identity |
A field's value may be a string, Typst content, or a (value, format)
dictionary to override the format per field.
plain— the field is sent to Anki as plain text.svg(the default) — the field is rendered to SVG and inlined into the card. Crisp, scalable, and theme-aware (see Dark mode below).png— the field is rendered to a raster image and attached as media. Use it for genuinely raster content.
Use plain for short text answers and svg/png for anything with math or
formatting.
svg cards adapt to your Anki theme automatically. They render with a
transparent background and a currentColor foreground, so they take on the
card's own colours and follow Anki's light/dark mode with no extra setup.
png cards are not theme-aware — a raster image can't recolour itself — so
prefer svg if you review in dark mode.
Optional — call it once near the top of the document.
#configure(
ankiconnect-url: "http://127.0.0.1:8765",
verbose: true,
scale: 1.5,
defaults: (deck: "My Course", model: "Basic", tags: ("lecture",), format: "svg"),
)scale enlarges every rendered card image (default 1.5) — raise it if your
cards look too small, lower it towards 1.0 if they look too big. If you omit
configure() entirely, built-in defaults are used.
Run ankify notes.typ again whenever you add or edit notes. Thanks to the
cache, unchanged notes are skipped, edited notes are updated, and new notes are
added. Renaming a note's label is recognised as a rename when its content is
otherwise unchanged, so the existing card is updated in place rather than
duplicated; a label that disappears from the document is reported as a warning,
its Anki note left untouched. (Changing a note's deck is not migrated —
AnkiConnect cannot move an existing card between decks.)
ankify <FILE> [options]
-v, --verbose Verbose output
--cache-file <PATH> Custom cache file location
--ankiconnect-url <URL> AnkiConnect URL (default: http://127.0.0.1:8765)
--root <DIR> Typst project root
--font-path <PATH> Additional font path (repeatable)
| Path | What |
|---|---|
packages/ankify-typst/ |
The ankify Typst package (note, configure). |
packages/ankify-cli/ |
The ankify CLI and library crate. |
demo/ |
A runnable example: a lecture that becomes an Anki deck. |
MIT — see LICENSE.
Anki is a trademark of Ankitects Pty Ltd. Ankify is an independent project, not affiliated with, endorsed by, or sponsored by Ankitects Pty Ltd.