What I shipped
KakutiResume is now live at [resume.kakuti.site](https://resume.kakuti.site/). It compiles the Typst typesetting engine to WebAssembly and runs the entire document pipeline — editing, typesetting, PDF generation — in the browser. Zero backend, zero accounts.
Why I built it
Every online resume tool uploads your data to a server for PDF generation. For a document that contains your name, address, phone, and full work history, that's a privacy problem. I wanted to see if I could run a professional typesetting engine directly in the browser.
How it works
Typst is written in Rust, which compiles to WebAssembly. Two WASM binaries — a compiler (~8 MB) and renderer (~5 MB) — run inside a Web Worker so the UI never blocks. The editor is a Notion-style block interface. Rich text formatting maps to Typst markup, which gets compiled into PDFs and SVG previews.
Hardest parts
- contentEditable + React. Selection preservation across re-renders required DOM TreeWalker path tracking. The dual WYSIWYG/Markdown mode was my escape hatch when contentEditable misbehaved.
- WASM template injection. Typst templates use `#import` for external files, but there's no filesystem in the sandbox. I strip imports and inject mock implementations before compilation.
- PDF import parser. Extracting structured content from arbitrary PDF resumes using only heuristics — font size thresholds, position alignment, regex. No AI, no OCR.
What went wrong
- The 13 MB WASM payload is heavy on first load. HTTP caching helps, but I should have added service worker precaching earlier.
- CJK font loading from CDN is surprisingly slow. 60-second timeout was necessary.
- Underestimated the debugging time for contentEditable edge cases (IME, copy-paste, undo/redo).
What's next
- PWA support for offline editing
- Cover letter templates
- More template options
Links
- Live: [resume.kakuti.site](https://resume.kakuti.site/)
- Source: [github.com/kakutixyz-ai/kakuti-resume](https://github.com/kakutixyz-ai/kakuti-resume)