cacography 0.14.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. cacography-0.14.0b1/LICENSE +40 -0
  2. cacography-0.14.0b1/PKG-INFO +178 -0
  3. cacography-0.14.0b1/README.md +157 -0
  4. cacography-0.14.0b1/cacography.egg-info/PKG-INFO +178 -0
  5. cacography-0.14.0b1/cacography.egg-info/SOURCES.txt +32 -0
  6. cacography-0.14.0b1/cacography.egg-info/dependency_links.txt +1 -0
  7. cacography-0.14.0b1/cacography.egg-info/entry_points.txt +3 -0
  8. cacography-0.14.0b1/cacography.egg-info/requires.txt +4 -0
  9. cacography-0.14.0b1/cacography.egg-info/top_level.txt +1 -0
  10. cacography-0.14.0b1/latex/LICENSE +15 -0
  11. cacography-0.14.0b1/latex/cacography.lua +620 -0
  12. cacography-0.14.0b1/latex/cacography.sty +182 -0
  13. cacography-0.14.0b1/pyproject.toml +45 -0
  14. cacography-0.14.0b1/python/cacography_render/__init__.py +1 -0
  15. cacography-0.14.0b1/python/cacography_render/__main__.py +155 -0
  16. cacography-0.14.0b1/python/cacography_render/aspects.py +128 -0
  17. cacography-0.14.0b1/python/cacography_render/camera.py +547 -0
  18. cacography-0.14.0b1/python/cacography_render/cli.py +293 -0
  19. cacography-0.14.0b1/python/cacography_render/drawing.py +247 -0
  20. cacography-0.14.0b1/python/cacography_render/fabric.py +579 -0
  21. cacography-0.14.0b1/python/cacography_render/handling.py +502 -0
  22. cacography-0.14.0b1/python/cacography_render/imaging.py +123 -0
  23. cacography-0.14.0b1/python/cacography_render/ink.py +199 -0
  24. cacography-0.14.0b1/python/cacography_render/marks.py +501 -0
  25. cacography-0.14.0b1/python/cacography_render/model.py +233 -0
  26. cacography-0.14.0b1/python/cacography_render/page.py +1533 -0
  27. cacography-0.14.0b1/python/cacography_render/paper.py +381 -0
  28. cacography-0.14.0b1/python/cacography_render/pen.py +188 -0
  29. cacography-0.14.0b1/python/cacography_render/pens.py +962 -0
  30. cacography-0.14.0b1/python/cacography_render/props.py +839 -0
  31. cacography-0.14.0b1/python/cacography_render/render3d.py +485 -0
  32. cacography-0.14.0b1/python/cacography_render/surfaces.py +463 -0
  33. cacography-0.14.0b1/python/cacography_render/symbols.py +111 -0
  34. cacography-0.14.0b1/setup.cfg +4 -0
@@ -0,0 +1,40 @@
1
+ cacography is three things under three licences.
2
+
3
+ 1. The LaTeX package (latex/cacography.sty, latex/cacography.lua) is under the LaTeX
4
+ Project Public License, version 1.3c or later (latex/LICENSE).
5
+
6
+ 2. Everything else in this repository (the renderer in python/, the training code in
7
+ training/, the tools and examples) is under the MIT License below.
8
+
9
+ 3. The trained handwriting models and the symbol bank are NOT in this repository and NOT
10
+ under either licence. They are a separate download (cacography-models.zip) and may be
11
+ used for non-commercial research only, because they are trained on datasets that allow
12
+ only that: BRUSH (Brown University), IAM-OnDB (University of Bern) and MathWriting
13
+ (Google, CC BY-NC-SA 4.0). See MODELS-LICENSE in that download.
14
+
15
+ Textures and room lights fetched at run time come from Poly Haven and ambientCG under CC0.
16
+ They are cached on your computer and not redistributed.
17
+
18
+ -------------------------------------------------------------------------------
19
+
20
+ MIT License
21
+
22
+ Copyright (c) 2026 the cacography authors
23
+
24
+ Permission is hereby granted, free of charge, to any person obtaining a copy
25
+ of this software and associated documentation files (the "Software"), to deal
26
+ in the Software without restriction, including without limitation the rights
27
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28
+ copies of the Software, and to permit persons to whom the Software is
29
+ furnished to do so, subject to the following conditions:
30
+
31
+ The above copyright notice and this permission notice shall be included in all
32
+ copies or substantial portions of the Software.
33
+
34
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40
+ SOFTWARE.
@@ -0,0 +1,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: cacography
3
+ Version: 0.14.0b1
4
+ Summary: Typeset in LaTeX, get back a phone photo of handwritten notes.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/aynader/cacography
7
+ Keywords: latex,lualatex,handwriting,notes,rendering
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
11
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ License-File: latex/LICENSE
16
+ Requires-Dist: numpy>=1.26
17
+ Requires-Dist: pillow>=10
18
+ Requires-Dist: torch>=2.2
19
+ Requires-Dist: mitsuba>=3.5
20
+ Dynamic: license-file
21
+
22
+ # cacography
23
+
24
+ *cacography* (n.): bad handwriting, on purpose.
25
+
26
+ Write your notes in LaTeX and get back a phone photo of them handwritten on a slightly abused sheet of paper, with crossouts, coffee rings and all. The PDF underneath stays searchable, so nobody has to know. ;)
27
+
28
+ ![Four pages written by cacography](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/showcase.jpg)
29
+
30
+ Every word is written by a handwriting model trained on real pen recordings. Each photo is traced in 3D (paper, desk, lamp, pen). LaTeX still does the layout, the maths and the figures.
31
+
32
+ ## From this to this
33
+
34
+ ![The LaTeX source of a page beside the photo it became](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/source-to-photo.jpg)
35
+
36
+ ## Install
37
+
38
+ You need LuaLaTeX ([TeX Live](https://tug.org/texlive) or [MiKTeX](https://miktex.org)). Then, from this folder:
39
+
40
+ ```bash
41
+ .\install.ps1 # Windows
42
+ sh install.sh # macOS, Linux
43
+ ```
44
+
45
+ The installer brings its own Python (via [uv](https://docs.astral.sh/uv)), installs the renderer, puts the LaTeX package where TeX finds it, fetches the handwriting models and runs `cacography doctor` to check everything. Allow for a few GB of download, mostly PyTorch. Already have PyTorch? Activate that environment first (`conda activate base`) and the installer uses it instead. An NVIDIA GPU is optional. Without one, pages are photographed with formulas instead of traced in 3D: no props, simpler light.
46
+
47
+ ## Use
48
+
49
+ ```bash
50
+ cacography notes.tex
51
+ ```
52
+
53
+ Or press Compile in your editor. Compile with LuaLaTeX and shell escape on, twice, as you would for references. The first run draws the pages and the second puts them in.
54
+
55
+ - **TeXstudio:** put these two lines at the top of the file. TeXstudio asks once whether to allow them.
56
+ ```latex
57
+ % !TeX program = lualatex
58
+ % !TeX TXS-program:compile = txs:///lualatex/[--shell-escape]
59
+ ```
60
+ - **VS Code (LaTeX Workshop), latexmk:** copy [`.latexmkrc`](https://github.com/aynader/cacography/blob/main/.latexmkrc) next to your file. It reruns by itself.
61
+ - **TeXworks, Texmaker, others:** add `-shell-escape` to the LuaLaTeX command.
62
+ - **Overleaf:** no. The pages are drawn by a program on your computer.
63
+
64
+ Start from [`examples/notes.tex`](https://github.com/aynader/cacography/blob/main/examples/notes.tex). Only pages that changed are drawn again.
65
+
66
+ ## Options
67
+
68
+ ```latex
69
+ \usepackage[paper=graph, ink=pencil, light=window, crumple=0.6, seed=42]{cacography}
70
+ ```
71
+
72
+ Anything you don't set is picked at random from the `seed`. Each part has its own seed, so pinning one part never reshuffles another. `\cacographypage{crumple=1, stains=coffee}` changes just the sheet it lands on. In each row below, only the named option changes.
73
+
74
+ ### The writing
75
+
76
+ **`seed`**: a different writer (and room) for each number.
77
+ ![seed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-seed.jpg)
78
+
79
+ **`sloppiness`**: 0 to 1, from neat, even lines to words that change size, tilt and wander off the line.
80
+ ![sloppiness](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-sloppiness.jpg)
81
+
82
+ **`ink`**: `blue`, `black`, `red` (ballpoint), `pencil`.
83
+ ![ink](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-ink.jpg)
84
+
85
+ **`paper`**: `notebook`, `wide`, `graph`, `legal` (yellow pad), `blank`.
86
+ ![paper](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-paper.jpg)
87
+
88
+ **`underline`**: `headings` underlines section titles by hand.
89
+ ![underline](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-underline.jpg)
90
+
91
+ ### The photo
92
+
93
+ **`camera`**: `phone`, `scan`, `none` (just the paper).
94
+ ![camera](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-camera.jpg)
95
+
96
+ **`background`**: 30-odd desks and fabrics (`oak`, `walnut`, `marble`, `concrete`, `denim`, `plaid`, `cork`, …), a group (`wood`, `fabric`, `stone`), or `file:my-desk.jpg`.
97
+ ![background](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-background.jpg)
98
+
99
+ **`light`**: `lamp`, `overhead`, `window`, `soft`, `raking`, `flash`, `dim`.
100
+ ![light](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-light.jpg)
101
+
102
+ **`angle`**: `flat`, `slight`, `steep`, or degrees.
103
+ ![angle](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-angle.jpg)
104
+
105
+ **`framing`**: `tight`, `loose`, `cropped`.
106
+ ![framing](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-framing.jpg)
107
+
108
+ **`shadow`**: `none`, or `phone` (your phone and hand, blocking the light).
109
+ ![shadow](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-shadow.jpg)
110
+
111
+ **`props`**: any of `tape`, `clip`, `binder`, `staple`, `pen`, `sheet`. Pens come in a dozen kinds, and pencil ink brings a pencil.
112
+ ![props](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-props.jpg)
113
+
114
+ ### The sheet
115
+
116
+ **`crumple`**: `none`, or 0 to 1 (balled up and smoothed out again).
117
+ ![crumple](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-crumple.jpg)
118
+
119
+ **`folds`**: `half`, `thirds`, `quarters`. **`creases`**, **`scores`** (thin pressed lines): how many.
120
+ ![folds](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-folds.jpg)
121
+ ![creases](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-creases.jpg)
122
+
123
+ **`edges`**: `clean`, `worn`, `torn`, `spiral`.
124
+ ![edges](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-edges.jpg)
125
+
126
+ **`stains`**: `coffee`, `water`, `smudge` (ink dragged by a hand), or several: `stains={coffee, smudge}`.
127
+ ![stains](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-stains.jpg)
128
+
129
+ **`grooves`**: 0 to 1, how hard the pen pressed into the paper, with faint grooves from writing on the sheet above. Subtle on purpose; it shows in raking light, up close.
130
+
131
+ **`curl`**: 0 to 1, edges and corners rolling up.
132
+ ![curl](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-curl.jpg)
133
+
134
+ **`age`**: 0 to 1, yellowed and faded.
135
+ ![age](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-age.jpg)
136
+
137
+ **`backside`**: `writing` shows the back of the sheet through.
138
+ ![backside](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-backside.jpg)
139
+
140
+ **`wear`**: 0 to 1, how likely everything in this section is when left random.
141
+ ![wear](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-wear.jpg)
142
+
143
+ ## Commands
144
+
145
+ Corrections are written the way people make them. Each picture below shows the LaTeX beside what it wrote.
146
+
147
+ **`\crossout[line|double|scribble]{text}`**
148
+ ![crossout](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-crossout.jpg)
149
+
150
+ **`\erased{old}{new}`**: rubbed out and written over; best with `ink=pencil`.
151
+ ![erased](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-erased.jpg)
152
+
153
+ **`\cacographynote{text}`**: a margin note; with `*`, an arrow to where it belongs; with `[right]`, in the right margin.
154
+ ![note](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-note.jpg)
155
+
156
+ **`\boxed`, `\underline`, `\fbox`**: drawn by hand.
157
+ ![boxed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-boxed.jpg)
158
+
159
+ **TikZ and pgfplots**: every line, curve, label and hatch drawn again by hand.
160
+ ![tikz](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-tikz.jpg)
161
+
162
+ **`\reroll[n]{word}`**: one badly written word written again, leaving the rest of the page alone.
163
+ ![reroll](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-reroll.jpg)
164
+
165
+ ## How it works
166
+
167
+ 1. **LuaLaTeX** lays the page out at handwriting proportions (letters 10% wider, word gaps 2.3× wider), so lines break where a hand would. It records where every glyph, rule and drawing goes.
168
+ 2. **The writer**, an LSTM with a mixture-density output, writes each word. A reader trained alongside it reads the word back, and anything that doesn't read as its text is written again. Maths symbols come from real handwritten samples.
169
+ 3. **The ink** is laid down like a ballpoint's: heavier on downstrokes, pooling where the pen lands, skipping now and then. It goes onto paper with grain, ruling, holes, folds and stains.
170
+ 4. **The camera** traces the sheet in 3D with [Mitsuba 3](https://www.mitsuba-renderer.org): bent paper, a real lamp, props, the phone's own processing and JPEG. The photo goes back into the PDF over the invisible typeset text.
171
+
172
+ The model, datasets and training recipe are in [`training/`](https://github.com/aynader/cacography/blob/main/training/README.md). Trained on [BRUSH](https://github.com/brownvc/decoupled-style-descriptors#brush-dataset), [IAM-OnDB](https://fki.tic.heia-fr.ch/databases/iam-on-line-handwriting-database) and [MathWriting](https://github.com/google-research/google-research/tree/master/mathwriting). In a blind test, its handwriting was judged real as often as real handwriting was.
173
+
174
+ The full reference is the [manual](https://github.com/aynader/cacography/blob/main/docs/cacography-manual.pdf). English and German are supported.
175
+
176
+ ## Licence
177
+
178
+ The LaTeX package is under the [LPPL 1.3c](https://github.com/aynader/cacography/blob/main/latex/LICENSE) and the rest of the code under [MIT](https://github.com/aynader/cacography/blob/main/LICENSE). The trained handwriting models are a separate download for **non-commercial research only**, because the datasets they learned from allow only that.
@@ -0,0 +1,157 @@
1
+ # cacography
2
+
3
+ *cacography* (n.): bad handwriting, on purpose.
4
+
5
+ Write your notes in LaTeX and get back a phone photo of them handwritten on a slightly abused sheet of paper, with crossouts, coffee rings and all. The PDF underneath stays searchable, so nobody has to know. ;)
6
+
7
+ ![Four pages written by cacography](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/showcase.jpg)
8
+
9
+ Every word is written by a handwriting model trained on real pen recordings. Each photo is traced in 3D (paper, desk, lamp, pen). LaTeX still does the layout, the maths and the figures.
10
+
11
+ ## From this to this
12
+
13
+ ![The LaTeX source of a page beside the photo it became](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/source-to-photo.jpg)
14
+
15
+ ## Install
16
+
17
+ You need LuaLaTeX ([TeX Live](https://tug.org/texlive) or [MiKTeX](https://miktex.org)). Then, from this folder:
18
+
19
+ ```bash
20
+ .\install.ps1 # Windows
21
+ sh install.sh # macOS, Linux
22
+ ```
23
+
24
+ The installer brings its own Python (via [uv](https://docs.astral.sh/uv)), installs the renderer, puts the LaTeX package where TeX finds it, fetches the handwriting models and runs `cacography doctor` to check everything. Allow for a few GB of download, mostly PyTorch. Already have PyTorch? Activate that environment first (`conda activate base`) and the installer uses it instead. An NVIDIA GPU is optional. Without one, pages are photographed with formulas instead of traced in 3D: no props, simpler light.
25
+
26
+ ## Use
27
+
28
+ ```bash
29
+ cacography notes.tex
30
+ ```
31
+
32
+ Or press Compile in your editor. Compile with LuaLaTeX and shell escape on, twice, as you would for references. The first run draws the pages and the second puts them in.
33
+
34
+ - **TeXstudio:** put these two lines at the top of the file. TeXstudio asks once whether to allow them.
35
+ ```latex
36
+ % !TeX program = lualatex
37
+ % !TeX TXS-program:compile = txs:///lualatex/[--shell-escape]
38
+ ```
39
+ - **VS Code (LaTeX Workshop), latexmk:** copy [`.latexmkrc`](https://github.com/aynader/cacography/blob/main/.latexmkrc) next to your file. It reruns by itself.
40
+ - **TeXworks, Texmaker, others:** add `-shell-escape` to the LuaLaTeX command.
41
+ - **Overleaf:** no. The pages are drawn by a program on your computer.
42
+
43
+ Start from [`examples/notes.tex`](https://github.com/aynader/cacography/blob/main/examples/notes.tex). Only pages that changed are drawn again.
44
+
45
+ ## Options
46
+
47
+ ```latex
48
+ \usepackage[paper=graph, ink=pencil, light=window, crumple=0.6, seed=42]{cacography}
49
+ ```
50
+
51
+ Anything you don't set is picked at random from the `seed`. Each part has its own seed, so pinning one part never reshuffles another. `\cacographypage{crumple=1, stains=coffee}` changes just the sheet it lands on. In each row below, only the named option changes.
52
+
53
+ ### The writing
54
+
55
+ **`seed`**: a different writer (and room) for each number.
56
+ ![seed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-seed.jpg)
57
+
58
+ **`sloppiness`**: 0 to 1, from neat, even lines to words that change size, tilt and wander off the line.
59
+ ![sloppiness](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-sloppiness.jpg)
60
+
61
+ **`ink`**: `blue`, `black`, `red` (ballpoint), `pencil`.
62
+ ![ink](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-ink.jpg)
63
+
64
+ **`paper`**: `notebook`, `wide`, `graph`, `legal` (yellow pad), `blank`.
65
+ ![paper](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-paper.jpg)
66
+
67
+ **`underline`**: `headings` underlines section titles by hand.
68
+ ![underline](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-underline.jpg)
69
+
70
+ ### The photo
71
+
72
+ **`camera`**: `phone`, `scan`, `none` (just the paper).
73
+ ![camera](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-camera.jpg)
74
+
75
+ **`background`**: 30-odd desks and fabrics (`oak`, `walnut`, `marble`, `concrete`, `denim`, `plaid`, `cork`, …), a group (`wood`, `fabric`, `stone`), or `file:my-desk.jpg`.
76
+ ![background](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-background.jpg)
77
+
78
+ **`light`**: `lamp`, `overhead`, `window`, `soft`, `raking`, `flash`, `dim`.
79
+ ![light](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-light.jpg)
80
+
81
+ **`angle`**: `flat`, `slight`, `steep`, or degrees.
82
+ ![angle](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-angle.jpg)
83
+
84
+ **`framing`**: `tight`, `loose`, `cropped`.
85
+ ![framing](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-framing.jpg)
86
+
87
+ **`shadow`**: `none`, or `phone` (your phone and hand, blocking the light).
88
+ ![shadow](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-shadow.jpg)
89
+
90
+ **`props`**: any of `tape`, `clip`, `binder`, `staple`, `pen`, `sheet`. Pens come in a dozen kinds, and pencil ink brings a pencil.
91
+ ![props](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-props.jpg)
92
+
93
+ ### The sheet
94
+
95
+ **`crumple`**: `none`, or 0 to 1 (balled up and smoothed out again).
96
+ ![crumple](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-crumple.jpg)
97
+
98
+ **`folds`**: `half`, `thirds`, `quarters`. **`creases`**, **`scores`** (thin pressed lines): how many.
99
+ ![folds](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-folds.jpg)
100
+ ![creases](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-creases.jpg)
101
+
102
+ **`edges`**: `clean`, `worn`, `torn`, `spiral`.
103
+ ![edges](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-edges.jpg)
104
+
105
+ **`stains`**: `coffee`, `water`, `smudge` (ink dragged by a hand), or several: `stains={coffee, smudge}`.
106
+ ![stains](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-stains.jpg)
107
+
108
+ **`grooves`**: 0 to 1, how hard the pen pressed into the paper, with faint grooves from writing on the sheet above. Subtle on purpose; it shows in raking light, up close.
109
+
110
+ **`curl`**: 0 to 1, edges and corners rolling up.
111
+ ![curl](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-curl.jpg)
112
+
113
+ **`age`**: 0 to 1, yellowed and faded.
114
+ ![age](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-age.jpg)
115
+
116
+ **`backside`**: `writing` shows the back of the sheet through.
117
+ ![backside](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-backside.jpg)
118
+
119
+ **`wear`**: 0 to 1, how likely everything in this section is when left random.
120
+ ![wear](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-wear.jpg)
121
+
122
+ ## Commands
123
+
124
+ Corrections are written the way people make them. Each picture below shows the LaTeX beside what it wrote.
125
+
126
+ **`\crossout[line|double|scribble]{text}`**
127
+ ![crossout](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-crossout.jpg)
128
+
129
+ **`\erased{old}{new}`**: rubbed out and written over; best with `ink=pencil`.
130
+ ![erased](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-erased.jpg)
131
+
132
+ **`\cacographynote{text}`**: a margin note; with `*`, an arrow to where it belongs; with `[right]`, in the right margin.
133
+ ![note](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-note.jpg)
134
+
135
+ **`\boxed`, `\underline`, `\fbox`**: drawn by hand.
136
+ ![boxed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-boxed.jpg)
137
+
138
+ **TikZ and pgfplots**: every line, curve, label and hatch drawn again by hand.
139
+ ![tikz](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-tikz.jpg)
140
+
141
+ **`\reroll[n]{word}`**: one badly written word written again, leaving the rest of the page alone.
142
+ ![reroll](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-reroll.jpg)
143
+
144
+ ## How it works
145
+
146
+ 1. **LuaLaTeX** lays the page out at handwriting proportions (letters 10% wider, word gaps 2.3× wider), so lines break where a hand would. It records where every glyph, rule and drawing goes.
147
+ 2. **The writer**, an LSTM with a mixture-density output, writes each word. A reader trained alongside it reads the word back, and anything that doesn't read as its text is written again. Maths symbols come from real handwritten samples.
148
+ 3. **The ink** is laid down like a ballpoint's: heavier on downstrokes, pooling where the pen lands, skipping now and then. It goes onto paper with grain, ruling, holes, folds and stains.
149
+ 4. **The camera** traces the sheet in 3D with [Mitsuba 3](https://www.mitsuba-renderer.org): bent paper, a real lamp, props, the phone's own processing and JPEG. The photo goes back into the PDF over the invisible typeset text.
150
+
151
+ The model, datasets and training recipe are in [`training/`](https://github.com/aynader/cacography/blob/main/training/README.md). Trained on [BRUSH](https://github.com/brownvc/decoupled-style-descriptors#brush-dataset), [IAM-OnDB](https://fki.tic.heia-fr.ch/databases/iam-on-line-handwriting-database) and [MathWriting](https://github.com/google-research/google-research/tree/master/mathwriting). In a blind test, its handwriting was judged real as often as real handwriting was.
152
+
153
+ The full reference is the [manual](https://github.com/aynader/cacography/blob/main/docs/cacography-manual.pdf). English and German are supported.
154
+
155
+ ## Licence
156
+
157
+ The LaTeX package is under the [LPPL 1.3c](https://github.com/aynader/cacography/blob/main/latex/LICENSE) and the rest of the code under [MIT](https://github.com/aynader/cacography/blob/main/LICENSE). The trained handwriting models are a separate download for **non-commercial research only**, because the datasets they learned from allow only that.
@@ -0,0 +1,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: cacography
3
+ Version: 0.14.0b1
4
+ Summary: Typeset in LaTeX, get back a phone photo of handwritten notes.
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/aynader/cacography
7
+ Keywords: latex,lualatex,handwriting,notes,rendering
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Environment :: Console
10
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
11
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ License-File: latex/LICENSE
16
+ Requires-Dist: numpy>=1.26
17
+ Requires-Dist: pillow>=10
18
+ Requires-Dist: torch>=2.2
19
+ Requires-Dist: mitsuba>=3.5
20
+ Dynamic: license-file
21
+
22
+ # cacography
23
+
24
+ *cacography* (n.): bad handwriting, on purpose.
25
+
26
+ Write your notes in LaTeX and get back a phone photo of them handwritten on a slightly abused sheet of paper, with crossouts, coffee rings and all. The PDF underneath stays searchable, so nobody has to know. ;)
27
+
28
+ ![Four pages written by cacography](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/showcase.jpg)
29
+
30
+ Every word is written by a handwriting model trained on real pen recordings. Each photo is traced in 3D (paper, desk, lamp, pen). LaTeX still does the layout, the maths and the figures.
31
+
32
+ ## From this to this
33
+
34
+ ![The LaTeX source of a page beside the photo it became](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/source-to-photo.jpg)
35
+
36
+ ## Install
37
+
38
+ You need LuaLaTeX ([TeX Live](https://tug.org/texlive) or [MiKTeX](https://miktex.org)). Then, from this folder:
39
+
40
+ ```bash
41
+ .\install.ps1 # Windows
42
+ sh install.sh # macOS, Linux
43
+ ```
44
+
45
+ The installer brings its own Python (via [uv](https://docs.astral.sh/uv)), installs the renderer, puts the LaTeX package where TeX finds it, fetches the handwriting models and runs `cacography doctor` to check everything. Allow for a few GB of download, mostly PyTorch. Already have PyTorch? Activate that environment first (`conda activate base`) and the installer uses it instead. An NVIDIA GPU is optional. Without one, pages are photographed with formulas instead of traced in 3D: no props, simpler light.
46
+
47
+ ## Use
48
+
49
+ ```bash
50
+ cacography notes.tex
51
+ ```
52
+
53
+ Or press Compile in your editor. Compile with LuaLaTeX and shell escape on, twice, as you would for references. The first run draws the pages and the second puts them in.
54
+
55
+ - **TeXstudio:** put these two lines at the top of the file. TeXstudio asks once whether to allow them.
56
+ ```latex
57
+ % !TeX program = lualatex
58
+ % !TeX TXS-program:compile = txs:///lualatex/[--shell-escape]
59
+ ```
60
+ - **VS Code (LaTeX Workshop), latexmk:** copy [`.latexmkrc`](https://github.com/aynader/cacography/blob/main/.latexmkrc) next to your file. It reruns by itself.
61
+ - **TeXworks, Texmaker, others:** add `-shell-escape` to the LuaLaTeX command.
62
+ - **Overleaf:** no. The pages are drawn by a program on your computer.
63
+
64
+ Start from [`examples/notes.tex`](https://github.com/aynader/cacography/blob/main/examples/notes.tex). Only pages that changed are drawn again.
65
+
66
+ ## Options
67
+
68
+ ```latex
69
+ \usepackage[paper=graph, ink=pencil, light=window, crumple=0.6, seed=42]{cacography}
70
+ ```
71
+
72
+ Anything you don't set is picked at random from the `seed`. Each part has its own seed, so pinning one part never reshuffles another. `\cacographypage{crumple=1, stains=coffee}` changes just the sheet it lands on. In each row below, only the named option changes.
73
+
74
+ ### The writing
75
+
76
+ **`seed`**: a different writer (and room) for each number.
77
+ ![seed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-seed.jpg)
78
+
79
+ **`sloppiness`**: 0 to 1, from neat, even lines to words that change size, tilt and wander off the line.
80
+ ![sloppiness](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-sloppiness.jpg)
81
+
82
+ **`ink`**: `blue`, `black`, `red` (ballpoint), `pencil`.
83
+ ![ink](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-ink.jpg)
84
+
85
+ **`paper`**: `notebook`, `wide`, `graph`, `legal` (yellow pad), `blank`.
86
+ ![paper](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-paper.jpg)
87
+
88
+ **`underline`**: `headings` underlines section titles by hand.
89
+ ![underline](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-underline.jpg)
90
+
91
+ ### The photo
92
+
93
+ **`camera`**: `phone`, `scan`, `none` (just the paper).
94
+ ![camera](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-camera.jpg)
95
+
96
+ **`background`**: 30-odd desks and fabrics (`oak`, `walnut`, `marble`, `concrete`, `denim`, `plaid`, `cork`, …), a group (`wood`, `fabric`, `stone`), or `file:my-desk.jpg`.
97
+ ![background](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-background.jpg)
98
+
99
+ **`light`**: `lamp`, `overhead`, `window`, `soft`, `raking`, `flash`, `dim`.
100
+ ![light](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-light.jpg)
101
+
102
+ **`angle`**: `flat`, `slight`, `steep`, or degrees.
103
+ ![angle](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-angle.jpg)
104
+
105
+ **`framing`**: `tight`, `loose`, `cropped`.
106
+ ![framing](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-framing.jpg)
107
+
108
+ **`shadow`**: `none`, or `phone` (your phone and hand, blocking the light).
109
+ ![shadow](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-shadow.jpg)
110
+
111
+ **`props`**: any of `tape`, `clip`, `binder`, `staple`, `pen`, `sheet`. Pens come in a dozen kinds, and pencil ink brings a pencil.
112
+ ![props](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-props.jpg)
113
+
114
+ ### The sheet
115
+
116
+ **`crumple`**: `none`, or 0 to 1 (balled up and smoothed out again).
117
+ ![crumple](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-crumple.jpg)
118
+
119
+ **`folds`**: `half`, `thirds`, `quarters`. **`creases`**, **`scores`** (thin pressed lines): how many.
120
+ ![folds](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-folds.jpg)
121
+ ![creases](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-creases.jpg)
122
+
123
+ **`edges`**: `clean`, `worn`, `torn`, `spiral`.
124
+ ![edges](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-edges.jpg)
125
+
126
+ **`stains`**: `coffee`, `water`, `smudge` (ink dragged by a hand), or several: `stains={coffee, smudge}`.
127
+ ![stains](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-stains.jpg)
128
+
129
+ **`grooves`**: 0 to 1, how hard the pen pressed into the paper, with faint grooves from writing on the sheet above. Subtle on purpose; it shows in raking light, up close.
130
+
131
+ **`curl`**: 0 to 1, edges and corners rolling up.
132
+ ![curl](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-curl.jpg)
133
+
134
+ **`age`**: 0 to 1, yellowed and faded.
135
+ ![age](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-age.jpg)
136
+
137
+ **`backside`**: `writing` shows the back of the sheet through.
138
+ ![backside](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-backside.jpg)
139
+
140
+ **`wear`**: 0 to 1, how likely everything in this section is when left random.
141
+ ![wear](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/option-wear.jpg)
142
+
143
+ ## Commands
144
+
145
+ Corrections are written the way people make them. Each picture below shows the LaTeX beside what it wrote.
146
+
147
+ **`\crossout[line|double|scribble]{text}`**
148
+ ![crossout](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-crossout.jpg)
149
+
150
+ **`\erased{old}{new}`**: rubbed out and written over; best with `ink=pencil`.
151
+ ![erased](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-erased.jpg)
152
+
153
+ **`\cacographynote{text}`**: a margin note; with `*`, an arrow to where it belongs; with `[right]`, in the right margin.
154
+ ![note](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-note.jpg)
155
+
156
+ **`\boxed`, `\underline`, `\fbox`**: drawn by hand.
157
+ ![boxed](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-boxed.jpg)
158
+
159
+ **TikZ and pgfplots**: every line, curve, label and hatch drawn again by hand.
160
+ ![tikz](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-tikz.jpg)
161
+
162
+ **`\reroll[n]{word}`**: one badly written word written again, leaving the rest of the page alone.
163
+ ![reroll](https://raw.githubusercontent.com/aynader/cacography/main/docs/img/command-reroll.jpg)
164
+
165
+ ## How it works
166
+
167
+ 1. **LuaLaTeX** lays the page out at handwriting proportions (letters 10% wider, word gaps 2.3× wider), so lines break where a hand would. It records where every glyph, rule and drawing goes.
168
+ 2. **The writer**, an LSTM with a mixture-density output, writes each word. A reader trained alongside it reads the word back, and anything that doesn't read as its text is written again. Maths symbols come from real handwritten samples.
169
+ 3. **The ink** is laid down like a ballpoint's: heavier on downstrokes, pooling where the pen lands, skipping now and then. It goes onto paper with grain, ruling, holes, folds and stains.
170
+ 4. **The camera** traces the sheet in 3D with [Mitsuba 3](https://www.mitsuba-renderer.org): bent paper, a real lamp, props, the phone's own processing and JPEG. The photo goes back into the PDF over the invisible typeset text.
171
+
172
+ The model, datasets and training recipe are in [`training/`](https://github.com/aynader/cacography/blob/main/training/README.md). Trained on [BRUSH](https://github.com/brownvc/decoupled-style-descriptors#brush-dataset), [IAM-OnDB](https://fki.tic.heia-fr.ch/databases/iam-on-line-handwriting-database) and [MathWriting](https://github.com/google-research/google-research/tree/master/mathwriting). In a blind test, its handwriting was judged real as often as real handwriting was.
173
+
174
+ The full reference is the [manual](https://github.com/aynader/cacography/blob/main/docs/cacography-manual.pdf). English and German are supported.
175
+
176
+ ## Licence
177
+
178
+ The LaTeX package is under the [LPPL 1.3c](https://github.com/aynader/cacography/blob/main/latex/LICENSE) and the rest of the code under [MIT](https://github.com/aynader/cacography/blob/main/LICENSE). The trained handwriting models are a separate download for **non-commercial research only**, because the datasets they learned from allow only that.
@@ -0,0 +1,32 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ cacography.egg-info/PKG-INFO
5
+ cacography.egg-info/SOURCES.txt
6
+ cacography.egg-info/dependency_links.txt
7
+ cacography.egg-info/entry_points.txt
8
+ cacography.egg-info/requires.txt
9
+ cacography.egg-info/top_level.txt
10
+ latex/LICENSE
11
+ latex/cacography.lua
12
+ latex/cacography.sty
13
+ python/cacography_render/__init__.py
14
+ python/cacography_render/__main__.py
15
+ python/cacography_render/aspects.py
16
+ python/cacography_render/camera.py
17
+ python/cacography_render/cli.py
18
+ python/cacography_render/drawing.py
19
+ python/cacography_render/fabric.py
20
+ python/cacography_render/handling.py
21
+ python/cacography_render/imaging.py
22
+ python/cacography_render/ink.py
23
+ python/cacography_render/marks.py
24
+ python/cacography_render/model.py
25
+ python/cacography_render/page.py
26
+ python/cacography_render/paper.py
27
+ python/cacography_render/pen.py
28
+ python/cacography_render/pens.py
29
+ python/cacography_render/props.py
30
+ python/cacography_render/render3d.py
31
+ python/cacography_render/surfaces.py
32
+ python/cacography_render/symbols.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ cacography = cacography_render.cli:main
3
+ cacography-render = cacography_render.__main__:main
@@ -0,0 +1,4 @@
1
+ numpy>=1.26
2
+ pillow>=10
3
+ torch>=2.2
4
+ mitsuba>=3.5
@@ -0,0 +1 @@
1
+ cacography_render
@@ -0,0 +1,15 @@
1
+ cacography.sty and cacography.lua
2
+
3
+ Copyright (c) 2026 the cacography authors
4
+
5
+ This work may be distributed and/or modified under the conditions of the LaTeX Project
6
+ Public License, either version 1.3c of this license or (at your option) any later
7
+ version. The latest version of this license is in
8
+
9
+ https://www.latex-project.org/lppl.txt
10
+
11
+ and version 1.3c or later is part of all distributions of LaTeX version 2008 or later.
12
+
13
+ This work has the LPPL maintenance status `maintained'.
14
+ The Current Maintainer of this work is the cacography authors.
15
+ This work consists of the files cacography.sty and cacography.lua.