Features • Companion • Firmware • Architecture • Format
InkCards is an open-source spaced-repetition flashcard app for the Xteink X4/X3 pocket e-reader. Study vocabulary, capitals, or any deck you like on a distraction-free e-ink screen with physical buttons, using the proven SM-2 algorithm.
It is built for the same hardware as, and lives happily alongside, CrossPoint Reader: it gets its device layer from inkkit and reuses CrossPoint's SD-card font system, so a single CJK font installed for CrossPoint also renders your Mandarin decks in InkCards.
On the device:
- Loads decks from the SD card at
/inkcards/decks/*.deck, a compact binary format optimised for streaming (documented indocs/FORMAT.md). - SM-2 spaced repetition with per-deck review state saved on the SD card.
- Four-button grading: Again / Hard / Good / Easy, mapped left to right to
the four front buttons (see
docs/BUTTON_MAPPING.md). - A session screen showing cards due today, new cards, cards reviewed and your study streak.
- Full Unicode including CJK, using CrossPoint's SD-card
.cpfontfonts rather than embedding fonts in flash. - A partial-refresh-friendly UI that repaints only the card area between cards.
On the desktop (the inkcards companion CLI):
inkcards convertturns Anki.apkgexports and plain CSV into.deckfiles, including optional pinyin handling for Chinese decks.inkcards statsreads review-state files off the SD card and prints your progress.
These are design mockups of the UI, generated from the layout in
firmware/src/ui/ by docs/images/screens/generate_screens.py. Real device
photos will replace them once captured on hardware (see
docs/HARDWARE_TESTING.md).
| Deck list | Reviewing a card | Answer + grades | Session summary |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Works with CrossPoint v1.5.x conventions: the SD-card font layout
(/.fonts or /fonts) and the .cpfont font format. InkCards reads those
fonts directly; it does not modify CrossPoint's files and can share the same SD
card. See ARCHITECTURE.md for how the two relate.
firmware/ ESP32-C3 firmware (PlatformIO)
lib/inkcards_core/ portable engine: deck format, SM-2, review state
src/ e-ink UI (device layer via inkkit)
selftest/ self-contained engine self-test firmware (CI-built)
test/ host unit tests for the engine
companion/ Python CLI: convert decks, read stats
decks/ sample decks and their CSV sources
docs/ format, button mapping, spaced repetition, hardware testing
Requires Python 3.9 or newer. No third-party dependencies.
cd companion
pip install -e .
# Convert a CSV of country,capital pairs into a deck.
inkcards convert my-capitals.csv -o world-capitals.deck --name "Capitals"
# Convert an Anki export, treating a Pinyin field specially.
inkcards convert HSK1.apkg -o hsk1.deck --name "HSK 1" --font-hint NotoSansSC
# See your progress from an inserted SD card.
inkcards stats --sd /Volumes/SDCARDThe three sample decks in decks/ are built from the CSVs in decks/src/ with:
python3 decks/build.pySD Card Root/
inkcards/
decks/
hsk1.deck
world-capitals.deck
demo.deck
.fonts/ (optional) CrossPoint-compatible CJK font for CJK decks
NotoSansSC/
NotoSansSC_16.cpfont
...
Copy .deck files into /inkcards/decks/. For CJK decks, install a
CJK-capable .cpfont family exactly as you would for CrossPoint (see
CrossPoint's
SD card fonts guide).
The device creates /inkcards/state/ for review progress on first use.
InkCards uses PlatformIO.
Three build environments are provided (see firmware/platformio.ini); run
them one at a time (concurrent pio invocations race on ~/.platformio):
-
selftest(default): a self-contained ESP32-C3 image that validates the deck engine over serial, with no device layer.cd firmware pio run -e selftest # build pio run -e selftest -t upload # flash over USB pio device monitor # watch the self-test report decks on your card
-
xteink_x4andxteink_x3: the full e-ink UI. The complete device layer comes from inkkit, pinned inplatformio.ini; no submodules or additional SDK setup. The rendering stack (GfxRenderer, EpdFont) is vendored underfirmware/lib/from CrossPoint Reader (MIT; seefirmware/lib/THIRD_PARTY.md). The two environments build identical firmware (the HAL detects X4 vs X3 at runtime) and exist so each target ships a named binary.cd firmware pio run -e xteink_x4 pio run -e xteink_x4 -t uploadStatus: builds in CI, not yet verified on device; see
docs/HARDWARE_TESTING.md.
Engine unit tests (host, no board or toolchain needed):
make -C firmware/testCompanion tests:
cd companion
pip install -e ".[dev]"
pytestARCHITECTURE.md: the fork-versus-standalone decision and the layered design.docs/FORMAT.md: the.deckand.revbinary formats.docs/BUTTON_MAPPING.md: the physical button layout.docs/SPACED_REPETITION.md: the SM-2 algorithm and grade mapping.docs/HARDWARE_TESTING.md: items to verify on a real device.CONTRIBUTING.md: how to build, test and contribute.CHANGELOG.md: release history.CODE_OF_CONDUCT.md: community expectations.SECURITY.md: how to report a vulnerability.
MIT. See LICENSE.



