penpad · Open source · MIT · Python 3.9–3.13

Typed notes in,handwritten pages out.

Write Markdown with LaTeX math and get realistic handwritten PDF or PNG pages for your iPad (Goodnotes, Notability), reMarkable, Kindle Scribe or printer. Free, offline, and it installs withpip alone.

pip install "git+https://github.com/felipefrf/penpad"
Fig. 1notes.md
# 2) Damped oscillator
A mass $m$ on a spring $k$ with viscous damping $c$:
$$ m\ddot{x} + c\dot{x} + kx = 0 $$
$$! x(t) = A e^{-\zeta\omega_n t} \cos\left(\omega_d t - \phi\right) $$
(a) underdamped, $\zeta < 1$: oscillates with $\omega_d = \omega_n\sqrt{1 - \zeta^2}$
> Energy lost per cycle: $\Delta E = \pi c \omega X^2$
{red} Lightly damped: about $1/(2\pi\zeta) \approx 1.6$ cycles per e-fold decay.
Fig. 2notes.pdf
Handwritten physics notes on Goodnotes-style grid paper, generated by penpad from the Markdown on the left: damped oscillator equations with a boxed solution
01Features

What it does

It lays notes out on a page the way a person would write them, math included, and every letter stays legible.

  1. 01

    Math in handwriting

    A practical subset of LaTeX: \frac, \int_a^b, \sqrt, \vec, \hat, \dot, \left( \right), Greek letters, \partial, \nabla, boxed results and colored pens.

  2. 02

    Believable variation

    Slant, size and baseline drift slowly like a real hand. Each letter has a few shapes and never repeats one back to back, while a legibility clamp keeps everything readable.

  3. 03

    Tablet-ready pages

    Presets for the Goodnotes page, A4 and US Letter (grid, lined, dotted, plain) and reMarkable. PDFs come out at the real page size, ready to import.

  4. 04

    Installs anywhere

    Pure pip dependencies (resvg, Pillow, fontTools) and bundled open fonts. No Cairo, no LaTeX, no browser, no API key, no network. Tested on Linux, macOS and Windows.

  5. 05

    Reproducible

    The same seed gives the same page, pixel for pixel. Change the seed for a different hand.

02The hand

One writer, never twice the same

Font-based generators either repeat the same glyph or jitter every letter on its own. Both look mechanical. penpad models a writer instead.

The same sentence handwritten several times by penpad, with natural differences between the letters
Fig. 3: One hand, the same sentence, again and again
01

Writer state

Slant, rotation, size and baseline follow mean-reverting random processes, so neighbouring letters lean and float together and the line wanders, then comes back.

02

Allographs

Each character gets a fixed repertoire of shapes derived from the seed. The writer draws an “a” in one of four ways and never the same way twice in a row.

03

Instance noise

Every use redraws part of the outline deformation, so no two letters on a page are pixel-identical.

The same notes in the cursive style on Goodnotes grid paper
--style cursiveGoodnotes grid
The same notes in the print style on A4 lined paper
--style printA4 lined
The same notes in the casual style on A4 dots paper
--style casualA4 dots
03Install & write

Two commands, one page

Pages render in parallel on every core. Output and errors are one line each.

~ pip install "git+https://github.com/felipefrf/penpad"
~ penpad demo                # writes penpad-demo.pdf
~ penpad render notes.md     # writes notes.pdf
~ penpad render notes.md --style print --paper a4-lines
No install, with uvuvx --from git+https://github.com/felipefrf/penpad penpad render notes.md
Dockerdocker build -t penpad https://github.com/felipefrf/penpad.git
You writeYou get
# TitleTitle in the accent pen (blue)
## HeadingHeading in purple
text with $...$Paragraph with inline math, wrapped to the page
$$ ... $$Equation on its own line, shrunk to fit if too wide
$$! ... $$Boxed result
- item, (a) item, 1. itemList item with hanging indent
> noteSide note in purple
{red} linePen color: black, blue, red, purple, green, gray or #hex
---New page
04Python API

Sketches, by hand

Lines, arrows, curves and circles drawn in the same pen, for free-body diagrams and quick figures.

from penpad import Notebook

nb = Notebook(paper="goodnotes", style="cursive", seed=21)
nb.title("Free-body diagram")
nb.text("Block on an incline, no friction:")

def incline(nb, x0, y0):
    nb.line(x0 + 40, y0 + 230, x0 + 520, y0 + 230)
    nb.line(x0 + 40, y0 + 230, x0 + 520, y0 + 30)
    nb.arrow(x0 + 300, y0 + 120, x0 + 300, y0 + 220, color="red")
    nb.write(x0 + 308, y0 + 214, "mg", color="red")

nb.figure(260, incline)
nb.math(r"\sum F_{\parallel} = mg\sin\theta = ma \Rightarrow a = g\sin\theta", box=True)
nb.save("incline.pdf")
Hand-drawn free-body diagram of a block on an incline with a boxed handwritten equation, made with the penpad Python API
05FAQ

Questions

How do I get the notes into Goodnotes, Notability or a reMarkable?

Import the PDF. The default goodnotes paper matches the Goodnotes page size and grid, so imported pages line up with the ones you write by hand.

Does it need LaTeX installed?

No. penpad reads LaTeX math syntax and draws it itself.

Can it write in my own handwriting?

Yes, through a font. Turn your writing into a font (for example with Calligraphr), load it with register_font, and run penpad calibrate on a page you wrote to match paper, grid and pen colors.

Is it free? Does it work offline?

Yes to both. It is MIT-licensed and nothing is uploaded anywhere.

Is the output deterministic?

Yes. Keep --seed for identical output, change it for a different hand.

Intended usepenpad is for your own study notes, tablet notebooks, flashcards, mockups and design work. Please don’t use it to pass generated text off as handwriting where handwriting is required, such as exams, signatures or handwritten assignments.

Your notes,
in your hand.