A comprehensive Typst package for creating and managing exercises with solutions, metadata, filtering, and exercise banks. Perfect for teachers, textbook authors, and educational content creators.
Gallery
Click on an image to see the source code.
![]() |
![]() |
![]() |
| Basic Exercises | With Solutions | Exercise Bank |
![]() |
![]() |
![]() |
| Filtering by Topic | Competency Tags | Solutions at End |
![]() |
![]() |
![]() |
| Teacher Corrections | Mixed Display Mode | Draft Mode |
![]() |
![]() |
|
| Visual Styles | Solutions with Page Break |
Features
- Exercises with solutions - Create exercises with inline or deferred solutions
- 9 visual styles - Box, circled, filled-circle, pill, tag, border-accent, underline, rounded-box, header-card
- Customizable colors - Set badge colors for any style
- Teacher corrections - Add detailed corrections for teachers
- Flexible display modes - Control what to show (exercises, solutions, or both)
- Multiple location modes - Show solutions inline, after page break, or at end of section/chapter
- Draft mode - Show placeholders for empty corrections/solutions, or hide them for clean student output
- Metadata support - Tag exercises with topic, level, author, and custom fields
- Exercise banks - Define exercises once, display them anywhere
- Powerful filtering - Select exercises by topic, level, competency, or custom criteria
- Competency tags - Tag and display competency indicators
- Automatic numbering - Counter resets per section, chapter, or globally
- Customizable labels - Change “Exercise” and “Solution” labels (localization support)
- Exercise IDs - Unique identifiers for referencing and bank management
- Advanced exercise markers - Visual cue (customizable symbol) for advanced/challenging exercises
- g-exam integration - Optional integration with g-exam for exam-style formatting and features
Quick Start
#import "@preview/exercise-bank:0.4.0": exo
#exo(
exercise: [
Solve the equation $2x + 5 = 13$.
]
)
Basic Usage
Simple Exercise
#import "@preview/exercise-bank:0.4.0": exo
#exo(
exercise: [
Calculate $3 + 4 times 2$.
]
)
Exercise with Solution
#import "@preview/exercise-bank:0.4.0": exo
#exo(
exercise: [
Calculate $3 + 4 times 2$.
],
solution: [
$3 + 4 times 2 = 3 + 8 = 11$
],
)
Multiple Exercises
#import "@preview/exercise-bank:0.4.0": exo
#exo(exercise: [Simplify $x^2 + 2x + 1$.])
#exo(exercise: [Factor $x^2 - 4$.])
#exo(exercise: [Solve $2x - 6 = 0$.])
Display Control
The package uses three parameters to control how exercises and solutions are displayed:
show - What to Display
Controls what content is displayed:
"both"(default) - Show both exercises and solutions/corrections"ex"- Show only exercises (hide solutions/corrections)"sol"- Show only solutions/corrections (hide exercises)
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
// Student worksheet - exercises only
#exo-setup(display: "ex")
// Answer key - solutions only
#exo-setup(display: "sol")
// Complete document - both
#exo-setup(display: "both")
corr-display - What Content to Show
Controls whether to show solutions or corrections:
"solution"(default) - Show the solution content"correction"- Show the correction content (for teachers)"mixed"- Default to solution, but show correction for exercises withshow-corr: true
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
// Student version - show solutions
#exo-setup(corr-display: "solution")
// Teacher version - show corrections
#exo-setup(corr-display: "correction")
// Mixed mode
#exo-setup(corr-display: "mixed")
#exo(
exercise: [Solve $x^2 = 9$.],
solution: [$x = plus.minus 3$],
correction: [Detailed explanation with teaching notes...],
show-corr: true, // In mixed mode, show correction for this exercise
)
corr-loc - Where to Display
Controls where solutions/corrections appear:
"after"(default) - Show immediately after each exercise"pagebreak"- Show with a page break between exercise and solution"end-section"- Collect and show at section end"end-chapter"- Collect and show at chapter end
#import "@preview/exercise-bank:0.4.0": exo, exo-setup, exo-print-solutions
// Solutions at end of section
#exo-setup(corr-loc: "end-section")
#exo(exercise: [Exercise 1], solution: [Answer 1])
#exo(exercise: [Exercise 2], solution: [Answer 2])
// Print all collected solutions
#exo-print-solutions(title: "Answers")
Corrections (Teacher Version)
Corrections are detailed solutions for teachers, including pedagogical notes and teaching tips.
Exercise with Correction
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
#exo-setup(corr-display: "correction")
#exo(
exercise: [Solve $x^2 = 9$.],
correction: [
*Teacher's notes:*
$x = plus.minus 3$
Common mistake: Students often forget the negative root.
],
)
Corrections Only (Teacher Answer Key)
Create teacher answer keys showing only corrections:
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
#exo-setup(
display: "sol", // Only show solutions/corrections
corr-display: "correction", // Show corrections
)
#exo(
exercise: [Exercise 1 (hidden in output)],
correction: [Detailed correction for teachers],
)
Mixed Display Mode
Use corr-display: "mixed" to default to solutions while showing corrections for specific exercises:
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
#exo-setup(corr-display: "mixed")
// This shows solution (default)
#exo(
exercise: [Simple problem],
solution: [Quick answer],
correction: [Detailed explanation],
)
// This shows correction (because show-corr: true)
#exo(
exercise: [Complex problem needing explanation],
solution: [Answer],
correction: [Detailed step-by-step solution with notes],
show-corr: true,
)
Exercise-Level Flags
show-corr: true- In “mixed” mode, show correction instead of solution for this exercisesol-in-corr: true- Indicates that the correction already includes the solution; in “correction” mode, only correction is shown (not both correction AND solution)
Draft Mode and Placeholders
When creating exercise documents, you may have incomplete corrections or solutions. Draft mode allows you to:
- Show placeholder text for empty corrections/solutions (useful for teacher drafts)
- Maintain exercise counters even with empty content
- Hide placeholders in student versions
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
// Teacher draft version - shows placeholders
#exo-setup(
draft-mode: true,
correction-placeholder: [_[To be completed]_],
solution-placeholder: [_[Answer to be written]_],
)
#exo(
exercise: [Solve $x + 5 = 12$],
solution: [], // Empty - shows placeholder in draft mode
)
// Student version (draft mode OFF)
#exo-setup(draft-mode: false)
#exo(
exercise: [Solve $x + 5 = 12$],
solution: [], // Empty - shows only space, no placeholder
)
Metadata and Filtering
Adding Metadata
Tag exercises with metadata for organization and filtering:
#import "@preview/exercise-bank:0.4.0": exo
#exo(
exercise: [Solve $x + 1 = 5$.],
topic: "algebra",
level: "easy",
authors: ("Prof. Smith",),
)
Filtering Exercises
Display only exercises matching certain criteria:
#import "@preview/exercise-bank:0.4.0": exo, exo-filter
// First, define exercises (they display normally)
#exo(exercise: [Exercise 1], topic: "algebra")
#exo(exercise: [Exercise 2], topic: "geometry")
#exo(exercise: [Exercise 3], topic: "algebra")
// Later, filter and redisplay specific exercises
#exo-filter(topic: "algebra") // Shows exercises 1 and 3
Exercise Banks
Define exercises once, use them anywhere. Perfect for creating exercise collections.
Defining Bank Exercises
#import "@preview/exercise-bank:0.4.0": exo-define
// These don't display - just registered
#exo-define(
id: "quad-1",
exercise: [Solve $x^2 - 5x + 6 = 0$.],
topic: "quadratics",
level: "1M",
solution: [$x = 2$ or $x = 3$],
)
#exo-define(
id: "geom-1",
exercise: [Find the area of a circle with radius 5.],
topic: "geometry",
level: "1M",
solution: [$A = pi r^2 = 25pi$],
)
Displaying Bank Exercises
#import "@preview/exercise-bank:0.4.0": exo-show, exo-show-many
// Show a single exercise by ID
#exo-show("quad-1")
// Show multiple exercises
#exo-show-many("quad-1", "geom-1", "quad-2")
Selecting from Bank
Use powerful filtering to select exercises:
#import "@preview/exercise-bank:0.4.0": exo-select
// All quadratics exercises
#exo-select(topic: "quadratics")
// Level 1M exercises only
#exo-select(level: "1M")
// Multiple topics
#exo-select(topics: ("quadratics", "geometry"))
// Limit number of exercises
#exo-select(topic: "algebra", max: 5)
// Custom filter function
#exo-select(where: ex => ex.metadata.level == "hard")
Competency Tags
Tag exercises with competencies and display them visually:
#import "@preview/exercise-bank:0.4.0": exo-define, exo-show, exo-setup
#exo-setup(show-competencies: true)
#exo-define(
id: "comp-ex-1",
exercise: [Solve and explain your reasoning.],
competencies: ("C1.1", "C2.3", "C4.1"),
solution: [Solution here],
)
#exo-show("comp-ex-1")
Filter by Competency
#import "@preview/exercise-bank:0.4.0": exo-select
// Exercises with specific competency
#exo-select(competency: "C1.1")
// Exercises with any of these competencies
#exo-select(competencies: ("C1.1", "C2.3"))
Configuration
Global Setup
#import "@preview/exercise-bank:0.4.0": exo-setup
#exo-setup(
// Display control
display: "both", // "ex", "sol", "both"
corr-display: "solution", // "solution", "correction", "mixed"
corr-loc: "after", // "after", "pagebreak", "end-section", "end-chapter"
// Labels
exercise-label: "Exercise",
solution-label: "Solution",
correction-label: "Correction",
// Counter behavior
counter-reset: "section", // "section", "chapter", "global"
// Display options
show-metadata: false,
show-id: false,
show-competencies: false,
// Draft mode
draft-mode: false,
correction-placeholder: [_To be completed_],
solution-placeholder: [_To be completed_],
// Spacing
exercise-above: 0.8em,
exercise-below: 0.8em,
solution-above: 0.8em,
solution-below: 0.8em,
correction-above: 0.8em,
correction-below: 0.8em,
// Advanced exercises
advanced-symbol: "*",
)
Localization
Change labels for different languages:
#import "@preview/exercise-bank:0.4.0": exo-setup
// French
#exo-setup(
exercise-label: "Exercice",
solution-label: "Solution",
correction-label: "Corrigé",
)
// German
#exo-setup(
exercise-label: "Aufgabe",
solution-label: "Lösung",
)
Visual Styles
Choose from 9 different badge styles:
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
// Circled number style
#exo-setup(badge-style: "circled")
// Filled circle with custom color
#exo-setup(badge-style: "filled-circle", badge-color: rgb("#2563eb"))
// Tag style
#exo-setup(badge-style: "tag", badge-color: rgb("#1e40af"))
// Custom colors for solutions and corrections
#exo-setup(
solution-color: rgb("#059669"), // Green for solutions
correction-color: rgb("#dc2626"), // Red for corrections
)
#exo(exercise: [Solve $x + 3 = 7$])
Available styles: "box" (default), "circled", "filled-circle", "pill", "tag", "border-accent", "underline", "rounded-box", "header-card"
Counter Reset Options
Control when exercise numbering resets:
#import "@preview/exercise-bank:0.4.0": exo-setup, exo-section-start, exo-chapter-start
// Reset at each section
#exo-setup(counter-reset: "section")
= Section 1
#exo-section-start()
// Reset at each chapter
#exo-setup(counter-reset: "chapter")
= Chapter 1
#exo-chapter-start()
// Never reset (global numbering)
#exo-setup(counter-reset: "global")
Show Exercise IDs
Display exercise IDs for reference:
#import "@preview/exercise-bank:0.4.0": exo-setup, exo
#exo-setup(show-id: true)
#exo(
id: "my-exercise",
exercise: [
This exercise shows its ID below the badge.
]
)
Advanced Exercises
Mark exercises as advanced to display a visual cue before the label:
#import "@preview/exercise-bank:0.4.0": exo, exo-setup
// Default symbol is "*"
#exo(
exercise: [This is a challenging problem.],
advanced: true,
)
// Use a custom symbol
#exo-setup(advanced-symbol: sym.dagger)
#exo(exercise: [Advanced with dagger.], advanced: true)
// Disable the feature
#exo-setup(advanced-symbol: none)
Utility Functions
Reset Counter
#import "@preview/exercise-bank:0.4.0": exo-reset-counter
#exo-reset-counter() // Reset exercise numbering to 0
Clear Registry
#import "@preview/exercise-bank:0.4.0": exo-clear-registry
#exo-clear-registry() // Clear all registered exercises
Count Exercises
#import "@preview/exercise-bank:0.4.0": exo-count
Total algebra exercises: #exo-count(topic: "algebra")
Level 1M exercises: #exo-count(level: "1M")
Parameters Reference
exo Function
| Parameter | Type | Default | Description |
|---|---|---|---|
exercise |
content | none | Exercise content (named parameter) |
solution |
content | none | Solution content |
correction |
content | none | Correction content (teacher version) |
id |
string/auto | auto | Unique exercise ID |
sol-in-corr |
bool | false | If true, solution is in correction (show only correction, not both) |
show-corr |
bool | false | If true, show correction in “mixed” mode |
topic |
string | none | Topic metadata |
level |
string | none | Difficulty level |
authors |
array | () | Array of author names |
..extra |
named | - | Additional metadata fields |
exo-define Function
| Parameter | Type | Default | Description |
|---|---|---|---|
exercise |
content | none | Exercise content (named parameter) |
solution |
content | none | Solution content |
correction |
content | none | Correction content (teacher version) |
id |
string/auto | auto | Unique exercise ID |
competencies |
array | () | List of competency tags |
sol-in-corr |
bool | false | If true, solution is in correction (show only correction) |
show-corr |
bool | false | If true, show correction in “mixed” mode |
topic |
string | none | Topic metadata |
level |
string | none | Difficulty level |
authors |
array | () | Array of author names |
..extra |
named | - | Additional metadata fields |
exo-select Function
| Parameter | Type | Default | Description |
|---|---|---|---|
topic |
string | none | Filter by exact topic |
level |
string | none | Filter by exact level |
author |
string | none | Filter by exact author |
competency |
string | none | Filter by single competency |
topics |
array | none | Filter by any of these topics |
levels |
array | none | Filter by any of these levels |
competencies |
array | none | Filter by any of these competencies |
where |
function | none | Custom filter function |
show-solutions |
bool/auto | auto | Override solution display |
renumber |
bool | true | Renumber exercises sequentially |
max |
int | none | Maximum exercises to show |
exo-setup Function
| Parameter | Type | Default | Description |
|---|---|---|---|
display |
string | “both” | “ex”, “sol”, “both” |
corr-display |
string | “solution” | “solution”, “correction”, “mixed” |
corr-loc |
string | “after” | “after”, “pagebreak”, “end-section”, “end-chapter” |
solution-label |
string | “Solution” | Label for solutions |
correction-label |
string | “Correction” | Label for corrections |
exercise-label |
string | “Exercise” | Label for exercises |
counter-reset |
string | “section” | “section”, “chapter”, “global” |
show-metadata |
bool | false | Display metadata |
show-id |
bool | false | Display exercise ID |
show-competencies |
bool | false | Display competency tags |
draft-mode |
bool | false | Show placeholders for empty content |
correction-placeholder |
content | [_To be completed_] |
Placeholder for empty corrections |
solution-placeholder |
content | [_To be completed_] |
Placeholder for empty solutions |
badge-style |
string | “box” | Visual style for badges |
badge-color |
color | black | Color for exercise badges |
solution-color |
color | green | Color for solution badges |
correction-color |
color | green | Color for correction badges |
exercise-above |
length | 0.8em | Space above exercise boxes |
exercise-below |
length | 0.8em | Space below exercise boxes |
solution-above |
length | 0.8em | Space above solution boxes |
solution-below |
length | 0.8em | Space below solution boxes |
correction-above |
length | 0.8em | Space above correction boxes |
correction-below |
length | 0.8em | Space below correction boxes |
advanced-symbol |
content/none | “*” | Symbol for advanced exercises |
Complete Example
#import "@preview/exercise-bank:0.4.0": *
// Setup
#exo-setup(
corr-loc: "end-section",
show-competencies: true,
)
= Algebra Exercises
// Define exercises in a bank
#exo-define(
id: "alg-1",
exercise: [Solve $2x + 5 = 13$.],
topic: "equations",
level: "easy",
competencies: ("C1.1",),
solution: [$x = 4$],
)
#exo-define(
id: "alg-2",
exercise: [Solve $x^2 = 9$.],
topic: "equations",
level: "medium",
competencies: ("C1.1", "C1.2"),
solution: [$x = 3$ or $x = -3$],
)
#exo-define(
id: "alg-3",
exercise: [Solve $3x - 1 > 5$.],
topic: "inequalities",
level: "medium",
competencies: ("C1.3",),
solution: [$x > 2$],
)
// Display exercises for this section
#exo-select(level: "easy")
#exo-select(level: "medium", max: 2)
// Print solutions at end of section
#exo-print-solutions(title: "Answers")
Integration with g-exam
The exercise-bank package includes optional integration with the g-exam package for creating exams. The core exercise functionality works completely standalone, but if you want to create exam-style documents, the integration provides additional features.
Using Exam Mode
Set the display mode to “exam” to use g-exam formatting:
#import "@preview/exercise-bank:0.4.0": *
// Define exercises with points
#exo-define(
id: "exam-q1",
exercise: [Solve $2x + 5 = 13$.],
points: 3,
solution: [$x = 4$],
)
// Configure for exam display
#exo-setup(display-mode: "exam")
#exam-setup(show-solutions: false) // Hide solutions for student version
// Display as exam questions
#exo-show("exam-q1")
Dependencies
- g-exam (v0.4.4+) - Optional, only needed if using exam mode integration features
License
MIT License - see LICENSE file for details.
Changelog
[0.4.0] - 2026-02-11
Changed (Breaking)
-
New display control system: Replaced
solution-mode,fallback-to-correction, andappend-solution-to-correctionwith three clearer parameters:display: Controls what to display -"ex"(exercises only),"sol"(solutions only),"both"(default)corr-display: Controls which content type to show -"solution"(default),"correction","mixed"corr-loc: Controls where solutions appear -"after"(default),"pagebreak","end-section","end-chapter"
-
New exercise-level flags:
sol-in-corr: If true, correction already contains solution (show only correction, not both)show-corr: If true, show correction in “mixed” mode for this exercise
Removed
solution-modeparameter (replaced byshowandcorr-loc)fallback-to-correctionparameter (behavior controlled bycorr-display)append-solution-to-correctionparameter (usecorr-display: "mixed"instead)solution-in-correction-styleparameter (no longer needed)
Migration Guide
| Old Parameter | New Equivalent |
|---|---|
solution-mode: "inline" |
display: "both", corr-loc: "after" (default) |
solution-mode: "none" |
display: "ex" |
solution-mode: "only" |
display: "sol" |
solution-mode: "end-section" |
corr-loc: "end-section" |
solution-mode: "end-chapter" |
corr-loc: "end-chapter" |
fallback-to-correction: true |
corr-display: "correction" |
append-solution-to-correction: true |
corr-display: "mixed" with show-corr: true on exercises |
[0.3.0] - 2026-01-27
Added
- 9 visual badge styles: Configure with
exo-setup(badge-style: "...") - Badge color customization:
exo-setup(badge-color: rgb("#2563eb")) - Separate solution/correction colors
- Advanced exercise markers:
advanced-symbolparameter - Spacing control: Independent spacing for exercises, solutions, and corrections
[0.2.0] - 2026-01-15
Changed (Breaking)
exofunction: Content parameter changed from positional to named parameterexercise:exo-definefunction: Content parameter changed from positional to named parameterexercise:- Author metadata: Changed from single
authortoauthorsarray
[0.1.0] - 2026-01-13
- Initial release










