Pixel-perfect paper templates for personal notes, cheatsheets, study sheets, etc. Every page is rendered at 8.5" × 11" @ 1000 DPI (8500 × 11000 px) with the same usable rectangle, header, and a shared center-margin invariant (125 px from element center to rect edge) across every mode and every density.
See SPEC.md for exact pixel numbers, dot/line sizes, density ratios, and the math.
Each mode comes in three densities: regular, extra, super. The orthogonal modes (dotted/lined/graph/cornell) use SPACING ∈ {250, 150, 125} px — the only integer spacings in that range that divide the lattice exactly. Modes with non-orthogonal geometry use mode-specific parameters chosen to preserve the same 120 px margins; see each notebook's header comment for the derivation.
| mode | description | output |
|---|---|---|
| dotted | dot grid | output/dotted/ |
| lined | horizontal rules | output/lined/ |
| graph | full grid (lines both directions) | output/graph/ |
| cornell | lined + cue column + summary band | output/cornell/ |
| isometric | triangular dot lattice (~60°, < 1.2° deviation) | output/isometric/ |
| hex | tessellated pointy-top hexagons | output/hex/ |
| storyboard | tiled rectangle frames | output/storyboard/ |
| cheatsheet | dotted background + 3 column dividers | output/cheatsheet/ |
A note on isometric / hex: true 60° lattices require an irrational P_y/P_x = sqrt(3)/2, which can't coexist with both integer pixel coordinates AND exact 120 px margins. The chosen (P_x, P_y) pairs deviate from 60° by less than 1.2° per density — visually indistinguishable at 1000 DPI. Hex vertex offsets P_y/3 are sub-pixel for two of the three densities; floats are passed to PIL so adjacent hexes still share the same vertex (seamless tessellation under anti-aliasing).
paper-generation/
├── papers/
│ ├── common.py # WIDTH, HEIGHT, MARGIN, HEADER_HEIGHT, lattice helpers
│ ├── dotted.ipynb
│ ├── lined.ipynb
│ ├── graph.ipynb
│ ├── cornell.ipynb
│ ├── isometric.ipynb
│ ├── hex.ipynb
│ ├── storyboard.ipynb
│ └── cheatsheet.ipynb
└── output/
├── dotted/{dotted,extra-dotted,super-dotted}.png
├── lined/...
└── ... # one folder per mode, three PNGs per folder
Every notebook is the same shape: import common, define a render_<mode>(spacing) function, loop over the three densities, save + display. All math is edge-based (PIL paste/rectangle take corners, not centers) — common.py documents the model in detail.
python3 -m venv venv && source venv/bin/activate
pip install pillow jupyter
jupyter nbconvert --to notebook --execute papers/<mode>.ipynb --output <mode>.ipynbOutputs go to output/<mode>/.