Inspiration
Math professors who write open-source textbooks are stuck in a painful loop: edit XML in a text editor → open a terminal → run a Docker build that takes 15 minutes → refresh a browser → realize one equation is wrong → repeat. There's no integrated workspace for it. Tools like Overleaf exist for LaTeX, but nothing exists for PreTeXt — the modern XML-based format used by university textbooks at Georgia Tech, MIT, and dozens of other institutions.
I'm a CS grad student at Vanderbilt. A professor in our math department showed me their workflow. I couldn't believe how broken it was for a format that produces genuinely beautiful output. So I built Proofdesk.
What it does
Proofdesk is a full-stack browser workspace that lets math professors write, build, preview, and publish PreTeXt textbooks without ever leaving their browser.
Write — Monaco editor (the engine behind VS Code) with PreTeXt XML syntax highlighting, full-text search across every file in the repository, and a LaTeX/PreTeXt snippet library for common blocks like theorems, definitions, and proofs.
Build — one click triggers the full PreTeXt → HTML pipeline inside a Docker container: TeX Live compiles LaTeX equations to PDF, fontforge extracts font metrics, Inkscape converts each equation to a crisp inline SVG. Every equation in the textbook renders as real vector math — not MathJax approximations.
Preview — a live side-by-side preview updates after each build. 31 interactive 3D visualizations built with MathBox.js (GPU-accelerated WebGL) let students explore eigenspaces, row reduction, orthogonal projection, and least-squares problems in real time.
Collaborate — WebSocket-powered real-time collaboration, in-browser terminal (node-pty + xterm.js), Git history browser, and one-click shareable preview links with a 7-day TTL. Send a draft chapter to a reviewer without them needing a GitHub account.
Publish — Export the entire built textbook as a self-contained ZIP. Deploy to any static host. No runtime dependencies.
How I built it
Frontend: React + TypeScript, Monaco editor, xterm.js, MathBox.js (WebGL), Playwright for E2E tests.
Backend: Node.js + Express, GitHub OAuth, WebSocket (ws), node-pty for real TTY terminal sessions, BullMQ + Redis for build job queuing, archiver for ZIP export.
Build pipeline: The hardest part. PreTeXt's toolchain was written for a specific era — Python 2, Ruby 2-era gems, Inkscape 0.9x CLI syntax, CoffeeScript 1.12.7, a custom SCons pipeline. I wrote a 720-line Docker build script that patches Python 2 idioms at build time without modifying the source repo permanently:
-
sedreplacesunichr()→chr()across Python files - Rewrites the Inkscape
inkscape_script()method for 1.x action syntax - Falls back from
compasstosass-embeddedwhen Ruby 3.2 rejects it - Patches SCons builder suffix declarations to fix cache-busting in the demo pipeline
- Wraps
git hash-objectcalls in try/except so missing intermediate files don't abort
The result: a fully reproducible Docker image that builds a 40-chapter math textbook with 750+ rendered equation SVGs from a completely unmodified upstream PreTeXt repo.
Infrastructure: EC2 t3.small, docker-compose, Nginx reverse proxy, DuckDNS, GitHub Actions for CI/CD with Playwright sanity tests on every deploy.
Challenges I ran into
The legacy dependency maze was the biggest one. The PreTeXt build toolchain spans four languages (Python, Ruby, CoffeeScript, XSL), three incompatible major versions of key tools, and a build system (SCons) that almost nobody uses anymore. Making all of this work reproducibly inside a modern Docker container on Ubuntu 24.04 required reverse-engineering error messages I had never seen before and patching code I didn't write.
The math rendering pipeline was non-trivial. Each equation takes a round-trip through pdflatex → fontforge → Inkscape before becoming an SVG. Getting fontforge to extract the right font metrics for the Charter typeface, and getting Inkscape 1.x to accept the rewritten CLI flags, took more debugging time than the entire React frontend.
Docker-in-Docker orchestration — the backend mounts the Docker socket and spawns isolated PreTeXt build containers on demand. Handling container lifecycle, cleanup on user disconnect, concurrent session limits, and OOM kills on a t3.small with 2GB RAM required careful resource management.
Localhost vs EC2 rendering differences — the deployed site has a text overlap bug I'm still actively debugging. My current theory is a Nginx MIME type misconfiguration for .woff2 font files causing the browser to fall back to a system font with different metrics. Working on it.
Accomplishments I'm proud of
- A 720-line build orchestration script that makes a Python 2 / Ruby 2 / Inkscape 0.9x toolchain work on modern infrastructure with zero permanent source modifications
- 31 GPU-accelerated interactive math visualizations running in the browser via MathBox.js
- A real TTY terminal session inside the browser using node-pty — same behavior as SSH, not a fake shell
- Full Playwright E2E test suite including GitHub OAuth smoke tests and multi-browser sanity checks
- A shareable preview link system that lets non-technical reviewers see a built textbook without any GitHub account
What I learned
Legacy compatibility is underrated as an engineering skill. The ability to make old code run on new infrastructure — without breaking the original — is something most CS programs don't teach but every production engineering team deals with constantly.
I also learned that the hardest bugs are the ones that only reproduce in production. The font rendering overlap on EC2 taught me that "it works on my machine" is not a deployment strategy, and that Nginx configuration deserves as much attention as application code.
What's next
- Fix the EC2 font rendering bug (actively working)
- Multi-textbook support — paste any PreTeXt GitHub URL and get a full workspace
- Student mode — read-only workspace with a purpose-limited AI tutor that can answer questions about the material but cannot do homework
- CRDT-based real-time collaboration for simultaneous multi-author editing
- Incremental builds — only rebuild changed chapters, cutting build time from 15 min to under 2 min
- LMS integration (Canvas, Blackboard) with SSO for institutional deployment
Built with
React TypeScript Node.js Express Docker Nginx Redis BullMQ Monaco Editor xterm.js MathBox.js WebGL node-pty Playwright GitHub OAuth AWS EC2 PreTeXt TeX Live Inkscape fontforge SCons Python Ruby CoffeeScript
Top comments (0)