Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

Cardagain is a Rust application using SDL2 for rendering and input. It’s designed for simplicity and low resource usage on handheld devices.

Project structure

src/
├── main.rs       # Entry point: SDL2 init, panic hooks, main loop
├── app.rs        # Screen state machine (MainMenu → DeckSelect → Study → Stats)
├── data.rs       # Card, Deck, Review models + SM-2 scheduler
├── import.rs     # CSV/JSON deck import logic
├── input.rs      # Keyboard + gamecontroller input mapping
├── render.rs     # SDL2 canvas, font rendering, UI primitives
└── study.rs      # Study session state machine (Front → Flip → Rate)

fonts/            # Bundled fonts (copied into release zip)
gameinfo.xml      # EmulationStation metadata

scripts/
├── build-aarch64.sh      # Cross-compile script
├── docker-build.sh       # Docker-based aarch64 build
├── Dockerfile.build      # Ubuntu 20.04 + SDL2 build image
└── package-tools.sh      # Create release zip

book.toml             # mdbook configuration
justfile              # Build recipes (native, aarch64, package)

Data flow

Startup
  → Load data.json (or create demo deck)
  → Scan for .csv/.json deck files
  → Import new decks
  → Save data.json

Main loop (60 FPS)
  → Poll input (keyboard + controller)
  → Update app state
  → Render current screen
  → Sleep to cap at ~30 FPS (save battery)

Study session
  → Build due card queue (new first, then by due date)
  → Show front → wait for flip
  → Show back → wait for rating
  → Apply SM-2 schedule
  → Save after each rating

Key design decisions

  • No allocations in hot path: Textures are recreated per frame (simple but not optimal; acceptable for a flashcard app)
  • Immediate-mode UI: No widget tree; draw calls happen directly in draw_* methods
  • Blocking save: data.json is rewritten synchronously after each rating. Cards are small; this is fast enough
  • No threading: Single-threaded; SDL2 event pump drives everything

Screen state machine

[MainMenu] --A(Study)--> [DeckSelect] --A(start session)--> [Study]
                                          B(back)                 |
                                                                   |
[MainMenu] <----------------------B(abandon)----------------------|
      |                                                             |
      |----------------A(Stats)----------------> [Stats] <---------|

Memory usage

Typical footprint on RG35XXSP:

ComponentSize
Binary~500 KB
Heap (fonts + textures)~5-10 MB
Data (1000 cards)~200 KB JSON
Total< 20 MB

Well within the RG35XXSP’s 1GB RAM.