With Typst 0.13, we wanted to improve the day-to-day experience of using Typst. We fixed some of the most long-standing bugs and made Typst even more flexible to use. And on top, we’re shipping a first, experimental version of HTML export.
by Laurenz Mädje
It’s been almost two years since Typst’s open-source launch and the project has matured quite a bit since then. Typst 0.12’s development cycle saw many large-scale changes to Typst’s foundations. With Typst 0.13, we moved the focus to the day-to-day experience of using Typst. We made quality-of-life improvements all across and fixed some of the biggest paper cuts. But, of course, we also shipped some exciting new features!
Contents
In this blog post, I’ll walk you through the highlights of the release. If you prefer a more visual take on the topic, also check out the release video.
- Paragraphs and first line indent
- Better-looking outlines
- New curves
- Files and bytes
- Generating images
- Faster plugins
- Single-letter strings in math
- Font coverage control
- PDF file embedding
- A first look at HTML export
- Migrating to Typst 0.13
- Community Call
For a comprehensive overview of all changes in the release, visit the changelog. If you’re looking to upgrade your document to Typst 0.13, you can also skip ahead to the Migration section.
Paragraphs and first-line indent
The work on semantic paragraphs is what I’m most proud of in this release, but at the same time it’s among the things that are least visible for users. What do I even mean with “semantic paragraphs?”
Let me explain. Up until now, Typst considered every piece of text you wrote as a paragraph — be it a single word in a page header, a figure caption, or a page number. Just like paragraphs, these things can have spacing, break across lines, etc. Layout-wise they are not all that different from paragraphs.
However, there are semantical differences. Only proper paragraphs should be counted when paragraphs are numbered (such as in legal texts). Only proper paragraphs should be announced by a screen reader as such. And even layout-wise there are differences; for instance, that only proper paragraphs should have first-line indent. While the layout routines for “just text” and a paragraph may be very similar, the second order effects of something being a proper paragraph are far-reaching.
In version 0.13, Typst finally gains a better understanding of this distinction. Whether something is a paragraph or just text is decided based on a few simple rules about which you can read in the updated paragraph documentation.
The most visible immediate effect of this work is that first-line-indent
can now be applied to all paragraphs instead of just consecutive ones, closing the most upvoted Typst bug. Semantic paragraphs are also crucial for the in-development HTML export and for planned future work on PDF accessibility.
#set block(spacing: 1.2em)
#set par(
spacing: 0.65em,
first-line-indent: (
amount: 1em,
all: true,
),
)
= Chapter 1
In this text, the paragraphs are
all indented, without exception.
With `all: true`, the first
paragraph is affected as well.
Better-looking outlines
If you’ve created a table of contents with Typst’s outline functionality before, you might remember that it always looked a bit bland. The default style had no indentation and rather tightly dotted leaders (leaders are the filler dots between a title and its page number).
In Typst 0.13, the outline gets a full facelift while also becoming easier to customize. The new automatic indentation nicely aligns all titles and numberings across the whole outline, long titles have better-looking wrapping behavior, and we fixed a number of bugs.
If you have a customized outline, check out the migration section for the outline to learn how to adapt your customization.
#set heading(numbering: "1.i.")
#outline()
= Introduction
= Methods
== Experiments
== Statistics
= Results
== T Experiment
== K Experiment
== V Experiment
== Additional experiments with extra length
= Discussion
= Conclusion
New Curves
Since Typst 0.2, you could draw Bézier paths with the path
function. However, the input format of this function was rather arcane. Rather than specifying pen movements as in an SVG, you had to specify directly points with their two control points. Moreover, the path function had a fatal flaw: You could not close a path and then keep on drawing. This is necessary to draw a shape with cutouts, as depicated below.
The new curve
function fixes these flaws. It provides an easier-to-understand and more expressive interface. We also used this opportunity to change the name from path
to curve
as we plan to repurpose the name path
for a file path type in an upcoming release.
#curve(
fill: blue.lighten(80%),
fill-rule: "even-odd",
stroke: blue,
curve.line((50pt, 0pt)),
curve.line((50pt, 50pt)),
curve.line((0pt, 50pt)),
curve.close(),
curve.move((10pt, 10pt)),
curve.line((40pt, 10pt)),
curve.line((40pt, 40pt)),
curve.line((10pt, 40pt)),
curve.close(),
)
Thanks to @Emm54321 for working on this!
Files and bytes
Various functions in Typst load files, be it images, data loading functions, or plugins. Sometimes though, a little extra flexibility is needed, for example, to preprocess, generate, or inline data into a Typst document.
For this reason, there are also .decode
variants on various of the functions, e.g. image.decode
or json.decode
. However, that approach didn’t work so well when a path is expected in a set rule, as in set raw(theme: "light.tmTheme")
. It also introduced duplication: All the properties of an image are also spelled out again in image.decode
.
Typst 0.13 revamps file handling to improve this unsatisfactory situation. All places where a path is expected now also support raw bytes instead. Typst will always interpret a string as a path and raw bytes as data. When trying to decode an image from a string, thus make sure to first convert it to bytes. Converting to bytes is cheap as Typst will internally reuse the memory from the string. It will even remember that the bytes came from a string to make conversions back to a string cheap as well!
The existing .decode
functions are now deprecated as they are not needed anymore. The .encode
variants of data loading functions remain unchanged.
See @netwok for details.
#bibliography(bytes(
```bib
@article{netwok,
title={At-scale impact of the {Net Wok}},
author={Astley, Rick and Morris, Linda},
journal={Armenian Journal of Proceedings},
volume={61},
pages={192--219},
year={2020},
publisher={Automattic Inc.}
}
```.text
))
Generating images
With the new byte-taking image
function (and previously image.decode
), you can generate images at runtime. However, the image function expects images in an encoded image exchange format like PNG or JPEG. Producing valid bytes for such a format in pure Typst code is prohibitively complicated. Meanwhile, plugins are unnecessarily bloated and slowed down if they have to include an image encoder.
To streamline image generation workflows, Typst 0.13 thus brings support for loading images from uncompressed raw pixel data. To that end, the format
parameter of the image function supports a new form, where the channel encoding and pixel width/height of the image can be specified. This feature is crucial for better scientific visualizations — think things like heatmaps.
#image(
bytes(range(64).map(x => x * 4)),
format: (
encoding: "luma8",
width: 8,
height: 8,
),
width: 4cm,
scaling: "pixelated",
)
Thanks to @frozolotl for working on this!
Faster plugins
In version 0.8, Typst gained support for WebAssembly plugins — one of the features that would very likely still be a little blue “feature request” label if not for our fabulous open source community. Since then, plugins have become the backbone of various community packages. They’re great because they bring the power and package ecosystem of all the languages that compile to WebAssembly right into Typst.
They are also faster to execute than Typst code. Still, with heavy usage the time spent executing plugin code can make up a significant chunk of compile time. A simple way to improve this would’ve been to switch to a faster WebAssembly runtime (specifically, from wasmi
to wasmtime
). However, taking on a dependency on a WebAssembly runtime with just-in-time compilation wasn’t a spot we wanted to put Typst into. It would have reduced portability and security and increased the amount of third-party code Typst depends on by a lot.
There was another way to speed up plugins: Since 0.12, Typst’s layout engine is multi-threaded. Plugins didn’t profit from this though as they couldn’t be easily replicated across threads. This is a limitation we’re lifting with 0.13. Typst will now automatically run plugins in multiple threads without any changes from plugin authors. This is possible because we require (and also already required in the past) plugin functions to be pure. This means that we can execute plugin functions out of order without a visible effect. For cases where purity is too limiting, Typst 0.13 introduces the new plugin.transition
API, which lets plugin authors deal with stateful operations in a sound way.
The work on speeding up plugins was prioritized through a Typst open-source support contract. If you’re using Typst in production at your company and are hitting any road blocks, please reach out to us!
Single-letter strings in math
Since Typst’s initial release, $ "hi" $
would generate the letters “h” and “i” in upright style while $ "h" $
would result in an italic “h”. It’s one of the longest-standing bugs, which is curious because it seems so easy to fix. Unfortunately, it was not. To see why, we need to take a look behind the scenes and understand how Typst views your equations.
In Typst 0.12 and lower, the x
in $ x $
is a text element like any other text in your document. A string like "hi"
is converted t
12 Comments
vondur
I watched the video presentation going over the new features, and the poor developer looks like he really needs a rest.
29athrowaway
Is this a LaTeX killer yet?
tombert
I need to play with Typst. I've been using Markdown and converting that to LaTeX with Pandoc for quite awhile, and that more or less works, but I've had issues when I need any non-standard formatting, like specific placement of something like a title page.
Typst looks like it might be the solution to this problem.
emaro
Small report from personal experience: I wrote the documentation for a project (~ half a bachelors thesis) with Typst. The writing experience was easy and nice, much better compared to the few Latex documents I worked on. Two main struggles I remember:
– We split the "paper" into multiple Typst files. While this organized our content nice, the VSC extension didn't recognize the bibliography imported in another file and displayed errors. Nothing major but certainly annoying.
– It couldn't deal well with SVGs and diagrams in general, so we resorted to just export graphics and include them as images.
6/10 would use again and I'm excited for the new release.
aiono
I am very excited about HTML export! HTML is much better at responsiveness and accessibility.
Typst is such a great software. With it's modern programming language like syntax I learned it much faster than Latex. It's compile duration is also much better in my experience. I am honestly more productive using Typst it this point. Though I am not a power user. I only used it for slides and notation heavy articles.
isaacvando
Looks wonderful!
divan
Nice! Excited about HTML export. I used LaTeX for autogenerating some semi-legal documents in both PDF and HTML, so all editing happens on Github and Github Actions do the rest for publishing PDFs and updating site. Started using Typst for some of these, but HTML export was a missing piece to completely switch to it.
replete
I've been following the HTML export thread, good to see some progress.
I've experimented with 'transpiling' to RST with Pandoc for purposes of digital documentation – but it's not quite there. Would love to see a flavour of Typst that could be viable for digital documentation with a decent live preview experience in VSCode.
I know this isn't the purpose of Typst, but one can hope. Would also welcome advice on this subject of decent authorship digital documentation – some of these frameworks are quite frankly massive, unweildy and painful to deal with.
zellyn
After reading Laurenz's blog post on TeX vs Typst layout [1], it made me wonder: how hard would it be at this point for them to make Typst directly understand TeX, and let you insert chunks of TeX. It would make for a really nice upgrade path. Of course, being bug-for-bug compatible once people layer on tons of TeX packages seems like a losing game. But if most straightforward TeX stuff "just worked", it would be an easy way to upgrade one paragraph at a time…
[1] https://laurmaedje.github.io/posts/layout-models/
elvircrn
I just love how responsive the editor is.
The biggest downside is that now I dread switching to overleaf after typst!
merb
The only downside of typst is that there is no libtypst, which would make it easy to embed.
anovick
Waiting for text-wrapping around images to be supported. https://github.com/typst/typst/issues/5181