Visruth Srimath Kandali

My Writing Stack

Background

I enjoy writing.

I’ve been writing for only about two years now; my style and content has obviously changed over time, but so has the very way I write. I handwrite some poems, but longer pieces, technical pieces, and editing pieces fare far better online. I used to use a single Google Doc, but that got unwieldy quickly. I swapped to Markdown, and wrote in Zettlr so I could build pieces and projects to PDF through Pandoc nicely. That worked for a while, but I got frustrated with the project system as I couldn’t figure out how to include pieces in projects without duplicating a file. This is a rough example of my file structure:

.
├── Prose
│   └── file.md
└── Projects
    └── Project 1
        └── file.md

I’m violating essential DRY–in this paradigm, when I wanted to make a change to file.md, I had to make sure to copy over the change to every other instance of file.md. So I eventually swapped to Typst.

Typst

I really like Typst. This is, in part, due to how elegant it is. It feels like a normal scripting language. To solve the issue sketched above, a single command suffices: # include (I wrap this in some super simple processing to make exports nicer, but it’s essentially just that.) Typst is best seen as an alternative to LaTeX, one without all the ugly syntax and confusion that I’ve found to be somewhat characteristic of casual LaTeX usage. I don’t really mind LaTeX, especially when given a template, but I won’t go out of my way to write it. I don’t know how to write styling for it, and it seems a touch annoying to do so; I like CS, but for writing I want something that just works. I don’t want to struggle with a template. I just want to write, and export pretty PDFs. For me, it is key that content is divested from styling. Also, waiting for LaTeX files to compile to see changes is annoying. So LaTeX is off the table.

Typst’s live preview is magical, and works brilliantly (most of the time–but that is an issue with my setup, not Typst.) Typst solves most of the qualms I have with LaTeX and is almost as clean as Markdown–but is far more extensible. I also think that scripting is cleaner in Typst (see below); it’s certainly easier for me to understand. I use Typst in Positron, because I really like Positron and use it for everything, and the Typst extensions (viz. Tinymist and Typst Companion) are good enough.

To separate my formatting and content concerns in Typst, I wrote a simple styling script. I have a snippet which handles the mundane work of applying the template, so I just have to make a new file, title it something, then I’m good to start writing.

 1#let apply-template(title, author: "Visruth Srimath Kandali", margin: 1in, size: 11pt, body) = {
 2  let title = smallcaps(title.replace(" (Unfinished)", "")) // cleanup titles if needed
 3
 4  // * Formatting
 5  set text(font: "New Computer Modern", size: size)
 6
 7  // * Spacing
 8  set page(margin: margin)
 9  set par(leading: 1em, spacing: 2em)
10
11  // * Headers
12  set page(
13    header: context {
14      let matches = query(heading)
15      let current = counter(page).get()
16      let has-header = matches.any(m => counter(page).at(m.location()) == current)
17      if not has-header {
18        text(13pt, emph(title))
19      }
20    },
21  )
22
23  //  * Footers
24  set page(numbering: "1")
25
26  // * Heading size control
27  show heading.where(level: 1): set text(30pt)
28  show heading.where(level: 2): set text(24pt)
29  show heading.where(level: 3): set text(14pt)
30
31  // * Final formatting of document
32  context {
33    heading(title, level: 1)
34    let spacing = 15pt
35    if here().page() == 1 {
36      // do this only if export is first true page, not just numbered 1
37      set document(title: title, author: author)
38      emph(text(author, 13pt))
39      v(-spacing)
40    }
41    v(spacing)
42    body
43  }
44}

It didn’t take much reading for me to figure out how to do this much, and I’m pretty satisfied with it. I’m sure it’s suboptimal, but it is good enough to get pretty PDFs.

I still have some gripes though.

The Typst community is smallish, which means (relatively) scarce online resources. My CV is still in LaTeX because I found a template online which I rather like and tweaked it to my liking. If I were to rewrite my CV in Typst, I think I would have to do so from scratch since I just couldn’t find one which I thought looked good. I might write my own CV template eventually, but for now I’d much rather just tweak a template than write one.

I also have a very specific complaint: I write poetry, so I make extensive use of hard line breaks, which look
like this

You can do so in Typst, but it belays the elegance I was just waxing about:

1line1 \
2line2 \
3
4line3 \
5line4 \

Which will render nicely as:

line1
line2

line3
line4

which works perfectly fine–but now I have all this ugly syntax in my source. (\ is being used as a shortcut for #linebreak()) In Markdown, I’d just tell Pandoc to use hard line breaks, and my source file is untouched. In Typst though, my endlines are littered with symbols for formatting, belaying the essential elegance of separate style and content, the elegance I enjoy so much in Typst elsewise.

I didn’t like this still. Markdown’s syntax is quite nice, especially since its ubiquity allows for me to copy source into foreign inputs and get parsed correctly (Typst uses some non-Markdown syntax, e.g. = for headings.) I thought of writing a simple transpiler allowing me to keep my Typst formatting but have the content stored in a Markdown file, with Markdown syntax; with that in mind, I searched online for the existence of a Typst to Markdown transpiler and happened upon cmarker.

cmarker

There’s not much for me to say–cmarker does exactly what I want it to: convert Markdown to Typst. It has more guarantees than the transpiler I was going to write, but is still pretty simple. cmarker slotted into my stack beautifully–I changed my snippet slightly, and I was off to the races. (I swapped from snippet to a custom build task DeepSeek wrote for me which makes $FILE.md and $FILE.typ with prompts for folder structure and title. My point still stands though.) I have a repo for my website, and a separate one for my writing–but Hugo compiles Markdown, and up till now I only had Typst sources. This new stack allows for me to copy paste files into my blog so easily.

Conclusion

A quick rundown of what software I use to write.

Writing:

  1. Positron, as my text editor
  2. Markdown, for content (imported in Typst by cmarker)
  3. Typst, for styling and compilation

Website:

  1. Positron, as my text editor
  2. Markdown, for content
  3. Hugo, for styling and compilation