Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

LaTeX & Typst (papers, theses, resumes and slides)  Module 12 – Automation, collaboration, conversion and publishing

Converting between LaTeX, Typst, Word and Markdown

Convert documents between LaTeX, Typst, Word and Markdown with pandoc, see exactly what each conversion dropped, and check the result before you trust it.

  • Intermediate
  • 15 minutes
  • Examples run with TeX Live 2026, TinyTeX 2026.10, Typst 0.15.1, Python 3.14.8, Pyodide 314.0.7, pandoc 3.12 and poppler 26.09.0
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Convert a document between LaTeX, Typst, Word and Markdown with pandoc
  • Identify what a conversion kept, changed and dropped, from pandoc's messages and the compiled PDFs
  • Convert LaTeX maths to Typst and check every formula
  • Generate HTML from LaTeX with TeX4ht and from Typst, and compare what each leaves out
  • Verify a converted document by its counts of headings, equations and tables and by the text of its PDF

Before you start

What you’ll learn · Before you start

What you will learn

  • Convert a document between LaTeX, Typst, Word and Markdown with pandoc
  • Identify what a conversion kept, changed and dropped, from pandoc's messages and the compiled PDFs
  • Convert LaTeX maths to Typst and check every formula
  • Generate HTML from LaTeX with TeX4ht and from Typst, and compare what each leaves out
  • Verify a converted document by its counts of headings, equations and tables and by the text of its PDF

Before you start

On this page

A short LaTeX note, converted to Typst by one pandoc command and compiled inside a small frame written by hand, still said “Table Table 1”, “Equation [eq:mean]” and “Section Section 1”, and it had lost a drawing without an error. A conversion that compiles is not yet a conversion that is right.

This lesson converts one note between LaTeX, Typst, Word and Markdown with pandoc, and turns it into HTML twice. For each conversion you will see what pandoc reported, what the new file says on the page, and how to prove, by counting and by comparing the text of the PDFs, that nothing went missing. Every session was recorded with pandoc 3.12, TeX Live 2026 and Typst 0.15.1.

pandoc reads a document into a tree, then writes the tree again

pandoc does not translate LaTeX into Typst directly. A reader parses the input into pandoc’s own document tree: pandoc's own representation of a document: blocks such as headings, paragraphs and tables, holding inlines such as words, emphasis, maths and citations. Every reader builds it and every writer works from it., and a writer turns the tree into the output format, so any reader can feed any writer. Its manual says the cost plainly: the tree is less expressive than many formats, so “one should not expect perfect conversions between every format and every other”. This is the note, and the start of its tree:

note.tex: a note with what a conversion has to carry TEX · note/note.tex
% note.tex: a short field note with the things a conversion has to carry.
\documentclass{article}
\usepackage{amsmath}
\usepackage{booktabs}
\usepackage{tikz}
\usepackage[numbers]{natbib}
\newcommand{\mean}[1]{\bar{#1}}
\title{Rain on two roofs}
\author{Meera Pillai}
\date{}
\begin{document}
\maketitle
\section{Method}\label{sec:method}
Two gauges logged the rain for \emph{two weeks}\footnote{Readings were taken at 8 a.m.} \citep{rao2025gauges}.
The daily mean of roof $r$ is
\begin{equation}\label{eq:mean}
  \mean{x}_r = \frac{1}{n}\sum_{i=1}^{n} x_{r,i}
\end{equation}
and Table~\ref{tab:totals} lists the totals.
\begin{itemize}
  \item Block A faces east.
  \item Block B faces west.
\end{itemize}
\section{Result}
\begin{table}[h]
  \centering
  \caption{Totals for two weeks}\label{tab:totals}
  \begin{tabular}{lr}
    \toprule
    Roof & Rain (mm) \\
    \midrule
    Block A & 83.0 \\
    Block B & 76.5 \\
    \bottomrule
  \end{tabular}
\end{table}
Equation~\eqref{eq:mean} gives $\mean{x}_A = 5.93$\,mm a day, as Section~\ref{sec:method} explains.
\begin{tikzpicture}
  \draw (0,0) rectangle (2,1) node[midway] {Block A};
\end{tikzpicture}
\bibliographystyle{plainnat}
\bibliography{refs}
\end{document}
The start of note.tex as pandoc's document tree Python · tree_session.py
from session import files, needs, run

# What pandoc reads: the start of note.tex as pandoc's own document tree (-t native), which every writer works from.
needs("pandoc")
files("note/note.tex")
run("""
pandoc note.tex -t native | head -24
""")

Output

$ pandoc note.tex -t native | head -24
[ Header 1 ( "sec:method" , [] , [] ) [ Str "Method" ]
, Para
    [ Str "Two"
    , Space
    , Str "gauges"
    , Space
    , Str "logged"
    , Space
    , Str "the"
    , Space
    , Str "rain"
    , Space
    , Str "for"
    , Space
    , Emph [ Str "two" , Space , Str "weeks" ]
    , Note
        [ Para
            [ Str "Readings"
            , Space
            , Str "were"
            , Space
            , Str "taken"
            , Space
            , Str "at"

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 tree_session.py

The first section became Header 1 ( "sec:method" , [] , [] ) [ Str "Method" ]: a level, the label, and the words. A sentence became a Para of Str and Space items, the emphasis an Emph, the footnote a Note. Step through what happened to the whole note on its way to Typst:

Interactive · stage by stage How pandoc turned note.tex into Typst Step through the conversion and watch what the reader keeps, what it drops, and what the writer makes of the rest.
How pandoc turned note.tex into Typst, step 6 of 6. Showing note.tex, LaTeX reader (4 commands skipped), Document tree (Header 1 "sec:method"), Typst writer (figure, @key, #footnote), body.typ. In focus: body.typ.skippednote.texLaTeX: macros, a table, TikZLaTeX reader4 commands skippedDocument treeHeader 1 "sec:method"Typst writerfigure, @key, #footnotebody.typready to include

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. One file in. pandoc note.tex -t typst reads a short note with a title, two sections, a footnote, a citation, an equation with a custom macro, a booktabs table and a TikZ picture.
  2. The reader builds a tree. The LaTeX reader turns the text into pandoc's own document tree: -t native printed Header 1 ( "sec:method" , [] , [] ) [ Str "Method" ] for the first section, and a Para of Str and Space items for its sentence.
  3. Macros are expanded on the way. The reader parsed \newcommand{\mean}[1]{\bar{#1}} and applied it, so the tree holds the bar accent itself: the Typst output says macron(x), and no \mean is left.
  4. Some commands are dropped. With --verbose, pandoc listed four things it skipped: \maketitle, \centering, the whole tikzpicture and \bibliographystyle{plainnat}. Nothing else said the drawing was gone.
  5. The writer makes Typst. The Typst writer turned the table into figure(table(...), kind: table), the citation into @rao2025gauges, the footnote into #footnote[...] and the label of the section into <sec:method>.
  6. The body, not a document. Without -s, pandoc wrote only the body. main.typ, written by hand, sets numbering for headings and equations, puts table captions on top and includes body.typ, so the layout is yours, not pandoc's template.

Two things follow from the tree. Anything the tree has no node for, such as a TikZ picture, cannot reach any output: the reader skips it, and says so only when asked with --verbose. And a custom macro is applied, not kept: pandoc read \newcommand{\mean}[1]{\bar{#1}} and expanded every use, so the Typst file has macron(x) where note.tex had \mean{x}, and a reader of the Typst file never learns that the macro existed.

Checkpoint

Check: pandoc's document tree

  1. Question 1 of 2 Why could no pandoc writer, Typst or any other, keep the TikZ picture of note.tex?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The LaTeX reader skipped it, so it never reached the document tree that every writer works from

    A reader and a writer meet only in the tree. What the reader cannot express as a node, every output loses.

  2. Question 2 of 2 note.tex defines \mean and writes \mean{x}. What did the converted Typst file contain?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: macron(x), the macro's meaning, with no \mean left

    Expanded macros convert correctly but leave the new file without the shorthand; define it again as a Typst function if the document needs it.

From LaTeX to Typst, the text arrives and the references need work

pandoc can write a whole Typst document with its own template (-s), or only the body, which a Typst file of your own then includes. This session tries the first, converts the body with --verbose to see what was skipped, compiles it inside a hand-written main.typ, and compares three sentences of the two PDFs:

main.typ: the frame of the converted note, written by hand TYP · note/main.typ
// main.typ: the frame of the converted note, written by hand. pandoc converts only the body, into body.typ.
#set document(title: [Rain on two roofs], author: "Meera Pillai")
#set page(paper: "a4")
#set heading(numbering: "1")
#set math.equation(numbering: "(1)")
#show figure.where(kind: table): set figure.caption(position: top)
#align(center)[
  #text(17pt)[Rain on two roofs] \
  Meera Pillai
]

#include "body.typ"

#bibliography("refs.bib", title: [References])
note.tex to Typst: a whole document, then the body inside main.typ Python · convert_session.py
from session import files, needs, run

# note.tex converted to Typst twice: first as a whole document with pandoc's own template, then only the body, which
# main.typ, written by hand, includes. Then three sentences of the LaTeX PDF and of the Typst PDF side by side, and
# how often each PDF's text says Block A.
needs("pandoc", "typst", "pdflatex", "latexmk", "pdftotext", "git")
files("note/note.tex", "note/refs.bib", "note/main.typ")
run("""
!pandoc -s note.tex -o whole.typ && typst compile whole.typ
pandoc --verbose note.tex -t typst -o body.typ 2>&1 | grep 'Skipped'
typst compile main.typ note-typst.pdf
latexmk -pdf -silent note.tex > /dev/null 2>&1
pdftotext note.pdf latex.txt && pdftotext note-typst.pdf typst.txt
grep -E 'daily mean|lists the totals|explains' latex.txt typst.txt
grep -c 'Block A' latex.txt typst.txt
""", env={"SOURCE_DATE_EPOCH": "1767225600"})

Output

$ pandoc -s note.tex -o whole.typ && typst compile whole.typ
error: cannot reference heading without numbering
    ┌─ whole.typ:182:16
    │
182 │ day, as Section~@sec:method explains.
    │                 ^^^^^^^^^^^
    │
    = hint: you can enable heading numbering with `#set heading(numbering: "1.")`

[exit status 1]
$ pandoc --verbose note.tex -t typst -o body.typ 2>&1 | grep 'Skipped'
[INFO] Skipped '\maketitle' at note.tex line 12 column 11
[INFO] Skipped '\centering' at note.tex line 26 column 13
[INFO] Skipped '\begin{tikzpicture}
[INFO] Skipped '\bibliographystyle{plainnat}' at note.tex line 41 column 29
$ typst compile main.typ note-typst.pdf
$ latexmk -pdf -silent note.tex > /dev/null 2>&1
$ pdftotext note.pdf latex.txt && pdftotext note-typst.pdf typst.txt
$ grep -E 'daily mean|lists the totals|explains' latex.txt typst.txt
latex.txt:Two gauges logged the rain for two weeks 1 [1]. The daily mean of roof r is
latex.txt:and Table 1 lists the totals.
latex.txt:Equation (1) gives x̄A = 5.93 mm a day, as Section 1 explains.
typst.txt:Two gauges logged the rain for two weeks1 [1]. The daily mean of roof 𝑟 is
typst.txt:and Table Table 1 lists the totals.
typst.txt:Equation [eq:mean] gives 𝑥̄𝐴 = 5.93 mm a day, as Section Section 1 explains.
$ grep -c 'Block A' latex.txt typst.txt
latex.txt:3
typst.txt:2

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 convert_session.py

The whole document stopped at once: cannot reference heading without numbering, because pandoc’s template leaves headings unnumbered while the text refers to them. The body compiled inside main.typ, which numbers headings and equations, and the three sentences then showed the faults a reader would see:

What note.tex says What the converted note printed Why
Table~\ref{tab:totals} Table Table 1 Typst’s @tab:totals prints the word Table itself, so the word before it doubles
Section~\ref{sec:method} Section Section 1 The same doubling, for a section
Equation~\eqref{eq:mean} Equation [eq:mean] pandoc wrote \eqref as a link with the label as its text
a tikzpicture labelled Block A nothing Skipped by the reader; Block A appeared 3 times in the LaTeX text and 2 in the Typst text

pandoc’s --verbose messages named four skipped commands, \maketitle, \centering, the tikzpicture and \bibliographystyle, but the doubled words and the wrong reference compiled without a message. The Typst guide for LaTeX users points to the same route, pandoc, and says the Typst web app has the conversion built in; either way, the result has to be checked.

Convert the body, write the frame

Let pandoc convert the text and keep the layout in a Typst file you write yourself, such as main.typ: numbering, captions, fonts and the title are then yours, and a later conversion of the body changes none of them.

Checkpoint

Check: LaTeX to Typst with pandoc

  1. Question 1 of 2 The converted note printed Table Table 1 where note.tex said Table~\ref{tab:totals}. Why?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Typst's @tab:totals prints the word Table with the number, and the word written before it stayed

    LaTeX's \ref prints only the number, so authors write the word; Typst's references print both. Every converted reference needs its word removed.

  2. Question 2 of 2 pandoc -s note.tex -o whole.typ, then typst compile whole.typ. What happened?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It stopped with cannot reference heading without numbering, because pandoc's template leaves headings unnumbered

    Writing your own frame, such as main.typ, and converting only the body puts numbering and layout under your control.

Maths converts formula by formula

Maths is the part pandoc converts best, because LaTeX maths has a node of its own in the tree. Ten formulas, each as pandoc wrote it, and the converted file compiled as a check:

maths.tex: ten formulas TEX · maths/maths.tex
$\frac{a+b}{2}$

$\sqrt[3]{x}$

$x \in \mathbb{R}$

$\hat{\theta} = \operatorname{arg\,max}_\theta L(\theta)$

$|x| = \begin{cases} x & \text{if } x \ge 0 \\ -x & \text{otherwise} \end{cases}$

$\left( \frac{1}{2} \right)^n$

$\int_0^1 x^2 \, \mathrm{d}x = \tfrac{1}{3}$

$A = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}$

$\vec{v} \cdot \vec{w} \le \lVert v \rVert \lVert w \rVert$

$\mathcal{O}(n \log n)$
Ten formulas from LaTeX to Typst Python · maths_session.py
from session import files, needs, run

# Ten LaTeX formulas, each as pandoc writes it in Typst, then the converted file compiled as a check.
needs("pandoc", "typst")
files("maths/maths.tex")
run("""
pandoc maths.tex -t typst
pandoc maths.tex -t typst -o maths.typ && typst compile maths.typ
""", env={"SOURCE_DATE_EPOCH": "1767225600"})

Output

$ pandoc maths.tex -t typst
$frac(a + b, 2)$

$root(3, x)$

$x in bb(R)$

$hat(theta) = "arg max"_theta L\(theta\)$

$\|x\|= cases(delim: "{", x & upright("if ") x gt.eq 0, - x & upright("otherwise"))$

$(1 / 2)^n$

$integral_0^1 x^2 thin upright(d) x = 1 / 3$

$A = mat(delim: "(", 1, 2; 3, 4)$

$arrow(v) dot.op arrow(w) lt.eq lr(bar.v.double v bar.v.double) lr(bar.v.double w bar.v.double)$

$cal(O)\(n log n\)$
$ pandoc maths.tex -t typst -o maths.typ && typst compile maths.typ

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 maths_session.py

All ten compiled. Most need nothing more, and a few are worth a look before you keep them:

LaTeX pandoc’s Typst Look at
\frac{a+b}{2} frac(a + b, 2) nothing; the same fraction
\sqrt[3]{x} root(3, x) nothing
x \in \mathbb{R} x in bb(R) nothing
\operatorname{arg\,max}_\theta "arg max"_theta an upright text operator; check where the subscript sits
\begin{cases} … \end{cases} cases(delim: "{", …) \text{if } became upright("if ")
\lVert v \rVert lr(bar.v.double v bar.v.double) correct but long; norm(v) reads better
L(\theta) L\(theta\) escaped brackets, which print as plain brackets

When a maths-heavy file must keep its LaTeX syntax for a while, MiTeX, a package on Typst Universe described as “LaTeX support for Typst, powered by Rust and WASM”, renders LaTeX maths inside a Typst document with #mi(...) and #mitex(...).

Trusting a formula because it compiled

Wrong: compiling the converted maths and moving on. Right: compare each formula on the page with the LaTeX PDF, at least once, because a formula can compile and mean something else, for example when brackets group differently.

Checkpoint

Check: Converting maths

  1. One question pandoc wrote \begin{cases} x & \text{if } x \ge 0 ... as which Typst code?

    Choose one answer.

    Show the answer: One question

    Answer: cases(delim: "{", x & upright("if ") x gt.eq 0, ...)

    Maths converts well because LaTeX maths is kept whole in the tree; check each formula on the page once anyway.

Word and Markdown keep the structure, not the LaTeX

A .docx file is a ZIP package of XML parts, defined by the ECMA-376 standard. pandoc’s manual says that maths in a Word file is written as OMML: Office Math Markup Language, the XML in which Word files store equations, as m:oMath elements, so that they stay editable in a word processor., Word’s own maths markup. This session writes the note as a Word file with citations formatted by pandoc’s --citeproc, lists what the file holds, reads it back as Markdown, and then turns a Markdown file of lecture notes into a PDF through Typst:

notes.md: lecture notes in Markdown Markdown · md/notes.md
---
title: Rain gauges on flat roofs
author: Meera Pillai
---

# What we measured

Two gauges logged the rain on two roofs for two weeks [@rao2025gauges].
Each daily reading $x_i$ was added up, so the total of a roof is $\sum_{i=1}^{14} x_i$.

| Roof    | Rain (mm) |
|---------|----------:|
| Block A |      83.0 |
| Block B |      76.5 |

# What to do next

- Read both gauges at the same time each day.
- Write *missing* when a reading cannot be taken.
LaTeX to Word and back to Markdown; Markdown to PDF through Typst Python · word_md_session.py
from session import files, needs, run

# The note as a Word file, what the file holds, and the Word file read back as Markdown; then Markdown notes turned
# into a PDF through Typst, with citations formatted by pandoc's citeproc.
needs("pandoc", "typst", "pdftotext")
files("note/note.tex", "note/refs.bib", "md/notes.md", "docx_parts.py")
run("""
pandoc note.tex --citeproc --bibliography=refs.bib --number-sections -o note.docx
python3 docx_parts.py note.docx
pandoc note.docx -t markdown --wrap=none
pandoc notes.md --citeproc --bibliography=refs.bib --pdf-engine=typst -o notes.pdf
pdfinfo notes.pdf | grep -E 'Creator|Tagged|Pages'
pdftotext notes.pdf - | grep 'Rao'
""", env={"SOURCE_DATE_EPOCH": "1767225600"})

Output

$ pandoc note.tex --citeproc --bibliography=refs.bib --number-sections -o note.docx
$ python3 docx_parts.py note.docx
16 parts, among them: word/document.xml, word/numbering.xml, word/styles.xml, word/footnotes.xml, word/comments.xml, word/settings.xml, word/fontTable.xml, word/webSettings.xml
paragraph styles: Author 1, Bibliography 1, BodyText 1, Compact 6, FirstParagraph 5, Heading1 2, TableCaption 1, Title 1
equations (m:oMath): 3
$ pandoc note.docx -t markdown --wrap=none
# 1 Method

Two gauges logged the rain for *two weeks*[^1] (Rao and Kulkarni 2025). The daily mean of roof $r$ is

$${\bar{x}}_{r} = \frac{1}{n}\sum_{i = 1}^{n}x_{r,i}$$

and Table [1](#_8ddf680cae075dc657fb546cd9f3f5f778cab5e) lists the totals.

- Block A faces east.

- Block B faces west.

# 2 Result

  -------------------------------------------------------------
  Roof                           Rain (mm)
  ------------------------------ ------------------------------
  Block A                        83.0

  Block B                        76.5
  -------------------------------------------------------------

  : Totals for two weeks

Equation [\[eq:mean\]](#_908f492889e3ae7c115bf8154b176a12b022e3a) gives ${\bar{x}}_{A} = 5.93$ mm a day, as Section [1](#_09ee8443ab55a3f30fdd88acf82bf7f547c29d1) explains.

Rao, Asha, and Dev Kulkarni. 2025. "Low-Cost Rain Gauges on Flat Roofs." *Journal of Example Hydrology* 12: 40--52. <https://doi.org/10.5555/jeh.2025.040>.

[^1]: Readings were taken at 8 a.m.
$ pandoc notes.md --citeproc --bibliography=refs.bib --pdf-engine=typst -o notes.pdf
$ pdfinfo notes.pdf | grep -E 'Creator|Tagged|Pages'
Creator:         Typst 0.15.1
Tagged:          yes
Pages:           1
$ pdftotext notes.pdf - | grep 'Rao'
Two gauges logged the rain on two roofs for two weeks (Rao and Kulkarni 2025). Each daily
Rao, Asha, and Dev Kulkarni. 2025. “Low-Cost Rain Gauges on Flat Roofs.” Journal of Example

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 word_md_session.py

The Word file had 16 parts and Word’s own paragraph styles, Title, Author, Heading1 for the two sections and TableCaption for the caption, and its three formulas were m:oMath equations. Read back as Markdown, the structure had survived, and so had the faults: the reference to the equation still read [eq:mean], and the citation had become (Rao and Kulkarni 2025), because citeproc formats in the Chicago author-date style unless it is given a style. --pdf-engine=typst made a one-page PDF whose pdfinfo said Creator: Typst 0.15.1 and Tagged: yes.

Route What survived What to fix by hand
LaTeX to Word headings as Heading 1, the table, the footnote, maths as Word equations, citations formatted the citation style, references made by \eqref
Word to Markdown headings, lists, the table, maths as LaTeX maths links to Word bookmarks in place of labels
Markdown to PDF through Typst headings, the table, maths, citations, a tagged PDF nothing in these notes; Markdown itself has no numbered references

MySmartCoPilot’s Markdown to Word and Markdown to PDF tools do the last two routes in your browser, for notes that need no numbering.

Markdown, HTML & Text to Word (DOCX) Turn Markdown notes into an editable Word file with real heading styles.

Checkpoint

Check: Word and Markdown routes

  1. Question 1 of 2 In what form did the three formulas of note.tex reach the Word file?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: As Word equations, m:oMath elements of Office Math Markup

    The manual says maths in a Word file is written as OMML, so a Word user can edit the formulas.

  2. Question 2 of 2 note.tex cites with natbib in numbered style, yet the Word file said (Rao and Kulkarni 2025). Why?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: citeproc formats citations in the Chicago author-date style unless it is given a style

    Give citeproc the venue's CSL file when the form of the citations matters.

HTML from LaTeX and from Typst keeps different things

A web page needs HTML, and both systems can write it. For LaTeX the tool is TeX4ht; its CTAN entry calls make4ht a simple build system for it, but make4ht stopped here because a module of the LuaXML package was missing from this lesson’s TinyTeX, so the session uses TeX4ht’s older driver, htlatex, which needs nothing more. Typst has an HTML export of its own, which its reference says is experimental, needs --features html and should not be used for production. The session converts the corrected note both ways and counts what each HTML file kept:

html_count.py: what an HTML file kept Python · html_count.py
"""Counts what an HTML file kept of a document: headings, MathML formulas, images, inline styles and style blocks.

    python3 html_count.py note.html

The counts come from the tags in the file, read with Python's HTML parser.
"""

import sys
from html.parser import HTMLParser


class Counter(HTMLParser):
    def __init__(self):
        super().__init__()
        self.headings, self.maths, self.images, self.styles, self.blocks, self.title = [], 0, [], 0, 0, ""
        self._in = None

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if "style" in attrs:
            self.styles += 1
        if tag in ("h1", "h2", "h3", "h4"):
            self._in = tag
            self.headings.append([tag, ""])
        elif tag == "title":
            self._in = "title"
        elif tag == "math":
            self.maths += 1
        elif tag == "img":
            self.images.append(attrs.get("src", ""))
        elif tag == "style":
            self.blocks += 1

    def handle_endtag(self, tag):
        if tag == self._in:
            self._in = None

    def handle_data(self, data):
        if self._in == "title":
            self.title += data
        elif self._in:
            self.headings[-1][1] += data


with open(sys.argv[1], encoding="utf-8", errors="replace") as file:
    counter = Counter()
    counter.feed(file.read())
print(f"title: {counter.title.strip()}")
for tag, text in counter.headings:
    print(f"{tag}: {' '.join(text.split())}")
print(f"MathML formulas: {counter.maths}, images: {', '.join(counter.images) or 'none'}")
print(f"style attributes: {counter.styles}, style blocks: {counter.blocks}")
HTML from note.tex with TeX4ht, and from the Typst note Python · html_session.py
from session import files, needs, run

# HTML from both sources. For note.tex, after a latexmk build that writes the .bbl it needs: make4ht, which stops
# because a module of LuaXML is not installed in this TinyTeX, then TeX4ht's older driver htlatex. For the converted
# and corrected note: Typst's experimental HTML export. html_count.py then counts what each HTML file kept.
needs("pdflatex", "latexmk", "htlatex", "typst")
files("note/note.tex", "note/refs.bib", "note/main.typ", "note/body-fixed.typ=body.typ", "html_count.py")
run("""
latexmk -pdf -silent note.tex > /dev/null 2>&1
!make4ht note.tex 'mathml' > make4ht.log 2>&1
grep -o "module 'luaxml[a-z-]*' not found" make4ht.log
htlatex note.tex 'xhtml,mathml' > htlatex.log 2>&1
ls note*.html note*.svg note.css
python3 html_count.py note.html
typst compile --features html --format html main.typ note-typst.html 2>&1 | grep '^warning'
python3 html_count.py note-typst.html
""", env={"SOURCE_DATE_EPOCH": "1767225600"})

Output

$ latexmk -pdf -silent note.tex > /dev/null 2>&1
$ make4ht note.tex 'mathml' > make4ht.log 2>&1
[exit status 1]
$ grep -o "module 'luaxml[a-z-]*' not found" make4ht.log
module 'luaxml-domobject' not found
$ htlatex note.tex 'xhtml,mathml' > htlatex.log 2>&1
$ ls note*.html note*.svg note.css
note.css
note.html
note0x.svg
note2.html
$ python3 html_count.py note.html
title: Rain on two roofs
h1: Rain on two roofs
h3: 1 Method
h3: 2 Result
h3: References
MathML formulas: 3, images: note0x.svg
style attributes: 11, style blocks: 0
$ typst compile --features html --format html main.typ note-typst.html 2>&1 | grep '^warning'
warning: html export is under active development and incomplete
warning: page set rule was ignored during HTML export
warning: align was ignored during HTML export
warning: align was ignored during HTML export
warning: rect was ignored during HTML export
$ python3 html_count.py note-typst.html
title: Rain on two roofs
h2: 1 Method
h2: 2 Result
h2: References
MathML formulas: 3, images: none
style attributes: 2, style blocks: 1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 html_session.py

Part of the note TeX4ht (htlatex) Typst HTML export
Title an h1 and the <title> the <title> only; the centred title block was ignored
Sections h3 headings h2 headings
Formulas 3 in MathML: The W3C's markup language for mathematics, which records a formula's structure, such as which part is a fraction or a power, so that browsers can lay it out and assistive technology can read it. More in “Maths fonts, symbol lookup and accessible equations” 3 in MathML
The Block A drawing note0x.svg, an image dropped: rect was ignored during HTML export
Styling a note.css file and 11 style attributes 1 style block and 2 style attributes

Typst listed what it ignored as warnings: the page settings, both align calls and the rect. TeX4ht kept the drawing as an SVG image. Its style attributes matter for any site whose security policy forbids inline styles, which must strip them or move them to classes.

Checkpoint

Check: HTML from both systems

  1. One question Which HTML file kept the Block A drawing, and in what form?

    Choose one answer.

    Show the answer: One question

    Answer: TeX4ht's note.html, as the image note0x.svg

    Typst's HTML export is experimental and says what it ignores in warnings; read them, then check the page.

A conversion is checked by its counts and its words

Compiling proves only that the new file is valid. Two checks prove that it says what the old one said. Count the parts that both should have, here with grep on note.tex and, for Typst, with typst eval and query(), which its reference describes as finding elements in the document; then compare the same sentences of both PDFs again after the fixes. This session compares pandoc’s body with the corrected one, then runs both checks:

body-fixed.typ: pandoc's body, corrected by hand TYP · note/body-fixed.typ
= Method
<sec:method>
Two gauges logged the rain for #emph[two weeks]#footnote[Readings were
taken at 8 a.m.] @rao2025gauges. The daily mean of roof $r$ is
$ macron(x)_r = 1 / n sum_(i = 1)^n x_(r\,i) $<eq:mean> and
@tab:totals lists the totals.

- Block A faces east.

- Block B faces west.

= Result
<result>
#figure(
  align(center)[#table(
    columns: 2,
    align: (left,right,),
    table.header([Roof], [Rain (mm)],),
    table.hline(),
    [Block A], [83.0],
    [Block B], [76.5],
  )]
  , caption: [Totals for two weeks]
  , kind: table
  )
<tab:totals>

@eq:mean gives $macron(x)_A = 5.93$ mm a
day, as @sec:method explains.

// The TikZ picture of note.tex, which pandoc skipped, drawn again in Typst.
#rect(width: 2cm, height: 1cm, inset: 0pt)[#align(center + horizon)[Block A]]
The fixes, then the counts and the sentences checked Python · check_session.py
from session import files, needs, run

# The converted body against the corrected one, then the corrected note checked: the numbered headings, display
# equations and tables of each source and document counted, and the same sentences of the two PDFs compared again.
needs("pandoc", "typst", "pdflatex", "latexmk", "pdftotext", "git")
files("note/note.tex", "note/refs.bib", "note/main.typ", "note/body-fixed.typ")
run("""
pandoc note.tex -t typst -o body.typ
!git diff --no-index -U0 body.typ body-fixed.typ
cp body-fixed.typ body.typ && typst compile main.typ note-typst.pdf
grep -c -E '^.section' note.tex
grep -c -E 'begin.equation' note.tex
grep -c -E 'begin.table' note.tex
typst eval 'query(heading.where(numbering: "1")).len()' --in main.typ
typst eval 'query(math.equation.where(block: true)).len()' --in main.typ
typst eval 'query(figure.where(kind: table)).len()' --in main.typ
latexmk -pdf -silent note.tex > /dev/null 2>&1
pdftotext note.pdf latex.txt && pdftotext note-typst.pdf typst.txt
grep -E 'daily mean|lists the totals|explains' latex.txt typst.txt
grep -c 'Block A' latex.txt typst.txt
""", env={"SOURCE_DATE_EPOCH": "1767225600"})

Output

$ pandoc note.tex -t typst -o body.typ
$ git diff --no-index -U0 body.typ body-fixed.typ
diff --git a/body.typ b/body-fixed.typ
index 4acbeaa..b7d9cfd 100644
--- a/body.typ
+++ b/body-fixed.typ
@@ -6 +6 @@ $ macron(x)_r = 1 / n sum_(i = 1)^n x_(r\,i) $<eq:mean> and
-Table~@tab:totals lists the totals.
+@tab:totals lists the totals.
@@ -28,2 +28,5 @@ Table~@tab:totals lists the totals.
-Equation~#link(<eq:mean>)[\[eq:mean\]] gives $macron(x)_A = 5.93$ mm a
-day, as Section~@sec:method explains.
+@eq:mean gives $macron(x)_A = 5.93$ mm a
+day, as @sec:method explains.
+
+// The TikZ picture of note.tex, which pandoc skipped, drawn again in Typst.
+#rect(width: 2cm, height: 1cm, inset: 0pt)[#align(center + horizon)[Block A]]
[exit status 1]
$ cp body-fixed.typ body.typ && typst compile main.typ note-typst.pdf
$ grep -c -E '^.section' note.tex
2
$ grep -c -E 'begin.equation' note.tex
1
$ grep -c -E 'begin.table' note.tex
1
$ typst eval 'query(heading.where(numbering: "1")).len()' --in main.typ
2
$ typst eval 'query(math.equation.where(block: true)).len()' --in main.typ
1
$ typst eval 'query(figure.where(kind: table)).len()' --in main.typ
1
$ latexmk -pdf -silent note.tex > /dev/null 2>&1
$ pdftotext note.pdf latex.txt && pdftotext note-typst.pdf typst.txt
$ grep -E 'daily mean|lists the totals|explains' latex.txt typst.txt
latex.txt:Two gauges logged the rain for two weeks 1 [1]. The daily mean of roof r is
latex.txt:and Table 1 lists the totals.
latex.txt:Equation (1) gives x̄A = 5.93 mm a day, as Section 1 explains.
typst.txt:Two gauges logged the rain for two weeks1 [1]. The daily mean of roof 𝑟 is
typst.txt:and Table 1 lists the totals.
typst.txt:Equation 1 gives 𝑥̄𝐴 = 5.93 mm a day, as Section 1 explains.
$ grep -c 'Block A' latex.txt typst.txt
latex.txt:3
typst.txt:3

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 check_session.py

The fixes were two hunks: Table~ and Section~ removed before their references, @eq:mean in place of the link, and the Block A box drawn again with rect. Both sides then counted 2 numbered sections, 1 display equation and 1 table, the sentences read Table 1, Equation 1 and Section 1, and Block A appeared 3 times in each text. Follow the checks in order:

Interactive · stage by stage Checking a conversion until nothing is missing Step through the checks in the order the lesson ran them, and see which check found which fault.
Checking a conversion until nothing is missing, step 6 of 6. Showing Compile (no error), Count the parts (2, 1 and 1 on both sides), Compare the text (3 faults, 1 lost drawing), Fix body.typ (2 hunks: 3 fixes, 1 box), Same words and parts. In focus: Same words and parts.build againCompileno errorCount the parts2, 1 and 1 on both sidesCompare the text3 faults, 1 lost drawingFix body.typ2 hunks: 3 fixes, 1 boxSame words and partswhat is left is expected

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. It compiles, so check it. main.typ with pandoc's body.typ compiled without an error. That says only that the markup is valid Typst, not that it says what note.tex said.
  2. Count what both should have. grep counted 2 sections, 1 equation and 1 table in note.tex; typst eval with query() counted 2 numbered headings, 1 display equation and 1 table figure. Equal counts rule out a lost section or table.
  3. Compare the words a reader sees. The same three sentences of both PDFs showed what the counts missed: and Table Table 1, Equation [eq:mean] for Equation (1), and Section Section 1. Block A appeared 3 times in the LaTeX text and 2 times in the Typst text.
  4. Fix the source, not the PDF. body-fixed.typ removes Table~ and Section~ before two references, because Typst adds those words itself, writes @eq:mean in place of the link, and draws the Block A box again with rect.
  5. Build and compare again. The second build gave and Table 1, Equation 1 and Section 1, and Block A 3 times in both texts. Only intended differences remain, such as the style of the bibliography.
  6. What is left is expected. LaTeX printed (1) for the equation where Typst printed 1, and the maths letters were extracted as r and 𝑟. Each remaining difference has a reason you can name, which is the test of a finished conversion.

What remains is expected and nameable: LaTeX’s \eqref printed (1) where Typst’s reference printed 1, the maths letters were extracted as r and 𝑟, which Unicode’s NFKC: A Unicode normalisation form that replaces compatibility variants, such as mathematical italic letters, superscript digits and ligatures, with their plain characters, so that text compares and searches as people type it. More in “Inline and display maths” form turns into the same letter, and the two bibliographies follow different styles.

Key idea

A conversion is finished when its counts match and every difference left in the text has a reason you can name: compiling only proves that the new file is valid.

Checkpoint

Check: Checking a conversion

  1. Question 1 of 2 What did the counts of sections, display equations and tables prove about the corrected note?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: That no section, equation or table was lost, but not that the sentences read the same

    Counts catch lost parts; a comparison of the words catches parts that came through wrong. A check needs both.

  2. Question 2 of 2 After the fixes, how many times did Block A appear in the text of the Typst PDF?

    Type a number.

    Show the answer: Question 2 of 2

    Answer: 3 times

    Twice in the list and the table, and once in the box that rect drew again; the LaTeX text also had 3, so the drawing was back.

Practise: list what a conversion lost

The sentence checks above compare by eye. A short function does it for every word of two extracted texts, and with normalising on it ignores the maths letters that differ only in their code points. The sample tests are made from this lesson’s note, and the first hint is open:

Exercise · Medium · Python

List the words a conversion lost or added

After a conversion, the text of the new PDF should hold the same words as the old one. Write word_changes(before, after, normalise=False) in wordcheck.py. before and after are texts that pdftotext extracted from the two PDFs. It returns a pair of lists, (missing, extra):

  • the words are the pieces of each text between runs of whitespace, punctuation included, as in (1) or totals.;
  • missing holds the words of before that after lacks, and extra the words of after that before lacks, counting repeats: three Block before and two after leave one Block missing;
  • both lists are sorted;
  • with normalise=True, every word is first put in Unicode's NFKC form, which turns mathematical italic letters such as 𝑟, the letters Typst's PDFs hold for maths, into the plain r that pdfLaTeX's PDFs hold.

Two texts with the same words in any order give ([], []).

Starter code · wordcheck.py

def word_changes(before, after, normalise=False):
    """Return (missing, extra): the sorted words that `after` lacks and the sorted words it has in addition."""
    # Replace this line: count the words of each text, then subtract the counts both ways.
    return [], []
The sample tests · test_wordcheck.py
from wordcheck import word_changes


def test_doubled_word():
    """finds the word the conversion doubled"""
    assert word_changes("and Table 1 lists the totals.", "and Table Table 1 lists the totals.") == ([], ["Table"])


def test_reference_as_text():
    """finds an equation number that became a label's name"""
    before = "Equation (1) gives 5.93 mm a day."
    after = "Equation [eq:mean] gives 5.93 mm a day."
    assert word_changes(before, after) == (["(1)"], ["[eq:mean]"])


def test_repeats_counted():
    """counts repeated words, so a drawing's lost label shows"""
    before = "Block A faces east.\nBlock A 83.0\nBlock A"
    after = "Block A faces east.\nBlock A 83.0"
    assert word_changes(before, after) == (["A", "Block"], [])


def test_order_and_spaces():
    """ignores the order of words and the kind and amount of whitespace"""
    assert word_changes("mean of roof r", "roof   r\nmean of") == ([], [])


def test_maths_letters():
    """treats a mathematical italic letter as a different word unless asked to normalise"""
    before = "The daily mean of roof r is"
    after = "The daily mean of roof \U0001d45f is"
    assert word_changes(before, after) == (["r"], ["\U0001d45f"])
    assert word_changes(before, after, normalise=True) == ([], [])


def test_sorted_lists():
    """returns both lists sorted"""
    assert word_changes("b a c", "d c e") == (["a", "b"], ["d", "e"])


def test_empty_texts():
    """gives two empty lists for two empty texts"""
    assert word_changes("", "") == ([], [])
A hint

text.split() gives the words, and collections.Counter counts them. One Counter minus another keeps only the positive differences, so before_counts - after_counts is what is missing. unicodedata.normalize("NFKC", word) does the normalising.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

The self-check below covers the six ideas, starting with the one you have answered least well, and explains every choice as soon as you make it:

Practice that adapts to you

Practise this lesson

16 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 16 What does pandoc note.tex -t native print?

    Choose one answer.

    Show the answer: Question 1 of 16

    Answer: The document as pandoc's tree, such as Header 1 ( "sec:method" , [] , [] ) [ Str "Method" ]

    Looking at the tree tells you what any conversion of the file can contain.

  2. Question 2 of 16 A colleague says pandoc converts LaTeX to Typst perfectly. What does pandoc's manual say?

    Choose one answer.

    Show the answer: Question 2 of 16

    Answer: Its tree is less expressive than many formats, so one should not expect perfect conversions

    Plan every conversion as a draft to check, never as a finished file.

  3. Question 3 of 16 Which pandoc option listed the commands it skipped in note.tex?

    Choose one answer.

    Show the answer: Question 3 of 16

    Answer: --verbose

    The skipped list is the first fix list of a conversion, but it misses faults that compile, such as doubled words.

  4. Question 4 of 16 Equation~\eqref{eq:mean} became Equation~#link(<eq:mean>)[\[eq:mean\]]. What is the fix?
    Show the answer: Question 4 of 16

    Answer: @eq:mean, with numbering set for equations, so Typst prints Equation 1

    Turn every converted \ref and \eqref into a Typst reference, and delete the word written before it.

  5. Question 5 of 16 You will convert a chapter again next month after co-authors edit the LaTeX. How do you keep your Typst layout?

    Choose one answer.

    Show the answer: Question 5 of 16

    Answer: Convert only the body and keep numbering, fonts and captions in a main.typ that includes it

    Separating the converted text from the hand-written frame is what makes a conversion repeatable.

  6. Question 6 of 16 pandoc wrote \lVert v \rVert as lr(bar.v.double v bar.v.double). What shorter Typst code means the same?

    Choose one answer.

    Show the answer: Question 6 of 16

    Answer: norm(v)

    A converted formula is correct but not always idiomatic; tidy it where people will edit it.

  7. Question 7 of 16 A maths-heavy LaTeX file must move to Typst before its formulas can be rewritten. What does MiTeX offer?

    Choose one answer.

    Show the answer: Question 7 of 16

    Answer: It renders LaTeX maths syntax inside a Typst document, with #mi(...) inline and #mitex(...) for displays

    MiTeX is a bridge for the maths while the rest of the document is already Typst.

  8. Question 8 of 16 Why check every converted formula on the page once, even when all of them compile?

    Choose one answer.

    Show the answer: Question 8 of 16

    Answer: A formula can compile and still group or space differently from the original

    For maths, the page is the test: put the two PDFs side by side for each formula once.

  9. Question 9 of 16 What did docx_parts.py read to list the paragraph styles of note.docx?

    Choose one answer.

    Show the answer: Question 9 of 16

    Answer: The w:pStyle elements in word/document.xml, inside the ZIP package

    Knowing the format lets you check a Word file without Word.

  10. Question 10 of 16 What did pandoc notes.md --citeproc --bibliography=refs.bib --pdf-engine=typst -o notes.pdf make?

    Choose one answer.

    Show the answer: Question 10 of 16

    Answer: A one-page PDF made by Typst 0.15.1, tagged, with the citation formatted

    For notes without numbered references, Markdown through Typst is a short route to an accessible PDF.

  11. Question 11 of 16 You send a co-author a Word file made from note.tex. Which fault from the Typst conversion will they also see?

    Choose one answer.

    Show the answer: Question 11 of 16

    Answer: The reference to the equation printed as [eq:mean]

    A fault made by the reader reaches every output; fix the LaTeX, or check each output.

  12. Question 12 of 16 What must typst compile be given to write HTML?

    Choose one answer.

    Show the answer: Question 12 of 16

    Answer: --features html, and --format html or an output name ending in .html

    The feature flag is the reminder that the export is incomplete; its reference advises against production use.

  13. Question 13 of 16 TeX4ht's note.html had 11 style attributes. Why can that matter?

    Choose one answer.

    Show the answer: Question 13 of 16

    Answer: A site whose security policy forbids inline styles must remove them or move them into classes

    Count what a generated page contains before you put it on a site with strict rules.

  14. Question 14 of 16 make4ht stopped with module 'luaxml-domobject' not found. What does that tell you?

    Choose one answer.

    Show the answer: Question 14 of 16

    Answer: A package make4ht depends on, LuaXML, is missing from the TeX installation

    A tool's missing module is an installation problem, solved with the package manager, not in the document.

  15. Question 15 of 16 Which command counted the display equations of the Typst note?

    Choose one answer.

    Show the answer: Question 15 of 16

    Answer: typst eval 'query(math.equation.where(block: true)).len()' --in main.typ

    Counting in the compiled document, not in the source, counts what the reader gets.

  16. Question 16 of 16 After the fixes, LaTeX printed Equation (1) and Typst Equation 1. Is the conversion still wrong?

    Choose one answer.

    Show the answer: Question 16 of 16

    Answer: Not necessarily; it is a difference of style with a known reason, which you may keep or change on purpose

    The goal is not identical text but differences you understand and accept.

Interview questions

Warm-up (fresher to 2–5 years): What does pandoc keep and lose when it converts a LaTeX file to Typst?

pandoc reads the LaTeX into its own document tree and writes Typst from the tree, so it keeps what the tree can hold: headings with their labels, paragraphs, emphasis, lists, footnotes, tables, maths and citations. It applies custom macros instead of keeping them, so \mean{x} arrived as macron(x). It drops what the tree cannot hold: in this lesson’s note it skipped \maketitle, \centering, a TikZ picture and \bibliographystyle, and said so only with --verbose. It also writes things that compile and read wrongly: Table~\ref{…} became “Table Table 1”, because a Typst reference prints its own word, and \eqref became a link whose text was the label’s name. So a converted file is a draft: compile it, count its headings, equations and tables against the original, and compare the text of both PDFs.

Two harder questions build on this: a thesis chapter that must move to Typst with all its references working, and a lab manual needed as a PDF, a Word file and a web page. Sketch an answer to each, then check it against its first step:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to mid

    You must move one 30-page chapter of a LaTeX thesis, with 40 cross-references, 12 equations, 6 tables and 3 TikZ figures, to Typst this week, and the rest of the thesis follows next term. How do you convert it so that every reference and number still works, and how do you prove it?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A department publishes its lab manual as a PDF for printing, a Word file that teaching assistants edit, and a web page that must be accessible. The manual has equations, tables and cross-references. Choose the source format and the conversions, and say what you check after every change.

    Model answer, Pro. First step and follow-ups

Key takeaways

  • pandoc reads a document into its own tree and writes the tree again, so whatever the tree cannot hold, such as a TikZ picture, is dropped, and custom macros arrive expanded.
  • Converted to Typst, the note compiled but printed “Table Table 1”, “Section Section 1” and “Equation [eq:mean]”, and had lost its drawing; --verbose named only the skipped commands.
  • Maths converts formula by formula into Typst’s own syntax; check each formula on the page once, and use MiTeX while a file must keep LaTeX maths.
  • Word files keep headings, tables and maths as Word’s own styles and equations, citeproc formats citations in Chicago author-date unless given a style, and Markdown reaches a tagged PDF through --pdf-engine=typst.
  • TeX4ht kept the drawing as SVG and wrote inline styles; Typst’s experimental HTML export dropped the drawing and the title block and said so in its warnings.
  • A conversion is checked by counting its parts on both sides and comparing the text of both PDFs until every difference left has a reason.

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. How does pandoc convert LaTeX to Typst?

    A reader parses the input into pandoc's own document tree and a writer writes Typst from the tree, so whatever the tree cannot hold, such as a TikZ picture, is dropped.

  2. What happens to a custom macro such as \mean{x} in a pandoc conversion?

    It is expanded, not kept: the Typst file has macron(x), and its reader never learns that the macro existed.

  3. Why did the converted note print Table Table 1?

    Typst's reference @tab:totals prints the word Table itself, so the word that the LaTeX source typed before \ref doubled.

  4. What did \eqref become in the conversion, and what replaces it?

    A link whose text was the label's name, printed as Equation [eq:mean]; in Typst write @eq:mean.

  5. Why convert only the body and write the Typst frame yourself?

    pandoc's whole-document template left the headings unnumbered and the build stopped on a reference; a main.typ of your own keeps numbering, captions, fonts and the title, and a later conversion changes none of them.

  6. Which pandoc option shows what the reader skipped?

    --verbose, which named \maketitle, \centering, the tikzpicture and \bibliographystyle; the doubled words and the wrong reference compiled without a message.

  7. How does pandoc store maths and citations in a Word file?

    Maths as OMML, Word's own maths markup, in m:oMath equations; --citeproc formats citations in the Chicago author-date style unless it is given another.

  8. How do you prove that a conversion lost nothing?

    Count the parts on both sides, such as sections, equations and tables (with typst eval and query() for Typst), then compare the text of both PDFs until every difference left has a reason.

Terms in this lesson

document tree
pandoc's own representation of a document: blocks such as headings, paragraphs and tables, holding inlines such as words, emphasis, maths and citations. Every reader builds it and every writer works from it.
OMML
Office Math Markup Language, the XML in which Word files store equations, as m:oMath elements, so that they stay editable in a word processor.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.