Generate printable math worksheets — with answer keys — for kindergarten through grade 12.
Worksheets are typeset by real LaTeX: a build of pdfTeX compiled to WebAssembly that runs entirely in your browser. There is no server, no upload and no account. The site is plain static files, so it works from GitHub Pages, and once the engine is cached it works offline.
This is the web version of the Math PDF Generator I made in Python.
The previous version drew each worksheet with jsPDF, one text call at a time. That meant
hand-rolled line wrapping, ASCII stand-ins for real notation (pi, x, /), and layout that
had to be nudged by hand. LaTeX does the typesetting properly:
| Before (jsPDF) | Now (pdfTeX) | |
|---|---|---|
| Fractions | 3/4 |
genuine stacked fractions |
| Radicals | sqrt(144) |
√144 with a real vinculum |
| Multiplication | x |
× |
| Degrees, π, θ, ≤ | spelled out in ASCII | typeset as symbols |
| Line breaking | custom, with a 65% width fudge for a known jsPDF bug | TeX's paragraph breaker |
| Output | one hard-coded layout | a LaTeX document you can read, copy and adapt |
Every preview also shows the generated LaTeX source, so a worksheet can be taken into Overleaf and edited further.
- Grades 1-12, following the Ontario mathematics curriculum (2020 for Grades 1-8, MTH1W and the senior courses above that)
- Nine subjects mapped to the Ontario strands: Number, Algebra, Data & Probability, Geometry, Measurement, Financial Literacy, Trigonometry, Advanced Functions and Calculus — 90 topics in all
- Topics are filtered to the grade that teaches them, so a Grade 3 worksheet cannot offer integers and a Grade 11 one is not padded with counting
- Per-topic customisation: open a topic to set its number range, denominators, decimal places, exponents, whether negatives or remainders are allowed, and more
- Equation pages, word-problem pages, or an alternating mix
- Optional answer key, name/date/score/grade fields, page border, circled question numbers, configurable page numbers, Letter or A4
- Generate many worksheets at once — each gets its own problems, and they download as a ZIP
- Runs offline after the first visit; nothing you type leaves your machine
Everything about what a worksheet can contain is data, under js/curriculum/:
| Path | What it holds |
|---|---|
gradeLevels/gradeN.js |
one grade: its subjects, number ceiling and Ontario course code |
subjects/*.js |
topics, each declaring its strand, the grades that teach it, and its parameters |
config/grades.js |
grade ids, ranges and the Ontario strand names |
config/parameters.js |
the parameter definitions topics draw on, with their limits |
templates/wordProblems.js |
the contextual word-problem templates |
templates/gradeProblems.js |
per-grade equation and word-problem draws |
templates/financialProblems.js |
the Financial Literacy strand |
Adding a topic means adding an entry, not editing a generator. tools/check-curriculum.mjs
typesets a worksheet for every grade, subject and difficulty to prove the whole
matrix still compiles.
The app uses ES modules and a web worker, so it needs to be served over HTTP.
npm start # serves the repository on http://localhost:8000
npm test # unit tests for the LaTeX and ZIP layers
npm run sample # typeset a sample worksheet to .cache/sample.pdfNothing is installed: npm start and npm test use only Node's standard library.
form options ──▶ problemGenerator ──▶ worksheet.js ──▶ .tex ──▶ pdfTeX (WASM) ──▶ PDF ──▶ ZIP
(curriculum data) (escape.js) in a Web Worker
| Path | What lives there |
|---|---|
js/curriculum/ |
grades, subjects, topics, parameters and problem templates |
js/modules/problemGenerator.js |
problem generation and de-duplication |
js/latex/escape.js |
text and expressions → LaTeX (fractions, radicals, symbols) |
js/latex/worksheet.js |
builds the LaTeX document from the form options |
js/latex/engine.js |
promise API over the pdfTeX worker |
js/modules/zip.js |
a small ZIP writer, so no ZIP library is needed |
vendor/swiftlatex/ |
the pdfTeX WebAssembly engine and its worker |
vendor/texlive/ |
the slice of TeX Live the worksheets need |
tools/ |
build, test and dev-server scripts |
pdfTeX needs article.cls, the AMS packages, font metrics and Type 1 outlines at run time.
Upstream SwiftLaTeX fetched these one at a time from a hosted service that no longer exists,
so this repository ships them instead: tools/build-texlive.mjs downloads the upstream
packages from CTAN, builds the pdfLaTeX format dump with the same WebAssembly engine the
browser runs, and packs everything into one gzipped archive
(vendor/texlive/texlive.bundle.gz, about 5.7 MB compressed).
The browser fetches that archive once, keeps it in the HTTP cache, and answers every one of pdfTeX's file lookups from memory. Typesetting a worksheet then takes roughly a quarter of a second.
Re-run the build only when the document template gains a dependency:
npm run build:texlive- The first visit downloads about 7 MB (engine plus TeX bundle). After that it is cached.
- Generating dozens of worksheets takes a few seconds each — they are typeset one at a time.
The app is GPL-3.0 licensed (see LICENSE). It bundles third-party components under their own terms:
- SwiftLaTeX pdfTeX (
vendor/swiftlatex/) — EPL-2.0 or GPL-2.0 with Classpath exception, from https://github.com/SwiftLaTeX/SwiftLaTeX - TeX Live (
vendor/texlive/) — LPPL and other free licences; seevendor/texlive/manifest.jsonfor the exact package list