Universe

Create project in app

Double-sided flash cards that line up when printed. Write the questions and answers, print the PDF double-sided, cut along the lines: every card has its question on the front and its answer on the back.

A sheet of DIN A8 cards

  • Any card size: DIN A8, A7, A6, A5, US index cards (3×5, 4×6 in), business cards on perforated sheets, or your own size; A4 or Letter paper; landscape or upright cards.
  • A list to check the cards: every card on one row, question and answer side by side, exactly as printed.
  • A calibration sheet to make up for printers that shift the back side.
  • Cards from a CSV file, e.g. a word list from Excel.
  • Header and footer with three slots each: logo, theme, card number, …
  • Coloured stripes per theme, to sort the cut cards.
  • Text that is too large is shrunk to fit, and marked in the list.
  • Reprint single cards without the rest of the deck.
  • Both directions (dir: "both"), several items (all, any) and hints shown only as question or only as answer ([? …], [! …]), e.g. for vocabulary.

The manual (PDF, attached to each release) explains everything, with many examples.

Needs Typst 0.15.0 or newer.

Getting started

#import "@preview/flipside:0.2.1": *

#flipside((
  (q: [France], a: [Paris]),
  (q: [Germany], a: [Berlin]),
  (q: [Which country has \ two capital cities?], a: [Bolivia \ #small[(Sucre and La Paz)]]),
))

or start from the template:

typst init @preview/flipside:0.2.1 my-cards

Page 1 holds the questions with cutting lines, page 2 the answers, mirrored so that each answer lands behind its question. Print all pages double-sided at 100 %: flip on short edge for a landscape sheet, flip on long edge for a portrait sheet.

Checking the cards

typst compile --input layout=list cards.typ cards-list.pdf

The list

#let number(c) = if c.number != none [#c.number/#c.total]

#flipside(
  header: (left: image("logo.png", width: 19mm), right: [Geography · 7a]),
  footer: (left: c => c.theme, right: number),
  back-footer: (right: c => text(fill: gray, number(c))),
  stripe: auto,
  (
    (theme: "Europe"),          // no card: the theme of the cards below
    (q: [France], a: [Paris]),
    (theme: "Asia"),
    (q: [Japan], a: [Tokyo]),
  ),
)

A slot is content, or a function that gets the card (c.theme, c.number, c.total, …). header/footer are the question side, back-header/back-footer the answer side.

Cards from a CSV file

#flipside(lang: (q: "de", a: "fr"), csv("words.csv", row-type: dictionary))
q,a,theme
der Verkäufer,"le vendeur
la vendeuse",Berufe
der Sänger,le chanteur,

Columns q and a, any other column becomes a field; an empty cell keeps the value above; a line break in a cell is a line break on the card.

Both directions, items and hints

#flipside(
  lang: (q: "de", a: "fr"),
  dir: "both",                                           // every card both ways
  (
    (q: [laut [? (m/f)]], a: [bruyant, bruyante]),
    (q: [der Lift, [? ein Lift]], a: [l'ascenseur, [! un ascenseur]]),
    (q: [der Kühlschrank], a: any[le réfrigérateur][le frigo]),
    (q: [die Möbel #q-note[Plural]], a: all[les meubles][le mobilier]),
  ),
)
  • [? …] is shown only when its side is asked, [! …] only when it is the answer (#q-only[…] / #a-only[…] for maths or bold).
  • all[…][…]: as the question one card, as the answer all needed; any[…][…]: as the question one card per item, as the answer any one right.
  • #note[…], #q-note[…], #a-note[…]: notes on a line of their own.

Card sizes

card: Card Paper Per sheet
"DIN A8" (default) 74 × 52 mm A4 16
"DIN A7" 105 × 74 mm A4 8
"DIN A6" 148 × 105 mm A4 4
"DIN A5" 210 × 148 mm A4 2
"US 3x5" 5 × 3 in Letter 4
"US 4x6" 6 × 4 in Letter 2
"US business" 3.5 × 2 in Letter 10
"EU business" 85 × 54 mm A4 10
(width: 90mm, height: 60mm) your own A4 as many as fit

paper: "us-letter" (or "a4", "a3", "a5", "us-legal") changes the paper, orientation: "portrait" makes the cards upright. Your own size can also give cols, rows, gap and margin to match a perforated sheet.

Printing

  • Back side shifted? Print the calibration sheet (--input layout=calibrate), hold it against the light, read the values on the rulers and set back-offset: (x: 0.8mm, y: -0.5mm).
  • Reprint lost cards: --input only=5-12,17; the numbers stay those of the whole deck.

Everything that changes between printouts can be chosen when compiling, and wins over the file: --input layout=…, card=…, paper=…, orientation=…, only=…, back-offset=…, dir=….

Parameters

Parameter Default
cards — (q: […], a: […]), entries with fields only, (q: [], a: []) for a blank card, CSV rows
header, footer, back-header, back-footer (:) slots (left:, center:, right:)
title none name of the deck, in the list’s footer
lang "en" "fr" or (q: "de", a: "fr")
font, size New Computer Modern, 13 pt text of the cards
slot-font, slot-size New Computer Modern, 7 pt text of the slots
back-borders false outline the answer cards too
fit true shrink a side that is too large
stripe, stripe-width none, 2.5 mm auto, ("Theme": colour) or c => colour
markup false read CSV cells as Typst markup
back-offset (x: 0mm, y: 0mm) shift of the answer pages
only none "5-12,17", (3, 8) or c => bool
layout "cards" "cards", "list", "calibrate", "report" (for the MyCards app)
dir "forward" "reverse" or "both"; a card’s own dir wins
count n => [(n)] shown on the question when more than 2 items are needed
card, paper, orientation "A8", auto, "landscape" see Card sizes

Helpers: small[…] (72 %), tiny[…] (60 %), block-left[…] (left-aligned, justified).

Examples

The examples folder of the repository holds complete decks: a German–French vocabulary from CSV learnt both ways with hints, maths with formulas, chemical elements on business-card sheets, US index cards, upright cards of your own size.

Development

Tests, the manual’s sources and how a version is released: see CONTRIBUTING.md in the repository.

Author and license

Frank Fasbender, ffasbend@gmail.com · github.com/ffasbend/flipside (questions, ideas and bug reports: please open an issue).

MIT, © 2026 Frank Fasbender (LICENSE). The template (template/, the files typst init copies into your project) is under MIT-0 (LICENSE-MIT-0): use and share your decks made from it without any notice.