Skip to content
Write to me
latex/

LaTeX

Since my first year at university I have written in LaTeX: lecture notes in Neovim, a thesis kept as a repository with releases, and my product's documents, whose figures come from data.

What it is
Three pieces of work in one tool: notes from 2022–2025, a thesis in 2026 and the documents of Pora na paru since September 2026.
How it was made
I built the notes and their setup by hand: there were no agents then. The thesis and the product's documents were made in 2026 with Claude Code: I set the structure and the rules, the tool did the typing.
What is open
The thesis' sources and releases are on GitHub. The documents' repository is private: shown here are how it works and pages of an invented example.
Period
since 2022
Stack
Neovim, vimtex, LuaSnip, Inkscape, LuaLaTeX
  • 630pages of notes
  • 139snippets
  • 130pages of the thesis
  • 10thesis releases
  • 6document types
  • 11build checks

As of 03.11.2026, from the repositories

Notes

Formulas at the speed of a lecture

In my first year I started taking mathematics notes on a laptop: by hand it was slow, Word cannot keep up with formulas, and the notes my classmates kept in Notion were not enough for me. The first attempts are lost; the repository starts with the second year.

A note is written in Neovim. vimtex builds the PDF, and LuaSnip expands abbreviations as I type: ff becomes a fraction, ;e an epsilon, and <= the sign ⩽ that Russian texts use. The config has 139 snippets: 132 expand by themselves, 44 work only inside formulas.

Below is line 259 of calculus lecture 17, 19.11.2023, typed again with the same snippets. The PDF updates when I leave insert mode and press ␣c: the file is saved and built once.

les-17.tex

Если $E \subset \R^{n} $ и $\forall \epsilon > 0 \ \exists B = B_{\epsilon } : \ E \subset B$ и $m(B) < \epsilon \implies m(E) = 0$.

NORMALpressed Esc ␣ ckeys 99 · characters 132

master.pdf

Pages

630 pages in two years

From September 2023 to June 2025 the repository holds 8 sets of lecture notes, 263 pages, and 14 collections for exams and tests, 367 pages. 64 figures are drawn in Inkscape and placed in the PDF with labels set by LaTeX itself.

My group prepared for exams with these notes and collections, and so did younger students when they reached the same subjects.

In the dark theme the pages are recoloured as Zathura showed them with my Catppuccin config.

  • A page of the notes: the directional derivative, a note and a definition in coloured boxes.A page of the notes: the directional derivative, a note and a definition in coloured boxes.
    CalculusLecture 1, 01.09.2023
  • A page with Taylor's formula for a function of two variables.A page with Taylor's formula for a function of two variables.
    CalculusLecture 2: Taylor's formula
  • A page with graphs drawn in Inkscape.A page with graphs drawn in Inkscape.
    Graph theoryExam questions
  • A drawing of the Riemann sphere and the formulas of the stereographic projection.A drawing of the Riemann sphere and the formulas of the stereographic projection.
    Complex analysisLecture 1: the Riemann sphere
  • A page with a contour of integration and a bound on the integral.A page with a contour of integration and a bound on the integral.
    Complex analysisLecture 5: the integral over a triangle
  • The title page and contents of a collection of proofs for an exam.The title page and contents of a collection of proofs for an exam.
    Proofs for the examCalculus, 85 pages

Origin

The method is not mine

This is how Gilles Castel took notes: in 2019 he described typing mathematics lectures in Vim and drawing their figures in Inkscape. Elijan Mastnak turned it into a detailed guide to the setup. I spent months building my config from their writing and looked for answers on Reddit: there were no agents to do it for me then.

From them the config has vimtex with LuaSnip, the layout of its files, the rules of the triggers and the preamble of the first notes. Mine are the colours of the boxes around definitions and theorems, the Russian names with their snippets, the lecture's date from the lesson command, ⩽ and ⩾ in place of ≤ and ≥, and a Russian dictionary. For this setup I moved from Windows to macOS, and installed Arch Linux on my home computer.

In my fourth year I wrote to the guide's author, showed him pictures of my setup and thanked him. He replied.

Thesis

Its source lies under the page

I kept my graduation thesis as a repository: the text in .tex files, built by LuaLaTeX through latexmk, the university's requirements in a file of their own that the preamble follows. The topic: “Development of the client applications of the VCourse SaaS platform for managing teaching schedules”.

The requirements are set once: A4, margins of 2, 2, 3 and 1 cm, 14 points, 1.5 spacing, a 1.25 cm indent. That is five lines, and all 130 pages take their look from them. The bibliography follows GOST 7.0.5 without BibTeX, and the title page is built from a file of data.

Page 69 of the thesis: the section on the web application.Page 69 of the thesis: the section on the web application.

Move the lens over the page: its source lies under it, paragraph for paragraph.

\documentclass[14pt,a4paper,oneside]{extarticle}\setmainfont{CMU Serif}\usepackage[a4paper, top=2cm, bottom=2cm, left=3cm, right=1cm]{geometry}\onehalfspacing\setlength{\parindent}{1.25cm}

Releases

Ten releases, from 3 pages to 130

make release checks that everything is committed, builds the PDF and puts a tag with the date. The tag starts GitHub Actions: the PDF is built in a container with a full TeX Live and attached to the release, and the link to the latest one stays the same.

Each release below is a real PDF from GitHub. On 22 May the screenshots of the apps went in: the file grew from 391 KB to 21.2 MB in one release.

Every page of release v2026.06.10Every page of release v2026.06.10

v2026.06.10

130pages

Date
10.06.2026
Words
23,049
File
21.2 MB
  1. make releasechecks that everything is committed and builds the PDF
  2. git tag vYYYY.MM.DDa tag with the date goes to GitHub
  3. build-pdf.ymlthe tag starts the build
  4. texlive/texlive:latesta full TeX Live with CMU Serif, the command make build
  5. bachelor-thesis.pdfthe PDF is attached to the release

Documents

The product's documents are built from data

Pora na paru has many documents that live longer than a week: registers of universities and colleges, overviews, policies. I refused to keep them in Word or in a tracker's editor, and since 30 September 2026 they are a LaTeX repository.

One class gives every document its look, and a type is told by its label, not by a colour: overview, status report, policy, register, brief, agreement. Tables and figures are never typed by hand: a document asks the data for them in document.json, and under every table the build prints the day the data was checked and where it came from.

Every document has a level of access, and the build will not let a document take a column or a source of a more closed level. An issued version goes into a journal with the hash of its PDF: different content cannot be issued under the same number.

document.json

"by-city": {
  "dataset": "example",
  "table": "organizations",
  "caption": "По городам",
  "pivot": {
    "by": "city",
    "total": true,
    "values": [
      { "key": "organizations", "count": true },
      { "key": "universities", "count": true,
        "filter": { "kind": "university" } },
      { "key": "students", "sum": "students" },
      { "key": "per-organization",
        "ratio": ["students", "organizations"] }
    ]
  },
  "sort": ["-students", "by"]
}
A page of the register: a chart by city and the start of a table.A page of the register: a chart by city and the start of a table.A page of the register: the end of the table, the date the data was checked and the numbers of its sources.A page of the register: the end of the table, the date the data was checked and the numbers of its sources.
Severny Mayak, the invented company of the repository's examples: a table's request and the pages built from it.

Checks

Agents collect, the build does not trust them

The registers are collected by Claude Code agents: they go through official sites and bring, for every fact, the address of the page and a verbatim quote. The repository itself was written with Claude Code too, in all 433 commits.

An agent's word is not taken. A script fetches every page itself and looks for the quote and the value on it, a person settles what is in doubt, and only the import writes to the data.

LaTeX finishes without an error even when the PDF is already broken. So the build is held by 11 checks and 465 tests: it fails on a letter the font does not have, on a line wider than its column by more than 2 pt, on an undefined reference and on a font not embedded in the PDF.

collect_verify.py

ok the quote and the value are on the page

values-on-page the quote is not word for word, but the values are on the page

quote-not-on-page the quote is not on the page

value-not-on-page the value is not on the page

page-empty the page is empty or did not come

tls the machine does not trust the site's certificate, and the check is never switched off

no-url no address of a page

no-quote no quote

quality.py

a letter the font does not have

a line wider than its column by more than 2 pt

an undefined reference or citation

a font not found or substituted

LaTeX asks for another run

a font not embedded in the PDF