<< Return to blog posts

Typst in a few words
2024-09-04
Simple explanations for very lazy people

Typst is a typesetting language. It transforms code into documents (generally PDF). It is an alternative to LaTeX but unlike LaTeX,

It can be used online on https://typst.app/ or locally by simply downloding a typst executable on Github.

Typst distinguishes three different contexts:

What you write is evaluated differently depending on the context you are in. In this article, I present the different contexts and how to switch from one context to another.

The documentation is here: https://typst.app/docs/

Content

In the content context, you can write in a markup language. This is the default context.

= Some title

== Some subtitle

=== Some sub-subtitle

// single-line comment
/* multi-line comment */
Some text. Some _italic_ text and some *bold* text.
Some `raw text`.

Paragraphs are separated by empty lines but you can
also manually break line as follows \ // Break line

- some item 1
  + some sub-item 1
  + some sub-item 2
- some item 2
- some item 3

Functions

Functions are expressions producing a result from some given arguments.

Calls

In the documentation, you can find expressions describing how predefined functions can be called:

// The function 'image' displays a picture on the document
/* Arguments of the function are listed with :
   - their name (optional)
   - a list of types they can have
*/
image(
    str, // unamed (positional) argument specified in order
    format: auto str, // 'auto' supports a contextual behaviour
    width: auto relative,
    height: auto relative,
    alt: none str,
    fit: str,
) -> content // type of the function's result

You can call functions and enter in a functional context by prefixing function identifiers with a # symbol. Let’s call the image function to display a picture some_image.jpg of your project:

// Only the path is required, other have default values.
#image("some_image.jpg")

// The order only matters for 'positional' arguments.
#image(width: 30%, "some_image.jpg")
#image("some_image.jpg", width: 30%)

// Width depends on the context (it is the default value)
#image(width: auto, "some_image.jpg")

Arguments are then interpreted in a functional context (in which # is not required anymore for internal function calls):

/* Displays the French flag with a grid of 3 columns
   containing coloured rectangles */
#grid(
    columns: (30pt, 30pt, 30pt),
    // No need for '#' once you entered the functional context
    // The number of arguments 
    rect(width: 100%, fill: blue),
    rect(width: 100%, fill: white),
    rect(width: 100%, fill: red),
)

More generally, you can open a whole block in a functional context:

#{
    image("some_image.jpg")
    image(width: 30%, "some_image.jpg")
    image("some_image.jpg", width: 30%)
    image(width: auto, "some_image.jpg")
    grid(
        columns: (30pt, 30pt, 30pt),
        rect(width: 100%, fill: blue),
        rect(width: 100%, fill: white),
        rect(width: 100%, fill: red),
    )
}

You can open back a content context by writing content between [ and ]:

#align(center, [Here is some content])

#align(center, [
    Here is a red rectangle #rect(width: 30%, fill: red)
])

// When the last argument is a content, you can write:
#align(center)[Here is some content]
#strike[Some strikethrough text]
Content should not be mistaken with string literals. In a content block, typesetting symbols such as *, _ or # have an effect, whereas every character is interpreted literally for string literals, as in "#function *bold* _italic_".

Tables are created with the table function:

#table(
    // 1fr are 'fraction' values
    // here each column takes 1/3 of space
    columns: (1fr, 1fr, 1fr),
    align: horizon,
    /* the number of arguments has to match
       the organization of the table */
    table.header(
      [*Header 1*], [*Header 2*], [*Header 3*],
    ),
    [Line 1 Item 1], [Line 1 Item 2], [Line 1 Item 3],
    [Line 2 Item 1], [Line 2 Item 2], [Line 2 Item 3],
    [Line 3 Item 1], [Line 3 Item 2], [Line 3 Item 3],
  )

Figure are used this way and you should find it very natural at this point:

#figure(
  image("some_picture.jpg", width: 80%),
  caption: [Some caption],
) <figure-identifier>

Look at @figure-identifier for more information

Definitions

You can define your own functions and constants:

// Function definition
#let call_someone(name) = [Hello #name!]

// Function call
#call_someone(name: "Boris") // Could also be [Boris]

// With default argument
#let call_someone(name: "Nobody") = [Hello #name!]

// Without argument (a constant)
#let content = [Some content]
#content

// anonymous function with call
#{it => [Hello #it!]}("Boris")

// anonymous function associated with a label and call
#let call_someone = it => [Hello #it!]
#call_someone("Boris")

Rules

Rules can be used to customise the behaviour of functions. They use the syntax and context of functions.

Set rule

Change the default default arguments of functions for every calls below:

#set image(width: 50%)
#set rect(fill: blue)
#set strike(stroke: red)
#set text(font: "New Computer Modern")
#set heading(numbering: "I.") // prefix titles by roman numerals

Show rule

Define how content is displayed:

// each occurrence of "hello" is displayed as "bye"
#show "hello": "bye"

// calls to 'strike' function displays 'hello'
#show strike: [hello]

// redefine the 'strike' function
#show strike: it => [*#it*]

// you can use specific named arguments instead, as follows
#show strike: it => [
    strikethrough of #it.body
    with offset #it.offset
]

// puts >> before titles
#show heading: it => [>> it.body]

// "show-set rule" displaying titles in red
#show heading: set text(red)

Math

The math context is opened between $ symbols. It is a variant of functional context in which:

/* Letters */
$x = y + z$ // interpreted as variables
$Gamma = alpha + beta + gamma$ // displayed as greek letters
$cal(C), bb(N), frak(A), sans(A), mono(A)$ // mathematical fonts
$bold(A), italic(A)$ // font styles
$NN$ // same as bb(N)

/* Mathematical operators */
$tan x = (sin x) / (cos x)$
$(n_k times 10 + 5)^n != 0$
$frac(1, sqrt(2)) + 1 <= 0$
$e in A sect (B union C) "or" e in.not C$
$not(C subset E and B (subset.eq.not) E)$
$[| a => b => c |] equiv [| (a and b) => c |]$

/* Putting math context in content context */
#align(center)[$k times frac(a, b) = frac(k times a, b)$]

/* Arrows */
$-> => ~> <- <= <~$
$--> ==> ~~>$
$<-> <=> <~>$
$arrow.l arrow.r arrow.b arrow.t$ // left, right, bottom, top
$arrow.l.r$ // same as <->
$arrow.l.r.double$ // same as <=>
$arrow.long$ // same as -->

// vectors and matrices
$vec(1, 2, delim: "[")$
$mat(1, 2; 3, 4)$

You can find a list of symbols on Typst documentation.

It is also possible to use emojis and any symbols outside of a math context:

This is a greek letter: #sym.alpha

Other features

<< Return to blog posts