Typst Documentation (Version: 0.15.0) Typst Documentation Version: 0.15.0 Copyright ©︎ 2019 – 2026 Laurenz Mädje, Martin Haug, and The Typst Project Developers. The contents of this document and the Typst compiler are licensed under the terms of the Apache License, Version 2.0. This documentation is open source and open for contribution on https://github.com/typst/typst. It has been typeset using Typst 0.15.0, HK Grotesk, and Cascadia Mono. Published by Typst GmbH, Heidestraße 34, 10557 Berlin, Germany. https://typst.app/ https://github.com/typst/typst https://typst.app/ 1 Overview Welcome to Typst's documentation! Typst is a markup-based typesetting system that combines powerful automation and high-quality typography with speed and ease of use. This makes it suitable for documents of any complexity. Typst is a great alternative to both word processors and LaTeX. This documentation is split into multiple parts, serving different needs: – If you are new to Typst, we highly recommend starting with our beginner-friendly tutorial2. Throughout the tutorial, we will introduce you to Typst through a practical example. – To answer targeted questions about Typst and familiarize yourself with advanced features, use the reference3. It describes the fundamental features of the Typst language and contains sections for all the functions, types, and more that come with Typst. – For tailored, in-depth how-tos on specific features, use cases, and audiences, check out our guides4. They provide copyable snippets throughout and allow you to build confidence with a specific feature area. If you are coming from LaTeX, the Guide for LaTeX Users4.1 provides an alternative introduction to Typst, building on concepts you already know. The term Typst refers to three concepts: The Typst language, the Typst compiler, and the Typst web app. The language is what you write, the compiler translates files in the Typst language into PDFs, HTML pages, and other formats, and the Typst web app lets you work collaboratively on Typst projects in your browser. The Typst language and the compiler are open-source. This documentation primarily documents the Typst language, although the tutorial and various pages will refer to the web app and the command line Typst compiler. In the copy of the docs hosted on https://typst. app/docs/[A], we also include documentation about the web app. To learn how to install the Typst compiler CLI, visit the Open Source page[B] on our website. There, you can also learn more about the relationship between the Typst compiler and the web app. Once you have installed the Typst compiler CLI, run typst help for more information on how to use it. Our GitHub repository[C] provides additional developer-facing documentation about how to contribute to Typst and how to integrate it into your applications. The documentation also contains a changelog5, in which you can track the evolution of Typst and what changes to the markup language mean for your projects. This documentation applies to Typst 0.15.0. [A]https://typst.app/docs/ [B]https://typst.app/open-source [C]https://github.com/typst/typst 9 https://typst.app/docs/ https://typst.app/docs/ https://typst.app/open-source https://github.com/typst/typst https://typst.app/docs/ https://typst.app/open-source https://github.com/typst/typst 2 Tutorial Welcome to Typst's tutorial! In this tutorial, you will learn how to write and format documents in Typst. We will start with everyday tasks and gradually introduce more advanced features. This tutorial does not assume prior knowledge of Typst, other markup languages, or programming. We do assume that you know how to edit a text file. The best way to start is to sign up to the Typst app for free and follow along with the steps below. The app gives you instant preview, syntax highlighting and helpful autocompletions. Alternatively, you can follow along in your local text editor with the open-source CLI[A]. 2.0.1 When to use Typst Before we get started, let's check what Typst is and when to use it. Typst is a markup language for typesetting documents. It is designed to be easy to learn, fast, and versatile. Typst takes text files with markup in them and outputs PDFs. Typst is a good choice for writing any long form text such as essays, articles, scientific papers, books, reports, and homework assignments. Moreover, Typst is a great fit for any documents containing mathe matical notation, such as papers in the math, physics, and engineering fields. Finally, due to its strong styling and automation features, it is an excellent choice for any set of documents that share a common style, such as a book series. 2.0.2 What you will learn This tutorial has four chapters. Each chapter builds on the previous one. Here is what you will learn in each of them: 1. Writing in Typst:2.1 Learn how to write text and insert images, equations, and other elements. 2. Formatting:2.2 Learn how to adjust the formatting of your document, including font size, heading styles, and more. 3. Advanced Styling:2.3 Create a complex page layout for a scientific paper with typographic features such as an author list and run-in headings. 4. Making a Template:2.4 Build a reusable template from the paper you created in the previous chapter. We hope you'll enjoy Typst! [A]https://github.com/typst/typst 10 https://github.com/typst/typst https://github.com/typst/typst 2.1 Writing in Typst Let's get started! Suppose you got assigned to write a technical report for university. It will contain prose, maths, headings, and figures. To get started, you create a new project on the Typst app. You'll be taken to the editor where you see two panels: A source panel where you compose your document and a preview panel where you see the rendered document. You already have a good angle for your report in mind. So let's start by writing the introduction. Enter some text in the editor panel. You'll notice that the text immediately appears on the previewed page. In this report, we will explore the various factors that influence fluid dynamics in glaciers and how they contribute to the formation and behaviour of these natural structures. In this report, we will explore the various factors that influence fluid dynamics in glaciers and how they contribute to the formation and behaviour of these natural structures. Throughout this tutorial, we'll show code examples like this one. Just like in the app, the first panel contains markup and the second panel shows a preview. We shrunk the page to fit the examples so you can see what's going on. The next step is to add a heading and emphasize some text. Typst uses simple markup for the most common formatting tasks. To add a heading, enter the = character and to emphasize some text with italics, enclose it in _underscores_. = Introduction In this report, we will explore the various factors that influence _fluid dynamics_ in glaciers and how they contribute to the formation and behaviour of these natural structures. Introduction In this report, we will explore the various factors that influence fluid dynamics in glaciers and how they contribute to the formation and behaviour of these natural structures. 11 2.1 Writing in Typst That was easy! To add a new paragraph, just add a blank line in between two lines of text. If that paragraph needs a subheading, produce it by typing == instead of =. The number of = characters determines the nesting level of the heading. Now we want to list a few of the circumstances that influence glacier dynamics. To do that, we use a numbered list. For each item of the list, we type a + character at the beginning of the line. Typst will automatically number the items. + The climate + The topography + The geology 1. The climate 2. The topography 3. The geology If we wanted to add a bulleted list, we would use the - character instead of the + character. We can also nest lists: For example, we can add a sub-list to the first item of the list above by indenting it. + The climate - Temperature - Precipitation + The topography + The geology 1. The climate • Temperature • Precipitation 2. The topography 3. The geology 2.1.1 Adding a figure You think that your report would benefit from a figure. Let's add one. Typst supports images in the formats PNG, JPEG, GIF, SVG, PDF, and WebP. To add an image file to your project, first open the file panel by clicking the box icon in the left sidebar. Here, you can see a list of all files in your project. Currently, there is only one: The main Typst file you are writing in. To upload another file, click the button with the arrow in the top- right corner. This opens the upload dialog, in which you can pick files to upload from your computer. Select an image file for your report. We have seen before that specific symbols (called markup) have specific meaning in Typst. We can use =, -, +, and _ to create headings, lists and emphasized text, respectively. However, having a special symbol for everything we want to insert into our document would soon become cryptic and unwieldy. For this reason, 12 2.1 Writing in Typst Typst reserves markup symbols only for the most common things. Everything else is inserted with functions. For our image to show up on the page, we use Typst's image3.11.7 function. #image("glacier.jpg") In general, a function produces some output for a set of arguments. When you call a function within markup, you provide the arguments and Typst inserts the result (the function's return value) into the document. In our case, the image function takes one argument: The path to the image file. To call a function in markup, we first need to type the # character, immediately followed by the name of the function. Then, we enclose the arguments in parentheses. Typst recognizes many different data types within argument lists. Our file path is a short string of text3.5.27, so we need to enclose it in double quotes. The inserted image uses the whole width of the page. To change that, pass the width argument to the image function. This is a named argument and therefore specified as a name: value pair. If there are multiple arguments, they are separated by commas, so we first need to put a comma behind the path. #image("glacier.jpg", width: 70%) The width argument is a relative length3.10.21. In our case, we specified a percentage, determining that the image shall take up 70% of the page's width. We also could have specified an absolute value like 1cm or 0.7in. Just like text, the image is now aligned at the left side of the page by default. It's also lacking a caption. Let's fix that by using the figure3.6.8 function. This function takes the figure's contents as a positional argument and an optional caption as a named argument. Within the argument list of the figure function, Typst is already in code mode. This means, you now have to remove the hash before the image function call. The hash is only needed directly in markup (to disambiguate text from function calls). The caption consists of arbitrary markup. To give markup to a function, we enclose it in square brackets. This construct is called a content block. 13 2.1 Writing in Typst #figure( image("glacier.jpg", width: 70%), caption: [ _Glaciers_ form an important part of the earth's climate system. ], ) Figure 1: Glaciers form an important part of the earth's climate system. You continue to write your report and now want to reference the figure. To do that, first attach a label to figure. A label uniquely identifies an element in your document. Add one after the figure by enclosing some name in angle brackets. You can then reference the figure in your text by writing an @ symbol followed by that name. Headings and equations can also be labelled to make them referenceable. Glaciers as the one shown in @glaciers will cease to exist if we don't take action soon! #figure( image("glacier.jpg", width: 70%), caption: [ _Glaciers_ form an important part of the earth's climate system. ], ) Glaciers as the one shown in Figure 1 will cease to exist if we don't take action soon! Figure 1: Glaciers form an important part of the earth's climate system. INFO So far, we've passed content blocks (markup in square brackets) and strings (text in double quotes) to our functions. Both seem to contain text. What's the difference? A content block can contain text, but also any other kind of markup, function calls, and more, whereas a string is really just a sequence of characters and nothing else. For example, the image function expects a path to an image file. It would not make sense to pass, e.g., a paragraph of text or another image as the image's path parameter. That's why only strings are allowed here. In contrast, strings work wherever content is expected because text is a valid kind of content. 2.1.2 Adding a bibliography As you write up your report, you need to back up some of your claims. You can add a bibliography to your document with the bibliography3.6.2 function. This function expects a path to a bibliography file. Typst's native bibliography format is Hayagriva[A], but for compatibility you can also use BibLaTeX files. As your classmate has already done a literature survey and sent you a .bib file, you'll use that one. Upload the file through the file panel to access it in Typst. Once the document contains a bibliography, you can start citing from it. Citations use the same syntax as references to a label. As soon as you cite a source for the first time, it will appear in the bibliography section of your document. Typst supports different citation and bibliography styles. Consult the reference3.6.2/4.4 for more details. [A]https://github.com/typst/hayagriva/blob/main/docs/file-format.md 14 https://github.com/typst/hayagriva/blob/main/docs/file-format.md https://github.com/typst/hayagriva/blob/main/docs/file-format.md 2.1 Writing in Typst = Methods We follow the glacier melting models established in @glacier-melt. #bibliography("works.bib") Methods We follow the glacier melting models established in [1]. Bibliography [1] R. Hock, "Glacier melt: a review of processes and their modelling," Progress in Physical Geography: Earth and Environment, vol. 29, no. 3, pp. 362–391, 2005, doi: 10.1191/0309133305pp453ra. 2.1.3 Maths After fleshing out the methods section, you move on to the meat of the document: Your equations. Typst has built-in mathematical typesetting and uses its own math notation. Let's start with a simple equation. We wrap it in $ signs to let Typst know it should expect a mathematical expression: The equation $Q = rho A v + C$ defines the glacial flow rate. The equation 𝑄 = 𝜌𝐴𝑣 + 𝐶 defines the glacial flow rate. The equation is typeset inline, on the same line as the surrounding text. If you want to have it on its own line instead, you should insert a single space at its start and end: The flow rate of a glacier is defined by the following equation: $ Q = rho A v + C $ The flow rate of a glacier is defined by the following equation: 𝑄 = 𝜌𝐴𝑣 + 𝐶 We can see that Typst displayed the single letters Q, A, v, and C as-is, while it translated rho into a Greek letter. Math mode will always show single letters verbatim. Multiple letters, however, are interpreted as symbols, variables, or function names. To imply a multiplication between single letters, put spaces between them. If you want to have a variable that consists of multiple letters, you can enclose it in quotes: The flow rate of a glacier is given by the following equation: $ Q = rho A v + "time offset" $ The flow rate of a glacier is given by the following equation: 𝑄 = 𝜌𝐴𝑣 + time offset You'll also need a sum formula in your paper. We can use the sum symbol and then specify the range of the summation in sub- and superscripts: Total displaced soil by glacial flow: $ 7.32 beta + sum_(i=0)^nabla Q_i / 2 $ Total displaced soil by glacial flow: 7.32𝛽 + ∑ ∇ 𝑖=0 𝑄𝑖 2 15 2.1 Writing in Typst To add a subscript to a symbol or variable, type a _ character and then the subscript. Similarly, use the ^ character for a superscript. If your sub- or superscript consists of multiple things, you must enclose them in round parentheses. The above example also showed us how to insert fractions: Simply put a / character between the numerator and the denominator and Typst will automatically turn it into a fraction. Parentheses are smartly resolved, so you can enter your expression as you would into a calculator and Typst will replace parenthesized sub- expressions with the appropriate notation. Total displaced soil by glacial flow: $ 7.32 beta + sum_(i=0)^nabla (Q_i (a_i - epsilon)) / 2 $ Total displaced soil by glacial flow: 7.32𝛽 + ∑ ∇ 𝑖=0 𝑄𝑖(𝑎𝑖 − 𝜀) 2 Not all math constructs have special syntax. Instead, we use functions, just like the image function we have seen before. For example, to insert a column vector, we can use the vec3.8.27 function. Within math mode, function calls don't need to start with the # character. $ v := vec(x_1, x_2, x_3) $ 𝑣 ≔ ( 𝑥1 𝑥2 𝑥3) Some functions are only available within math mode. For example, the cal3.8.26/1.6 function is used to typeset calligraphic letters commonly used for sets. The math section of the reference3.8 provides a complete list of all functions that math mode makes available. One more thing: Many symbols, such as the arrow, have a lot of variants. You can select among these variants by appending a dot and a modifier name to a symbol's name: $ a arrow.squiggly b $ 𝑎 ⇝ 𝑏 This notation is also available in markup mode, but the symbol name must be preceded with #sym. there. See the symbols section3.9.2 for a list of all available symbols. 2.1.4 Review You have now seen how to write a basic document in Typst. You learned how to emphasize text, write lists, insert images, align content, and typeset mathematical expressions. You also learned about Typst's functions. There are many more kinds of content that Typst lets you insert into your document, such as tables3.6.20, shapes3.11, and code blocks3.7.6. You can peruse the reference3 to learn more about these and other features. For the moment, you have completed writing your report. You have already saved a PDF by clicking on the download button in the top right corner. However, you think the report could look a bit less plain. In the next section, we'll learn how to customize the look of our document. 16 2.2 Formatting So far, you have written a report with some text, a few equations and images. However, it still looks very plain. Your teaching assistant does not yet know that you are using a new typesetting system, and you want your report to fit in with the other student's submissions. In this chapter, we will see how to format your report using Typst's styling system. 2.2.1 Set rules As we have seen in the previous chapter, Typst has functions that insert content (e.g. the image3.11.7 function) and others that manipulate content that they received as arguments (e.g. the align3.10.1 function). The first impulse you might have when you want, for example, to change the font, could be to look for a function that does that and wrap the complete document in it. #text(font: "New Computer Modern")[ = Background In the case of glaciers, fluid dynamics principles can be used to understand how the movement and behaviour of the ice is influenced by factors such as temperature, pressure, and the presence of other fluids (such as water). ] Background In the case of glaciers, fluid dynamics principles can be used to understand how the movement and behaviour of the ice is influenced by factors such as temperature, pressure, and the presence of other fluids (such as water). Wait, shouldn't all arguments of a function be specified within parentheses? Why is there a second set of square brackets with content after the parentheses? The answer is that, as passing content to a function is such a common thing to do in Typst, there is special syntax for it: Instead of putting the content inside of the argument list, you can write it in square brackets directly after the normal arguments, saving on punctuation. As seen above, that works. With the text3.7.12 function, we can adjust the font for all text within it. However, wrapping the document in countless functions and applying styles selectively and in-situ can quickly become cumbersome. Fortunately, Typst has a more elegant solution. With set rules, you can apply style properties to all occur rences of some kind of content. You write a set rule by entering the set keyword, followed by the name of the function whose properties you want to set, and a list of arguments in parentheses. #set text( font: "New Computer Modern" ) = Background In the case of glaciers, fluid dynamics principles can be used to understand how the movement and behaviour of the ice is influenced by factors such as temperature, pressure, and the presence of other fluids (such as water). Background In the case of glaciers, fluid dynamics principles can be used to understand how the movement and behaviour of the ice is influenced by factors such as temperature, pressure, and the presence of other fluids (such as water). INFO Want to know in more technical terms what is happening here? Set rules can be conceptualized as setting default values for some of the parameters of a function for all future uses of that function. 17 2.2 Formatting 2.2.2 The autocomplete panel If you followed along and tried a few things in the app, you might have noticed that always after you enter a # character, a panel pops up to show you the available functions, and, within an argument list, the available parameters. That's the autocomplete panel. It can be very useful while you are writing your document: You can apply its suggestions by hitting the Return key or navigate to the desired completion with the arrow keys. The panel can be dismissed by hitting the Escape key and opened again by typing # or hitting Ctrl + Space . Use the autocomplete panel to discover the right arguments for functions. Most suggestions come with a small description of what they do. 2.2.3 Set up the page Back to set rules: When writing a rule, you choose the function depending on what type of element you want to style. Here is a list of some functions that are commonly used in set rules: – text3.7.12 to set font family, size, color, and other properties of text – page3.10.17 to set the page size, margins, headers, enable columns, and footers – par3.6.15 to justify paragraphs, set line spacing, and more – heading3.6.10 to set the appearance of headings and enable numbering – document3.6.6 to set the metadata contained in the PDF output, such as title and author Not all function parameters can be set. In general, only parameters that tell a function how to do something can be set, not those that tell it what to do it with. The function reference pages indicate which parameters are settable. Let's add a few more styles to our document. We want larger margins and a serif font. For the purposes of the example, we'll also set another page size. 18 2.2 Formatting #set page( paper: "a6", margin: (x: 1.8cm, y: 1.5cm), ) #set text( font: "New Computer Modern", size: 10pt ) #set par( justify: true, leading: 0.52em, ) = Introduction In this report, we will explore the various factors that influence fluid dynamics in glaciers and how they contribute to the formation and behaviour of these natural structures. ... #align(center + bottom)[ #image("glacier.jpg", width: 70%) *Glaciers form an important part of the earth's climate system.* ] Introduction In this report, we will explore the various factors that influence fluid dynamics in glaci­ ers and how they contribute to the formation and behaviour of these natural structures. Glacier displacement is influenced by a num­ ber of factors, including 1. The climate 2. The topography 3. The geology This report will present a physical model of glacier displacement and dynamics, and will explore the influence of these factors on the movement of large bodies of ice. Glaciers form an important part of the earth's climate system. There are a few things of note here. First is the page3.10.17 set rule. It receives two arguments: the page size and margins for the page. The page size is a string. Typst accepts many standard page sizes,3.10.17/4.1 but you can also specify a custom page size. The margins are specified as a dictionary.3.5.11 Dictionaries are a collection of key-value pairs. In this case, the keys are x and y, and the values are the horizontal and vertical margins, respectively. We could also have specified separate margins for each side by passing a dictionary with the keys left, right, top, and bottom. Next is the set text3.7.12 set rule. Here, we set the font size to 10pt and font family to "New Computer Modern". The Typst app comes with many fonts that you can try for your document. When you are in the text function's argument list, you can discover the available fonts in the autocomplete panel. We have also set the spacing between lines (a.k.a. leading): It is specified as a length3.10.13 value, and we used the em unit to specify the leading relative to the size of the font: 1em is equivalent to the current font size (which defaults to 11pt). Finally, we have bottom aligned our image by adding a vertical alignment to our center alignment. Vertical and horizontal alignments can be combined with the + operator to yield a 2D alignment. 2.2.4 A hint of sophistication To structure our document more clearly, we now want to number our headings. We can do this by setting the numbering parameter of the heading3.6.10 function. 19 2.2 Formatting #set heading(numbering: "1.") = Introduction #lorem(10) == Background #lorem(12) == Methods #lorem(15) 1. Introduction Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do. 1.1. Background Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. 1.2. Methods Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore. We specified the string "1." as the numbering parameter. This tells Typst to number the headings with arabic numerals and to put a dot between the number of each level. We can also use letters, roman numerals, and symbols3.6.13 for our headings: #set heading(numbering: "1.a") = Introduction #lorem(10) == Background #lorem(12) == Methods #lorem(15) 1 Introduction Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do. 1.a Background Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor. 1.b Methods Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore. This example also uses the lorem3.7.3 function to generate some placeholder text. This function takes a number as an argument and generates that many words of Lorem Ipsum text. INFO Did you wonder why the headings and text set rules apply to all text and headings, even if they are not produced with the respective functions? Typst internally calls the heading function every time you write = Conclusion. In fact, the function call #heading[Conclusion] is equivalent to the heading markup above. Other markup elements work similarly, they are only syntax sugar for the corresponding function calls. 2.2.5 Show rules You are already pretty happy with how this turned out. But one last thing needs to be fixed: The report you are writing is intended for a larger project and that project's name should always be accompanied by a logo, even in prose. You consider your options. You could add an #image("logo.svg") call before every instance of the logo using search and replace. That sounds very tedious. Instead, you could maybe define a custom function3.5.15/4 that always yields the logo with its image. However, there is an even easier way: With show rules, you can redefine how Typst displays certain elements. You specify which elements Typst should show differently and how they should look. Show rules can be applied to instances of text, many functions, and even the whole document. 20 2.2 Formatting #show "ArtosFlow": name => box[ #box(image( "logo.svg", height: 0.7em, )) #name ] This report is embedded in the ArtosFlow project. ArtosFlow is a project of the Artos Institute. This report is embedded in the ArtosFlow project. ArtosFlow is a project of the Artos Institute. There is a lot of new syntax in this example: We write the show keyword, followed by a string of text we want to show differently and a colon. Then, we write a function that takes the content that shall be shown as an argument. Here, we called that argument name. We can now use the name variable in the function's body to print the ArtosFlow name. Our show rule adds the logo image in front of the name and puts the result into a box to prevent linebreaks from occurring between logo and name. The image is also put inside of a box, so that it does not appear in its own paragraph. The calls to the first box function and the image function did not require a leading # because they were not embedded directly in markup. When Typst expects code instead of markup, the leading # is not needed to access functions, keywords, and variables. This can be observed in parameter lists, function definitions, and code blocks3.3. 2.2.6 Review You now know how to apply basic formatting to your Typst documents. You learned how to set the font, justify your paragraphs, change the page dimensions, and add numbering to your headings with set rules. You also learned how to use a basic show rule to change how text appears throughout your document. You have handed in your report. Your supervisor was so happy with it that they want to adapt it into a conference paper! In the next section, we will learn how to format your document as a paper using more advanced show rules and functions. 21 2.3 Advanced Styling In the previous two chapters of this tutorial, you have learned how to write a document in Typst and how to change its formatting. The report you wrote throughout the last two chapters got a straight A and your supervisor wants to base a conference paper on it! The report will of course have to comply with the conference's style guide. Let's see how we can achieve that. Before we start, let's create a team, invite your supervisor and add them to the team. You can do this by going back to the app dashboard with the back icon in the top left corner of the editor. Then, choose the plus icon in the left toolbar and create a team. Finally, click on the new team and go to its settings by clicking 'manage team' next to the team name. Now you can invite your supervisor by email. Next, move your project into the team: Open it, going to its settings by choosing the gear icon in the left toolbar and selecting your new team from the owners dropdown. Don't forget to save your changes! Now, your supervisor can also edit the project and you can both see the changes in real time. You can join our Discord server[A] to find other users and try teams with them! 2.3.1 The conference guidelines The layout guidelines are available on the conference website. Let's take a look at them: – The font should be an 11pt serif font – The title should be in 17pt and bold – The paper contains a single-column abstract and two-column main text – The abstract should be centered – The main text should be justified – First level section headings should be 13pt, centered, and rendered in small capitals – Second level headings are run-ins, italicized and have the same size as the body text – Finally, the pages should be US letter sized, numbered in the center of the footer and the top right corner of each page should contain the title of the paper We already know how to do many of these things, but for some of them, we'll need to learn some new tricks. 2.3.2 Writing the right set rules Let's start by writing some set rules for the document. [A]https://discord.gg/2uDybryKPe 22 https://discord.gg/2uDybryKPe https://discord.gg/2uDybryKPe 2.3 Advanced Styling #set page( paper: "us-letter", header: align(right)[ A Fluid Dynamic Model for Glacier Flow ], numbering: "1", ) #set par(justify: true) #set text( font: "Libertinus Serif", size: 11pt, ) #lorem(600) A Fluid Dynamic Model for Glacier Flow Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplifi­ carique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere, Tite!' hinc hostis mi Albucius, hinc inimicus. Sed iure Mucius. Ego autem mirari satis non queo unde hoc sit tam insolens domesticarum rerum fastidium. Non est omnino hic docendi locus; sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo est consecutus? – Laudem et caritatem, quae sunt vitae sine metu degendae praesidia firmissima. – Filium morte multavit. – Si sine causa, nollem me ab eo delectari, quod ista Platonis, Aristoteli, Theophrasti orationis ornamenta neglexerit. Nam illud quidem physici, credere aliquid esse minimum, quod profecto numquam putavisset, si a Polyaeno, familiari suo, geometrica discere maluisset quam illum etiam ipsum dedocere. Sol Democrito magnus videtur, quippe homini erudito in geometriaque perfecto, huic pedalis fortasse; tantum enim esse omnino in nostris poetis aut inertissimae segnitiae est aut fastidii delicatissimi. Mihi quidem videtur, inermis ac nudus est. Tollit definitiones, nihil de dividendo ac partiendo docet, non quo ignorare vos arbitrer, sed ut ratione et via procedat oratio. Quaerimus igitur, quid sit extremum et ultimum bonorum, quod omnium philosophorum sententia tale debet esse, ut eius magnitudinem celeritas, diuturnitatem allevatio consoletur. Ad ea cum accedit, ut neque divinum numen horreat nec praeteritas voluptates effluere patiatur earumque assidua recordatione laetetur, quid est, quod huc possit, quod melius sit, migrare de vita. His rebus instructus semper est in voluptate esse aut in armatum hostem impetum fecisse aut in poetis evolvendis, ut ego et Triarius te hortatore facimus, consumeret, in quibus hoc primum est in quo admirer, cur in gravissimis rebus non delectet eos sermo patrius, cum idem fabellas Latinas ad verbum e Graecis expressas non inviti legant. Quis enim tam inimicus paene nomini Romano est, qui Ennii Medeam aut Antiopam Pacuvii spernat aut reiciat, quod se isdem Euripidis fabulis delectari dicat, Latinas litteras oderit? Synephebos ego, inquit, potius Caecilii aut Andriam Terentii quam utramque Menandri legam? A quibus tantum dissentio, ut, cum Sophocles vel optime scripserit Electram, tamen male conversam Atilii mihi legendam putem, de quo Lucilius: 'ferreum scriptorem', verum, opinor, scrip­ torem tamen, ut legendus sit. Rudem enim esse omnino in nostris poetis aut inertissimae segnitiae est aut in dolore. Omnis autem privatione doloris putat Epicurus terminari summam voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in voluptate aut a voluptate discedere. Nam cum ignoratione rerum bonarum et malarum maxime hominum vita vexetur, ob eumque errorem et voluptatibus maximis saepe priventur et durissimis animi doloribus torqueantur, sapientia est adhibenda, quae et terroribus cupiditatibusque detractis et omnium falsarum opinionum temeritate derepta certissimam se nobis ducem praebeat ad voluptatem. Sapientia enim est una, quae maestitiam pellat ex animis, quae nos exhorrescere metu non sinat. Qua praeceptrice in tranquillitate vivi potest omnium cupiditatum ardore restincto. 1 You are already familiar with most of what is going on here. We set the text size to 11pt and the font to Libertinus Serif. We also enable paragraph justification and set the page size to US letter. The header argument is new: With it, we can provide content to fill the top margin of every page. In the header, we specify our paper's title as requested by the conference style guide. We use the align function to align the text to the right. Last but not least is the numbering argument. Here, we can provide a numbering pattern3.6.13 that defines how to number the pages. By setting it to "1", Typst only displays the bare page number. Setting it to "(1/1)" would have displayed the current page and total number of pages surrounded by parentheses. And we could even have provided a completely custom function here to format things to our liking. 2.3.3 Creating a title and abstract Now, let's add a title and an abstract. We'll start with the title. Typst comes with a title3.6.22 function. Let's start by providing our title as an argument: #title[ A Fluid Dynamic Model for Glacier Flow ] A Fluid Dynamic Model for Glacier Flow You can see that the title is already boldfaced and has some space around it. However, it is left-aligned and not exactly 17pt large. Hence, we need to adjust its appearance. The title function does not come with any arguments for font or text size we could set. Instead, these properties are defined on the text and align functions. INFO What is the difference between what the title function inserted and the headings we produced with equals signs? 23 2.3 Advanced Styling Headings, even first-level headings, can appear multiple times in your document whereas a title only appears once, usually at the beginning. Differentiating between the two helps Typst make your document accessible for users of Assistive Technology such as screen readers. When we want to customize the properties of some element inside of another kind of element, we can use show-set rules. First, we use show to select which element we want to customize. We call this a selector. Then, we type a colon. Next, we write the set rule that should apply to elements matching the selector. Summarized, the syntax looks like this: #show your-selector: set some-element(/* ... */) Let's recall: We want to center-align the title and make it 17pt large. Hence, we need two show-set rules: – One with the selector title and the rule set text(size: 17pt) – One with the selector title and the rule set align(center) Our example now looks like this: #show title: set text(size: 17pt) #show title: set align(center) #title[ A Fluid Dynamic Model for Glacier Flow ] A Fluid Dynamic Model for Glacier Flow This looks right. Let's also add the author list: Since we are writing this paper together with our supervisor, we'll add our own and their name. #grid( columns: (1fr, 1fr), align(center)[ Therese Tungsten \ Artos Institute \ #link("mailto:tung@artos.edu") ], align(center)[ Dr. John Doe \ Artos Institute \ #link("mailto:doe@artos.edu") ] ) A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu The two author blocks are laid out next to each other. We use the grid3.10.10 function to create this layout. With a grid, we can control exactly how large each column is and which content goes into which cell. The columns argument takes an array of relative lengths3.10.21 or fractions3.10.9. In this case, we passed it two equal fractional sizes, telling it to split the available space into two equal columns. We then passed two content arguments to the grid function. The first with our own details, and the second with our supervisors'. We again use the align function to center the content within the column. The grid takes an arbitrary number of content arguments specifying the cells. Rows are added automatically, but they can also be manually sized with the rows argument. Looking at the authors and the title, they are a bit too close together. You can address this by using another show-set rule to configure the space below the title. The title, the grid, and all other elements that Typst arranges from the top to the bottom of the page (except for paragraphs) are called blocks. Each block is controlled by the block3.10.4 function. It controls behaviors like their distance and whether a block can contain a page break. That means that we can write another show-set rule that selects the title to set the block spacing: 24 2.3 Advanced Styling #show title: set text(size: 17pt) #show title: set align(center) #show title: set block(below: 1.2em) #title[ A Fluid Dynamic Model for Glacier Flow ] #grid( // ... ) A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu With this show-set rule, we overrode the spacing below the title. We have used the em unit: It allows us to express lengths as multiples of the font size. Here, we used it to space the title and the author list exactly 1.2× the font size apart. Now, let's add the abstract. Remember that the conference wants the abstract to be set ragged and centered. ... #align(center)[ #set par(justify: false) *Abstract* \ #lorem(80) ] A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplifi­ carique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere, Tite!' hinc hostis mi Albucius, hinc inimicus. Sed iure Mucius. Ego autem mirari satis non queo unde hoc sit tam insolens domesticarum rerum fastidium. Non est omnino hic docendi locus; sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo est consecutus? – Laudem et caritatem, quae sunt vitae sine metu degendae praesidia firmissima. – Filium morte multavit. – Si sine causa, nollem me ab eo delectari, quod ista Platonis, Aristoteli, Theophrasti orationis ornamenta neglexerit. Nam illud quidem physici, credere aliquid esse minimum, quod profecto numquam putavisset, si a Polyaeno, familiari suo, geometrica discere maluisset quam illum etiam ipsum dedocere. Sol Democrito magnus videtur, quippe homini erudito in geometriaque perfecto, huic pedalis fortasse; tantum enim esse omnino in nostris poetis aut inertissimae segnitiae est aut fastidii delicatissimi. Mihi quidem videtur, inermis ac nudus est. Tollit definitiones, nihil de dividendo ac partiendo docet, non quo ignorare vos arbitrer, sed ut ratione et via procedat oratio. Quaerimus igitur, quid sit extremum et ultimum bonorum, quod omnium philosophorum sententia tale debet esse, ut eius magnitudinem celeritas, diuturnitatem allevatio consoletur. Ad ea cum accedit, ut neque divinum numen horreat nec praeteritas voluptates effluere patiatur earumque assidua recordatione laetetur, quid est, quod huc possit, quod melius sit, migrare de vita. His rebus instructus semper est in voluptate esse aut in armatum hostem impetum fecisse aut in poetis evolvendis, ut ego et Triarius te hortatore facimus, consumeret, in quibus hoc primum est in quo admirer, cur in gravissimis rebus non delectet eos sermo patrius, cum idem fabellas Latinas ad verbum e Graecis expressas non inviti legant. Quis enim tam inimicus paene nomini Romano est, qui Ennii Medeam aut Antiopam Pacuvii spernat aut reiciat, quod se isdem Euripidis fabulis delectari dicat, Latinas litteras oderit? Synephebos ego, inquit, potius Caecilii aut Andriam Terentii quam utramque Menandri legam? A quibus tantum dissentio, ut, cum Sophocles vel optime scripserit Electram, tamen male conversam Atilii mihi legendam putem, de quo Lucilius: 'ferreum scriptorem', verum, opinor, scrip­ 1 Well done! One notable thing is that we used a set rule within the content argument of align to turn off justification for the abstract. This does not affect the remainder of the document even though it was specified after the first set rule because content blocks scope styling. Anything set within a content block will only affect the content within that block. Another tweak could be to remove the duplication between the header and the title element's argument. Since they share the title, it would be convenient to store it in a place designed to hold metadata about the document. We would then need a way to retrieve the title in both places. The document element can help us with the former: By using it in a set rule, we can store document metadata like title, description, and keywords. #set document(title: [A Fluid Dynamic Model for Glacier Flow]) When exporting a PDF, the title set here will appear in the title bar of your PDF reader. Your operating system will also use this title to make the file retrievable with search. Last but not least, it contributes to making your document more accessible and is required if you choose to comply with PDF/UA, a PDF standard focused on accessibility. Now, we need a way to retrieve the value we set in the main title and the header. Because the title function is designed to work together with the document element, calling it with no arguments will just print the title. For the header, we will need to be more explicit: Because Typst has no way of knowing that we want to insert the title there, we will need to tell it to do so manually. Using context, we can retrieve the contents of any values we have set on elements before. When we use the context keyword, we can access any property of any element, including the document element's title property. Its use looks like this: 25 2.3 Advanced Styling #set document(title: [ A Fluid Dynamic Model for Glacier Flow ]) ... #set page( header: align( right + horizon, // Retrieve the document // element's title property. context document.title, ), ... ) #title() ... A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplifi­ carique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere, Tite!' hinc hostis mi Albucius, hinc inimicus. Sed iure Mucius. Ego autem mirari satis non queo unde hoc sit tam insolens domesticarum rerum fastidium. Non est omnino hic docendi locus; sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo est consecutus? – Laudem et caritatem, quae sunt vitae sine metu degendae praesidia firmissima. – Filium morte multavit. – Si sine causa, nollem me ab eo delectari, quod ista Platonis, Aristoteli, Theophrasti orationis ornamenta neglexerit. Nam illud quidem physici, credere aliquid esse minimum, quod profecto numquam putavisset, si a Polyaeno, familiari suo, geometrica discere maluisset quam illum etiam ipsum dedocere. Sol Democrito magnus videtur, quippe homini erudito in geometriaque perfecto, huic pedalis fortasse; tantum enim esse omnino in nostris poetis aut inertissimae segnitiae est aut fastidii delicatissimi. Mihi quidem videtur, inermis ac nudus est. Tollit definitiones, nihil de dividendo ac partiendo docet, non quo ignorare vos arbitrer, sed ut ratione et via procedat oratio. Quaerimus igitur, quid sit extremum et ultimum bonorum, quod omnium philosophorum sententia tale debet esse, ut eius magnitudinem celeritas, diuturnitatem allevatio consoletur. Ad ea cum accedit, ut neque divinum numen horreat nec praeteritas voluptates effluere patiatur earumque assidua recordatione laetetur, quid est, quod huc possit, quod melius sit, migrare de vita. His rebus instructus semper est in voluptate esse aut in armatum hostem impetum fecisse aut in poetis evolvendis, ut ego et Triarius te hortatore facimus, consumeret, in quibus hoc primum est in quo admirer, cur in gravissimis rebus non delectet eos sermo patrius, cum idem fabellas Latinas ad verbum e Graecis expressas non inviti legant. Quis enim tam inimicus paene nomini Romano est, qui Ennii Medeam aut Antiopam Pacuvii spernat aut reiciat, quod se isdem Euripidis fabulis delectari dicat, Latinas litteras oderit? Synephebos ego, inquit, potius Caecilii aut Andriam Terentii quam utramque Menandri legam? A quibus tantum dissentio, ut, cum Sophocles vel optime scripserit Electram, tamen male conversam Atilii mihi legendam putem, de quo Lucilius: 'ferreum scriptorem', verum, opinor, scrip­ 1 First, notice how we called the title function with empty, round parentheses. Because no argument was passed, it defaulted to what we set for the document element above. The distinction between empty round and empty square brackets is important: While empty round brackets show that you are passing nothing, empty square brackets mean that you are passing one argument: an empty content block. If called that way, the title would have no visible content. Next, take a look at the header. Instead of the title in square parentheses, we used the context keyword to access the document title. This inserted exactly what we set above. The role of context is not limited to accessing properties: With it, you can check if some elements are present in the document, measure the physical dimensions of others, and more. Using context, you can build powerful templates that react to the preferences of the end-user. INFO Why is the context keyword required to access element properties? Normally, when we access a variable, we know exactly what its value is going to be: – The variable could be a constant built into Typst, like #sym.pi – The variable could be defined by an argument – The variable could be defined or overwritten in the current scope However, sometimes, that's not enough. In this chapter of the tutorial, we have inserted a page header with the title. Even though we pass only one piece of content for the header, we may want different pages to have different headers. For example, we may want to print the chapter name or use the page number. When we use context, we can write a single context block that tells Typst to take a look at where it's inserted, look for the last heading, the current page number, or anything else, and go from there. That means that the same context block, inserted on different pages, can produce different output. For more information, read up on context in its docs3.4 after completing this tutorial. 2.3.4 Adding columns and headings The paper above unfortunately looks like a wall of lead. To fix that, let's add some headings and switch our paper to a two-column layout. Fortunately, that's easy to do: We just need to amend our page set rule with the columns argument. 26 2.3 Advanced Styling By adding columns: 2 to the argument list, we have wrapped the whole document in two columns. However, that would also affect the title and authors overview. To keep them spanning the whole page, we can wrap them in a function call to place3.10.19. Place expects an alignment and the content it should place as positional arguments. Using the named scope argument, we can decide if the items should be placed relative to the current column or its parent (the page). There is one more thing to configure: If no other arguments are provided, place takes its content out of the flow of the document and positions it over the other content without affecting the layout of other content in its container: #place( top + center, rect(fill: black), ) #lorem(30) Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri. If we hadn't used place here, the square would be in its own line, but here it overlaps the few lines of text following it. Likewise, that text acts as if there was no square. To change this behavior, we can pass the argument float: true to ensure that the space taken up by the placed item at the top or bottom of the page is not occupied by any other content. #set page( paper: "us-letter", header: align( right + horizon, context document.title, ), numbering: "1", columns: 2, ) #place( top + center, float: true, scope: "parent", clearance: 2em, )[ ... #par(justify: false)[ *Abstract* \ #lorem(80) ] ] = Introduction #lorem(300) = Related Work #lorem(200) A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Introduction Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Tempo­ ribus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet, ut et volup­ tates repudiandae sint et molestiae non recusan­ dae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma om­ nis chorusque: 'chaere, Tite!' hinc hostis mi Albu­ cius, hinc inimicus. Sed iure Mucius. Ego autem mirari satis non queo unde hoc sit tam insolens do­ mesticarum rerum fastidium. Non est omnino hic docendi locus; sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo est consecutus? – Laudem et caritatem, quae sunt vitae sine metu degendae praesidia firmis­ sima. – Filium morte multavit. – Si sine causa, nollem me ab eo delectari, quod ista Platonis, Aris­ toteli, Theophrasti orationis ornamenta neglexerit. Nam illud quidem physici, credere aliquid esse minimum, quod profecto numquam putavisset, si a Polyaeno, familiari suo, geometrica discere maluisset quam illum etiam ipsum dedocere. Sol Democrito magnus videtur, quippe homini erudito in geometriaque perfecto, huic pedalis fortasse; tantum enim esse omnino in nostris poetis aut inertissimae segnitiae est aut fastidii delicatissimi. Mihi quidem videtur, inermis ac nudus est. Tollit definitiones, nihil de dividendo ac partiendo docet, non quo ignorare vos arbitrer, sed ut ratione et via. Related Work Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis deb­ itis aut rerum necessitatibus saepe eveniet, ut 1 In this example, we also used the clearance argument of the place function to provide the space between it and the body instead of using the v3.10.27 function. We can also remove the explicit align(center, ..) calls around the various parts since they inherit the center alignment from the placement. Now there is only one thing left to do: Style our headings. We need to make them centered and use small capitals. These properties are not available on the heading function, so we will need to write a few show- set rules and a show rule: – A show-set rule to make headings center-aligned – A show-set rule to make headings 13pt large and use the regular weight – A show rule to wrap the headings in a call to the smallcaps function 27 2.3 Advanced Styling #show heading: set align(center) #show heading: set text( size: 13pt, weight: "regular", ) #show heading: smallcaps ... = Introduction ... == Motivation ... A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Introduction Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si. Motivation Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem. 1 This looks great! We used show rules that apply to all headings. In the final show rule, we applied the smallcaps function to the complete heading. As we will see in the next example, we can also provide a custom rule to completely override the default look of headings. The only remaining problem is that all headings look the same now. The "Motivation" and "Problem Statement" subsections ought to be italic run-in headers, but right now, they look indistinguishable from the section headings. We can fix that by using a where selector on our show rule: This is a method3.3.7 we can call on headings (and other elements) that allows us to filter them by their properties. We can use it to differentiate between section and subsection headings: #show heading.where(level: 1): set align(center) #show heading.where(level: 1): set text(size: 13pt, weight: "regular") #show heading.where(level: 1): smallcaps #show heading.where(level: 2): set text( size: 11pt, weight: "regular", style: "italic", ) #show heading.where(level: 2): it => { it.body + [.] } 28 2.3 Advanced Styling A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Therese Tungsten Artos Institute tung@artos.edu Dr. John Doe Artos Institute doe@artos.edu Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Introduction Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si. Motivation. Lorem ipsum dolor sit amet, con­ sectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus an­ imo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem. 1 In this example, we first scope our previous rules to first-level headings by using .where(level: 1) to make the selector more specific. Then, we add a show-set rule for the second heading level. Finally, we need a show rule with a custom function: Headings enclose their contents with a block by default. This has the effect that the heading gets its own line. However, we want it to run into the text, so we need to provide our own show rule to get rid of this block. We provide the rule with a function that takes the heading as a parameter. This parameter is conventionally called it, but can have another name. The parameter can be used as content and will just display the whole default heading. Alternatively, when we want to build our own heading instead, we can use its fields like body, numbering, and level to compose a custom look. Here, we are just printing the body of the heading with a trailing dot and leave out the block that the built-in show rule produces. Note that this heading will no longer react to set rules for heading numbering and similar because we did not explicitly use it.numbering in the show rule. If you are writing show rules like this and want the document to remain customizable, you will need to take these fields into account. This looks great! We wrote show rules that selectively apply to the first and second level headings. We used a where selector to filter the headings by their level. We then rendered the subsection headings as run-ins. We also automatically add a period to the end of the subsection headings. Let's review the conference's style guide: ✓ The font should be an 11pt serif font ✓ The title should be in 17pt and bold ✓ The paper contains a single-column abstract and two-column main text ✓ The abstract should be centered ✓ The main text should be justified ✓ First level section headings should be centered, rendered in small caps and in 13pt ✓ Second level headings are run-ins, italicized and have the same size as the body text ✓ Finally, the pages should be US letter sized, numbered in the center and the top right corner of each page should contain the title of the paper We are now in compliance with all of these styles and can submit the paper to the conference! The finished paper looks like this: 29 2.3 Advanced Styling 2.3.5 Review You have now learned how to create titles, headers, and footers, how to use functions, show-set rules, and scopes to locally override styles, how to create more complex layouts with the grid3.10.10 function, how to access element properties with context, and how to write show rules for individual functions, and the whole document. You also learned how to use the where selector3.2.2 to filter the headings by their level. The paper was a great success! You've met a lot of like-minded researchers at the conference and are planning a project which you hope to publish at the same venue next year. You'll need to write a new paper using the same style guide though, so maybe now you want to create a time-saving template for you and your team? In the next section, we will learn how to create templates that can be reused in multiple documents. This is a more advanced topic, so feel free to come back to it later if you don't feel up to it right now. 30 2.4 Making a Template In the previous three chapters of this tutorial, you have learned how to write a document in Typst, apply basic styles, and customize its appearance in-depth to comply with a publisher's style guide. Because the paper you wrote in the previous chapter was a tremendous success, you have been asked to write a follow- up article for the same conference. This time, you want to take the style you created in the previous chapter and turn it into a reusable template. In this chapter you will learn how to create a template that you and your team can use with just one show rule. Let's get started! 2.4.1 Reusing data with variables In the past chapters, most of the content of the document was entered by hand. In the third chapter, we used the document element and context to cut down on repetition and only enter the title once. But in practice, there may be many more things that occur multiple times in your document. There are multiple good reasons to just define these repeated values once: 1. It makes changing them later easier 2. It allows you to quickly find all instances where you used something 3. It makes it easy to be consistent throughout 4. For long or hard-to-enter repeated segments, a shorter variable name is often more convenient to type If you were using a conventional word processor, you might resort to using a placeholder value that you can later search for. In Typst, however, you can instead use variables to safely store content and reuse it across your whole document through a variable name. The technique of using context to reproduce an element's property we have learned earlier is not always the most appropriate for this: Typst's built-in elements focus on semantic properties like the title and description of a document, or things that directly relate to typesetting, like the text size. For our example, we want to take a look at Typst's pronunciation. One of the best ways to transcribe pronunciation is the International Phonetic Alphabet (IPA). But because it uses characters not found on common keyboards, typing IPA repeatedly can become cumbersome. So let's instead define a variable that we can reference multiple times. #let ipa = [taɪpst] Here, we use a new keyword, let, to indicate a variable definition. Then, we put the name of our variable, in this case, ipa. Finally, we type an equals sign and the value of our variable. It is enclosed in square brackets because it is content, mirroring how you would call a function accepting content. In other words, this syntax mirrors the phrase "Let the variable ipa have the value [taɪpst]." Now, we can use the variable in our document: #let ipa = [taɪpst] The canonical way to pronounce Typst is #ipa. #table( columns: (1fr, 1fr), [Name], [Typst], [Pronunciation], ipa, ) The canonical way to pronounce Typst is taɪpst. Name Typst Pronunciation taɪpst In the example, you can see that the variable can be used both in markup (prefixed with a #) and in a function call (by just typing its name). Of course, we can change the value of the variable and all its occurrences will automatically change with it. Let's make it a bit clearer what is IPA and what is normal prose by rendering IPA in italics. We are also using slashes which, by convention, often enclose IPA. 31 2.4 Making a Template #let ipa = text( style: "italic", )[/taɪpst/] The canonical way to pronounce Typst is #ipa. #table( columns: (1fr, 1fr), [Name], [Typst], [Pronunciation], ipa, ) The canonical way to pronounce Typst is /taɪpst/. Name Typst Pronunciation /taɪpst/ Here, we called the text function and assigned its return value to the variable. When you call a function, it processes its arguments and then yields another value (often content). So far in this tutorial, we called most functions directly in markup, like this: #text(fill: red)[CRIMSON!]. This call to the text function returns the red text as a return value. Because we placed it in markup, its return value just immediately got inserted into the content we wrote. With variables, we can instead store it to use it later or compose it with other values. Variables are not limited to storing content: they can store any data type Typst knows about. Throughout this tutorial, you made use of many data types when you passed them to Typst's built-in functions. Here is an example assigning each of them to a variable: // Content with markup inside #let blind-text = [_Lorem ipsum_ dolor sit amet] // Unformatted strings #let funny-font = "MS Comic Sans" // Absolute lengths (see also pt, in, ...) #let mile = 160934cm // Lengths relative to the font size #let double-space = 2em // Ratios #let progress = 80% // Integer numbers #let answer = 42 // Booleans #let truth = false // Horizontal and vertical alignment #let focus = center In this chapter of the tutorial, you will leverage variables and your own functions to build templates that can be reused across multiple documents. 2.4.2 A toy template In Typst, templates are functions in which you can wrap your whole document. To learn how to do that, let's first review how to write your very own functions. They can do anything you want them to, so why not go a bit crazy? #let amazed(term) = box[✨ #term ✨] You are #amazed[beautiful]! You are ✨ beautiful ✨! 32 2.4 Making a Template Comparing this against the previous section, you may have noticed that this looks a lot like a variable definition using let. This instinct is correct: Functions are just another data type. Here, we are defining the variable amazed, assigning it a function that takes a single argument, term, and returns content with the term surrounded by sparkles. We also put the whole thing in a box3.10.5 so that the term we are amazed by cannot be separated from its sparkles by a line break. The special function definition syntax makes the definition shorter and more readable, but you can also use the regular variable definition syntax (see the scripting reference3.3.3 for details). After its definition, we are able to call the function just like all built-in functions. Many functions that come with Typst have optional named parameters. Our functions can also have them. Let's add a parameter to our function that lets us choose the color of the text. We need to provide a default color in case the parameter isn't given. #let amazed(term, color: blue) = { text(color, box[✨ #term ✨]) } You are #amazed[beautiful]! I am #amazed(color: purple)[amazed]! You are ✨ beautiful ✨! I am ✨ amazed ✨! Templates now work by wrapping our whole document in a custom function like amazed. But wrapping a whole document in a giant function call would be cumbersome! Instead, we can use an "everything" show rule to achieve the same with cleaner code. To write such a show rule, put a colon directly after the show keyword and then provide a function. This function is given the rest of the document as a parameter. The function can then do anything with this content. Since the amazed function can be called with a single content argument, we can just pass it by name to the show rule. Let's try it: #show: amazed I choose to focus on the good in my life and let go of any negative thoughts or beliefs. In fact, I am amazing! ✨ I choose to focus on the good in my life and let go of any negative thoughts or beliefs. In fact, I am amazing! ✨ Our whole document will now be passed to the amazed function, as if we wrapped it around it. Of course, this is not especially useful with this particular function, but when combined with set rules and named arguments, it can be very powerful. 2.4.3 Embedding set and show rules To apply some set and show rules to our template, we can use set and show within a content block in our function and then insert the document into that content block. #let template(doc) = [ #set text(font: "Inria Serif") #show "something cool": [Typst] #doc ] #show: template I am learning something cool today. It's going great so far! I am learning Typst today. It's going great so far! Just like we already discovered in the previous chapter, set rules will apply to everything within their content block. Since the everything show rule passes our whole document to the template function, the text set rule and string show rule in our template will apply to the whole document. Let's use this knowledge to create a template that reproduces the body style of the paper we wrote in the previous chapter. 33 2.4 Making a Template #let conf(title, doc) = { set page( paper: "us-letter", header: align( right + horizon, title ), columns: 2, ... ) set par(justify: true) set text( font: "Libertinus Serif", size: 11pt, ) // Heading show rules. ... doc } #show: doc => conf( [Paper title], doc, ) = Introduction ... Paper title Introduction Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis. Motivation. Lorem ipsum dolor sit amet, con­ sectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus an­ imo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis deb­ itis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere. Problem Statement. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus an­ imo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut. Related Work Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis deb­ itis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere, Tite!' hinc hostis mi Albucius, hinc inimicus. Sed iure Mucius. Ego autem mirari satis non queo unde hoc sit tam insolens domesticarum rerum fastidium. Non est omnino hic docendi locus; sed ita prorsus existimo, neque eum Torquatum, qui hoc primus cognomen invenerit, aut torquem illum hosti detraxisse, ut aliquam ex eo est consecutus? – Laudem et cari­ tatem, quae sunt vitae sine. 1 We copy-pasted most of that code from the previous chapter. The two differences are this: 1. We wrapped everything in the function conf using an everything show rule. The function applies a few set and show rules and echoes the content it has been passed at the end. 2. Moreover, we used a curly-braced code block instead of a content block. This way, we don't need to prefix all set rules and function calls with a #. In exchange, we cannot write markup directly in the code block anymore. Also note where the title comes from: We previously had it inside of a variable. Now, we are receiving it as the first parameter of the template function. To do so, we passed a closure (that's a function without a name that is used right away) to the everything show rule. We did that because the conf function expects two positional arguments, the title and the body, but the show rule will only pass the body. Therefore, we add a new function definition that allows us to set a paper title and use the single parameter from the show rule. 2.4.4 Templates with named arguments Our paper in the previous chapter had a title and an author list. Let's add these things to our template. In addition to the title, we want our template to accept a list of authors with their affiliations and the paper's abstract. To keep things readable, we'll add those as named arguments. In the end, we want it to work like this: #show: doc => conf( title: [ A Fluid Dynamic Model for Glacier Flow ], authors: ( ( name: "Theresa Tungsten", affiliation: "Artos Institute", email: "tung@artos.edu", 34 2.4 Making a Template ), ( name: "Eugene Deklan", affiliation: "Honduras State", email: "e.deklan@hstate.hn", ), ), abstract: lorem(80), doc, ) ... Let's build this new template function. First, we add a default value to the title argument. This way, we can call the template without specifying a title. We also add the named authors and abstract parameters with empty defaults. Next, we copy the code that generates title, abstract and authors from the previous chapter into the template, replacing the fixed details with the parameters. The new authors parameter expects an array3.5.2 of dictionaries3.5.11 with the keys name, affiliation and email. Because we can have an arbitrary number of authors, we dynamically determine if we need one, two or three columns for the author list. First, we determine the number of authors using the .len()3.5.2/3.1 method on the authors array. Then, we set the number of columns as the minimum of this count and three, so that we never create more than three columns. If there are more than three authors, a new row will be inserted instead. For this purpose, we have also added a row-gutter parameter to the grid function. Otherwise, the rows would be too close together. To extract the details about the authors from the dictionary, we use the field access syntax3.3.6. We still have to provide an argument to the grid for each author: Here is where the array's map method3.5.2/3.15 comes in handy. It takes a function as an argument that gets called with each item of the array. We pass it a function that formats the details for each author and returns a new array containing content values. We've now got one array of values that we'd like to use as multiple arguments for the grid. We can do that by using the spread operator3.5.1. It takes an array and applies each of its items as a separate argument to the function. The resulting template function looks like this: #let conf( authors: (), abstract: [], doc, ) = { // Set and show rules from before. ... place( top + center, float: true, scope: "parent", clearance: 2em, { title() let count = authors.len() let ncols = calc.min(count, 3) grid( columns: (1fr,) * ncols, row-gutter: 24pt, ..authors.map(author => [ #author.name \ #author.affiliation \ #link("mailto:" + author.email) ]), 35 2.4 Making a Template ) par(justify: false)[ *Abstract* \ #abstract ] } ) doc } 2.4.5 A separate file Most of the time, a template is specified in a different file and then imported into the document. This way, the main file you write in is kept clutter free and your template is easily reused. Create a new text file in the file panel by clicking the plus button and name it conf.typ. Move the conf function definition inside of that new file. Now you can access it from your main file by adding an import before the show rule. Specify the path of the file between the import keyword and a colon, then name the function that you want to import. Another thing that you can do to make applying templates just a bit more elegant is to use the .with3.5.15/8.1 method on functions to pre-populate all the named arguments. This way, you can avoid spelling out a closure and appending the content argument at the bottom of your template list. Templates on Typst Universe[A] are designed to work with this style of function call. #import "conf.typ": conf #set document(title: [ A Fluid Dynamic Model for Glacier Flow ]) #show: conf.with( authors: ( ( name: "Theresa Tungsten", affiliation: "Artos Institute", email: "tung@artos.edu", ), ( name: "Eugene Deklan", affiliation: "Honduras State", email: "e.deklan@hstate.hn", ), ), abstract: lorem(80), ) = Introduction #lorem(90) == Motivation #lorem(140) == Problem Statement #lorem(50) = Related Work #lorem(200) A Fluid Dynamic Model for Glacier Flow A Fluid Dynamic Model for Glacier Flow Theresa Tungsten Artos Institute tung@artos.edu Eugene Deklan Honduras State e.deklan@hstate.hn Abstract Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et. Introduction Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis. Motivation. Lorem ipsum dolor sit amet, con­ sectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus an­ imo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distinguique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis deb­ itis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum defuturum, quas natura non depravata desiderat. Et quem ad me accedis, saluto: 'chaere,' inquam, 'Tite!' lictores, turma omnis chorusque: 'chaere. Problem Statement. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim aeque doleamus an­ imo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut. Related Work Lorem ipsum dolor sit amet, consectetur adipisc­ ing elit, sed do eiusmod tempor incididunt ut labore et dolore magnam aliquam quaerat volup­ tatem. Ut enim aeque doleamus animo, cum corpore dolemus, fieri tamen permagna accessio potest, si aliquod aeternum et infinitum impendere malum nobis opinemur. Quod idem licet transferre in voluptatem, ut postea variari voluptas distin­ guique possit, augeri amplificarique non possit. At etiam Athenis, ut e patre audiebam facete et urbane Stoicos irridente, statua est in quo a nobis philosophia defensa et collaudata est, cum id, quod maxime placeat, facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis deb­ itis aut rerum necessitatibus saepe eveniet, ut et voluptates repudiandae sint et molestiae non 1 [A]https://typst.app/universe 36 https://typst.app/universe https://typst.app/universe 2.4 Making a Template We have now converted the conference paper into a reusable template for that conference! Why not share it in the Forum[A] or on Typst's Discord server[B] so that others can use it too? 2.4.6 Review Congratulations, you have completed Typst's Tutorial! In this section, you have learned how to define your own functions and how to create and apply templates that define reusable document styles. You've made it far and learned a lot. You can now use Typst to write your own documents and share them with others. We are still a super young project and are looking for feedback. If you have any questions, suggestions or you found a bug, please let us know in the Forum[C], on our Discord server[D], on GitHub[E], or via the web app's feedback form (always available in the Help menu). So what are you waiting for? Sign up[F] and write something! [A]https://forum.typst.app/ [B]https://discord.gg/2uDybryKPe [C]https://forum.typst.app/ [D]https://discord.gg/2uDybryKPe [E]https://github.com/typst/typst/ [F]https://typst.app 37 https://forum.typst.app/ https://discord.gg/2uDybryKPe https://forum.typst.app/ https://discord.gg/2uDybryKPe https://github.com/typst/typst/ https://typst.app https://forum.typst.app/ https://discord.gg/2uDybryKPe https://forum.typst.app/ https://discord.gg/2uDybryKPe https://github.com/typst/typst/ https://typst.app 3 Reference This reference documentation is a comprehensive guide to all of Typst's syntax, concepts, functions, types, and other definitions. Use the reference to answer specific questions about Typst and to broaden your understanding of the available features. If you are completely new to Typst, we recommend starting with the tutorial2 and then coming back to the reference to learn more about Typst's features as you need them. 3.0.1 Language The reference starts by covering fundamentals of the Typst language. First, we give an overview of Typst's syntax.3.1 The following sections cover core concepts central to the Typst language such as styling docu ments,3.2 using Typst's scripting capabilities,3.3 and reasoning about the contents of your document.3.4 3.0.2 Library Starting with Foundations3.5, the reference includes sections on all functions, types, and other definitions provided by the standard library of the Typst language. The definition sections are grouped by topic. For example, if you would like to explore all tools Typst provides to adjust where elements land on the page, you should start in the Layout3.10 section. 3.0.3 Export Some of the features in Typst only apply to certain output file formats. Starting in the PDF3.14 section, you can find chapters for each of the output formats Typst supports. This is where you find the available format- specific settings and learn what features are available to customize your document for a given format. 3.0.4 Reading the reference This reference uses a few graphical conventions and labels to let you quickly scan its sections. str These pills indicate that a value is of a particular type. Each type's chapter uses the respective pill as its title. Similar types share a color. For example, all numeric types have the same color. Element Some functions are labelled as elements. This means that they can be used with set and show rules. Some elements can be located3.12.3 and used with the query3.12.6 function. Elements generally produce visible output in the document. You may be using elements even if you are not calling functions, as there is dedicated markup for some elements. Contextual These functions can reason about the contents of your document. They can only be used when context is available, for example through a context block. Refer to the Context3.4 section for more information. Required Appears on a function parameter if calling the function without that parameter would result in an error. Positional Appears on a function parameter that is specified without a parameter name and colon. Instead, Typst will use the parameter order to determine which argument is which. Parameters not marked as positional are named parameters. Variadic Appears on function parameters that can be specified multiple times. Settable Appears on function parameters of element functions that can be customized with a set rule. 38 3.1 Syntax Typst is a markup language. This means that you can use simple syntax to accomplish common layout tasks. The lightweight markup syntax is complemented by set and show rules, which let you style your document easily and automatically. All this is backed by a tightly integrated scripting language with built-in and user- defined functions. 3.1.1 Modes Typst has three syntactical modes: Markup, math, and code. Markup mode is the default in a Typst document, math mode lets you write mathematical formulas, and code mode lets you use Typst's scripting features. You can switch to a specific mode at any point by referring to the following table: New mode Syntax Example Code Prefix the code with # Number: #(1 + 2) Math Surround equation with $..$ $-x$ is the opposite of $x$ Markup Surround markup with [..] let name = [*Typst!*] Once you have entered code mode with #, you don't need to use further hashes unless you switched back to markup or math mode in between. 3.1.2 Markup Typst provides built-in markup for the most common document elements. Most of the syntax elements are just shortcuts for a corresponding function. The table below lists all markup that is available and links to the best place to learn more about their syntax and usage. Name Example See Paragraph break Blank line parbreak3.6.16 Strong emphasis *strong* strong3.6.19 Emphasis _emphasis_ emph3.6.7 Raw text `print(1)` raw3.7.6 Link https://typst.app/ link3.6.11 Label label3.5.17 Reference @intro ref3.6.18 Heading = Heading heading3.6.10 Bullet list - item list3.6.3 Numbered list + item enum3.6.12 Term list / Term: description terms3.6.21 Math $x^2$ Math3.8 Line break \ linebreak3.7.2 Smart quote 'single' or "double" smartquote3.7.8 Symbol shorthand ~, --- Symbols3.9.1 Code expression #rect(width: 1cm) Scripting3.3.1 Character escape Tweet at us \#ad Below3.1.6 Comment /* block */, // line Below3.1.5 3.1.3 Math mode Math mode is a special markup mode that is used to typeset mathematical formulas. It is entered by wrapping an equation in $ characters. This works both in markup and code. The equation will be typeset 39 3.1 Syntax into its own block if it starts and ends with at least one space (e.g. $ x^2 $). Inline math can be produced by omitting the whitespace (e.g. $x^2$). An overview over the syntax specific to math mode follows: Name Example See Inline math $x^2$ Math3.8 Block-level math $ x^2 $ Math3.8 Bottom attachment $x_1$ attach3.8.10 Top attachment $x^2$ attach3.8.10 Fraction $1 + (a+b)/5$ frac3.8.16 Line break $x \ y$ linebreak3.7.2 Alignment point $x &= 2 \ &= 3$ Math3.8 Variable access $#x$, $pi$ Math3.8 Field access $arrow.r.long$ Scripting3.3.6 Implied multiplication $x y$ Math3.8 Symbol shorthand $->$, $!=$ Symbols3.9.1 Text/string in math $a "is natural"$ Math3.8 Math function call $floor(x)$ Math3.8 Code expression $#rect(width: 1cm)$ Scripting3.3.1 Character escape $x\^2$ Below3.1.6 Comment $/* comment */$ Below3.1.5 3.1.4 Code mode Within code blocks and expressions, new expressions can start without a leading # character. Many syntactic elements are specific to expressions. Below is a table listing all syntax that is available in code mode: Name Example See None none none3.5.19 Auto auto auto3.5.4 Boolean false, true bool3.5.5 Integer 10, 0xff int3.5.16 Floating-point number 3.14, 1e5 float3.5.14 Length 2pt, 3mm, 1em, .. length3.10.13 Angle 90deg, 1rad angle3.10.3 Fraction 2fr fraction3.10.9 Ratio 50% ratio3.10.20 String "hello" str3.5.27 Label label3.5.17 Math $x^2$ Math3.8 Raw text `print(1)` raw3.7.6 Variable access x Scripting3.3.2 Code block { let x = 1; x + 2 } Scripting3.3.2 Content block [*Hello*] Scripting3.3.2 Parenthesized expression (1 + 2) Scripting3.3.2 Array (1, 2, 3) Array3.5.2 Dictionary (a: "hi", b: 2) Dictionary3.5.11 Unary operator -x Scripting3.3.10 Binary operator x + y Scripting3.3.10 Assignment x = 1 Scripting3.3.10 40 3.1 Syntax Name Example See Field access x.y Scripting3.3.6 Method call x.flatten() Scripting3.3.7 Function call min(x, y) Function3.5.15 Argument spreading min(..nums) Arguments3.5.1 Unnamed function (x, y) => x + y Function3.5.15/6 Let binding let x = 1 Scripting3.3.3 Named function let f(x) = 2 * x Function3.5.15 Set rule set text(14pt) Styling3.2.1 Set-if rule set text(..) if .. Styling3.2.1 Show-set rule show heading: set block(..) Styling3.2.2 Show rule with function show raw: it => {..} Styling3.2.2 Show-everything rule show: template Styling3.2.2 Context expression context text.lang Context3.4 Conditional if x == 1 {..} else {..} Scripting3.3.4 For loop for x in (1, 2, 3) {..} Scripting3.3.5 While loop while x < 10 {..} Scripting3.3.5 Loop control flow break, continue Scripting3.3.5 Return from function return x Function3.5.15 Include module include "bar.typ" Scripting3.3.8 Import module import "bar.typ" Scripting3.3.8 Import items from module import "bar.typ": a, b, c Scripting3.3.8 Comment /* block */, // line Below3.1.5 3.1.5 Comments Comments are ignored by Typst and will not be included in the output. This is useful to exclude old versions or to add annotations. To comment out a single line, start it with //: // our data barely supports // this claim We show with $p < 0.05$ that the difference is significant. We show with 𝑝 < 0.05 that the difference is significant. Comments can also be wrapped between /* and */. In this case, the comment can span over multiple lines: Our study design is as follows: /* Somebody write this up: - 1000 participants. - 2x2 data design. */ Our study design is as follows: 3.1.6 Escape sequences Escape sequences are used to insert special characters that are hard to type or otherwise have special meaning in Typst. To escape a character, precede it with a backslash. To insert any Unicode codepoint, you can write a hexadecimal escape sequence: \u{1f600}. The same kind of escape sequences also work in strings3.5.27. 41 3.1 Syntax I got an ice cream for \$1.50! \u{1f600} I got an ice cream for $1.50! 😀 3.1.7 Identifiers Names of variables, functions, and so on (identifiers) can contain letters, numbers, hyphens (-), and under scores (_). They must start with a letter or an underscore. More specifically, the identifier syntax in Typst is based on the Unicode Standard Annex #31[A], with two extensions: Allowing _ as a starting character, and allowing both _ and - as continuing characters. For multi-word identifiers, the recommended case convention is Kebab case[B]. In Kebab case, words are written in lowercase and separated by hyphens (as in top-edge). This is especially relevant when developing modules and packages for others to use, as it keeps things predictable. #let kebab-case = [Using hyphen] #let _schön = "😊" #let 始料不及 = "😱" #let π = calc.pi #kebab-case #if -π < 0 { _schön } else { 始料不及 } // -π means -1 * π, // so it's not a valid identifier Using hyphen 😊 [A]https://www.unicode.org/reports/tr31/ [B]https://en.wikipedia.org/wiki/Letter_case#Kebab_case 42 https://www.unicode.org/reports/tr31/ https://en.wikipedia.org/wiki/Letter_case#Kebab_case https://www.unicode.org/reports/tr31/ https://en.wikipedia.org/wiki/Letter_case#Kebab_case 3.2 Styling Typst includes a flexible styling system that automatically applies styling of your choice to your document. With set rules, you can configure basic properties of elements. This way, you create most common styles. However, there might not be a built-in property for everything you wish to do. For this reason, Typst further supports show rules that can completely redefine the appearance of elements. 3.2.1 Set rules With set rules, you can customize the appearance of elements. They are written as a function call3.5.15 to an element function3.5.15/2 preceded by the set keyword (or #set in markup). Only optional parameters of that function can be provided to the set rule. Refer to each function's documentation to see which parameters are optional. In the example below, we use two set rules to change the font family3.7.12/2.1 and heading numbering3.6.10/5.4. #set heading(numbering: "I.") #set text( font: "New Computer Modern" ) = Introduction With set rules, you can style your document. I. Introduction With set rules, you can style your document. A top level set rule stays in effect until the end of the file. When nested inside of a code or content block, it is only in effect until the end of that block. With a block, you can thus restrict the effect of a rule to a particular segment of your document. Below, we use a content block to scope the list styling to one particular list. This list is affected: #[ #set list(marker: [--]) - Dash ] This one is not: - Bullet This list is affected: – Dash This one is not: • Bullet Sometimes, you'll want to apply a set rule conditionally. For this, you can use a set-if rule. #let task(body, critical: false) = { set text(red) if critical [- #body] } #task(critical: true)[Food today?] #task(critical: false)[Work deadline] • Food today? • Work deadline 3.2.2 Show rules With show rules, you can deeply customize the look of a type of element. The most basic form of show rule is a show-set rule. Such a rule is written as the show keyword followed by a selector3.5.25, a colon and then a set rule. The most basic form of selector is an element function3.5.15/2. This lets the set rule only apply to the selected element. In the example below, headings become dark blue while all other text stays black. #show heading: set text(navy) = This is navy-blue But this stays black. This is navy-blue But this stays black. 43 3.2 Styling With show-set rules you can mix and match properties from different functions to achieve many different effects. But they still limit you to what is predefined in Typst. For maximum flexibility, you can instead write a transformational show rule that defines how to format an element from scratch. To write such a show rule, replace the set rule after the colon with an arbitrary function3.5.15. This function receives the element in question and can return arbitrary content. The function is often defined inline as it => .. using the unnamed function syntax3.5.15/6. The function's parameter is typically named it by convention. The available fields3.3.6 on the element passed to the function match the parameters of the respective element function. Below, we define a show rule that formats headings for a fantasy encyclopedia. The show rule itself adds tilde characters around the title (these must be escaped with a backslash because otherwise they would indicate a non-breaking space), emphasizes the title with italics, and then displays the heading counter after the title. For this example, we also wanted center alignment and a different font. While we could've added these set rules into the existing show rule, we instead added them as separate show-set rules. This is good practice because now these rules can still be overridden by later show-set rules in the document, keeping styling composable. In contrast, set rules within a transformational show rule would not be overridable anymore. #set heading(numbering: "(I)") #show heading: set align(center) #show heading: set text(font: "Inria Serif") #show heading: it => block[ \~ #emph(it.body) #counter(heading).display() \~ ] = Dragon With a base health of 15, the dragon is the most powerful creature. = Manticore While less powerful than the dragon, the manticore gets extra style points. ~ Dragon (I) ~ With a base health of 15, the dragon is the most powerful creature. ~ Manticore (II) ~ While less powerful than the dragon, the manticore gets extra style points. Like set rules, show rules are in effect until the end of the current block or file. Instead of a function, the right-hand side of a show rule can also take a literal string or content block that should be directly substituted for the element. And apart from a function, the left-hand side of a show rule can also take a number of other selectors that define what to apply the transformation to: – Everything: show: rest => .. Transform everything after the show rule. This is useful to apply a more complex layout to your whole document without wrapping everything in a giant function call. – Text: show "Text": .. Style, transform or replace text. 44 3.2 Styling – Regex: show regex("\w+"): .. Select and transform text with a regular expression for even more flexibility. See the documentation of the regex type3.5.23 for details. – Function with fields: show heading.where(level: 1): .. Transform only elements that have the specified fields. For example, you might want to only change the style of level-1 headings. – Label: show : .. Select and transform elements that have the specified label. See the documentation of the label type3.5.17 for more details. #show "Project": smallcaps #show "badly": "great" We started Project in 2019 and are still working on it. Project is progressing badly. We started Project in 2019 and are still working on it. Project is progressing great. 45 3.3 Scripting Typst embeds a powerful scripting language. You can automate your documents and create more sophisti cated styles with code. Below is an overview over the scripting concepts. 3.3.1 Expressions In Typst, markup and code are fused into one. All but the most common elements are created with functions. To make this as convenient as possible, Typst provides compact syntax to embed a code expression into markup: An expression is introduced with a hash (#) and normal markup parsing resumes after the expression is finished. If a character would continue the expression but should be interpreted as text, the expression can forcibly be ended with a semicolon (;). You can escape a literal # or ; with a backslash3.1.6. #emph[Hello] \ #emoji.face \ #"hello".len() Hello 😀 5 The example above shows a few of the available expressions, including function calls3.5.15, field accesses3.3.6, and method calls3.3.7. More kinds of expressions are discussed in the remainder of this chapter. A few kinds of expressions are not compatible with the hash syntax (e.g. binary operator expressions). To embed these into markup, you can use parentheses, as in #(1 + 2). 3.3.2 Blocks To structure your code and embed markup into it, Typst provides two kinds of blocks: – Code block: { let x = 1; x + 2 } When writing code, you'll probably want to split up your computation into multiple statements, create some intermediate variables and so on. Code blocks let you write multiple expressions where one is expected. The individual expressions in a code block should be separated by line breaks or semicolons. The output values of the individual expressions in a code block are joined to determine the block's value. Expressions without useful output, like let bindings yield none, which can be joined with any value without effect. – Content block: [*Hey* there!] With content blocks, you can handle markup/content as a programmatic value, store it in variables and pass it to functions3.5.15. Content blocks are delimited by square brackets and can contain arbitrary markup. A content block results in a value of type content3.5.8. An arbitrary number of content blocks can be passed as trailing arguments to functions. That is, list([A], [B]) is equivalent to list[A][B]. Content and code blocks can be nested arbitrarily. In the example below, [hello ] is joined with the output of a + [ the ] + b yielding [hello from the *world*]. #{ let a = [from] let b = [*world*] [hello ] a + [ the ] + b } hello from the world 3.3.3 Bindings and Destructuring As already demonstrated above, variables can be defined with let bindings. The variable is assigned the value of the expression that follows the = sign. A valid variable name3.1.7 may contain -, but cannot start with -. The assignment of a value is optional, if no value is assigned, the variable will be initialized as none. The let keyword can also be used to create a custom named function3.5.15/4. Variables can be accessed for the rest of the containing block (or the rest of the file if there is no containing block). 46 3.3 Scripting #let name = "Typst" This is #name's documentation. It explains #name. #let my-add(x, y) = x + y Sum is #my-add(2, 3). This is Typst's documentation. It explains Typst. Sum is 5. Let bindings can also be used to destructure arrays3.5.2 and dictionaries3.5.11. In this case, the structure of the left-hand side of the assignment should mirror the array or dictionary: With bindings corresponding by position for arrays and by key name for dictionaries. The .. operator can be used once in the pattern to collect the remainder of the array's or the dictionary's items. #let (x, y) = (1, 2) The coordinates are #x, #y. #let (a, .., b) = (1, 2, 3, 4) The first element is #a. The last element is #b. #let books = ( Shakespeare: "Hamlet", Homer: "The Odyssey", Austen: "Persuasion", ) #let (Austen,) = books Austen wrote #Austen. #let (Homer: h) = books Homer wrote #h. #let (Homer, ..other) = books #for (author, title) in other [ #author wrote #title. ] The coordinates are 1, 2. The first element is 1. The last element is 4. Austen wrote Persuasion. Homer wrote The Odyssey. Shakespeare wrote Hamlet. Austen wrote Persuasion. You can use the underscore to discard elements in a destructuring pattern: #let (_, y, _) = (1, 2, 3) The y coordinate is #y. The y coordinate is 2. Destructuring also works in argument lists of functions … #let left = (2, 4, 5) #let right = (3, 2, 6) #left.zip(right).map( ((a,b)) => a + b ) (5, 6, 11) … and on the left-hand side of normal assignments. This can be useful to swap variables among other things. #{ let a = 1 let b = 2 (a, b) = (b, a) [a = #a, b = #b] } a = 2, b = 1 47 3.3 Scripting 3.3.4 Conditionals With a conditional, you can display or compute different things depending on whether some condition is fulfilled. Typst supports if, else if and else expressions. When the condition evaluates to true, the conditional yields the value resulting from the if's body. Otherwise, it yields the value resulting from the else's body. #if 1 < 2 [ This is shown ] else [ This is not. ] This is shown Each branch can have a code or content block as its body. – if condition {..} – if condition [..] – if condition [..] else {..} – if condition [..] else if condition {..} else [..] 3.3.5 Loops With loops, you can repeat content or compute something iteratively. Typst supports two types of loops: for and while loops. The former iterate over a specified collection whereas the latter iterate as long as a condition stays fulfilled. Just like blocks, loops join the results from each iteration into one value. In the example below, the three sentences created by the for loop join together into a single content value and the length-1 arrays in the while loop join together into one larger array. #for c in "ABC" [ #c is a letter. ] #let n = 2 #while n < 10 { n = (n * 2) - 1 (n,) } A is a letter. B is a letter. C is a letter. (3, 5, 9, 17) For loops can iterate over a variety of collections: – for value in array {..} Iterates over the items in the array3.5.2. The destructuring syntax described in Let binding3.3.3 can also be used here. – for pair in dict {..} Iterates over the key-value pairs of the dictionary3.5.11. The pairs can also be destructured by using for (key, value) in dict {..}. It is more efficient than for pair in dict.pairs() {..} because it doesn't create a temporary array of all key-value pairs. – for letter in "abc" {..} Iterates over the characters of the string3.5.27. Technically, it iterates over the grapheme clusters of the string. Most of the time, a grapheme cluster is just a single codepoint. However, a grapheme cluster could contain multiple codepoints, like a flag emoji. – for byte in bytes("😀") {..} Iterates over the bytes3.5.6, which can be converted from a string3.5.27 or read3.13.5 from a file without encoding. Each byte value is an integer3.5.16 between 0 and 255. To control the execution of the loop, Typst provides the break and continue statements. The former performs an early exit from the loop while the latter skips ahead to the next iteration of the loop. 48 3.3 Scripting #for letter in "abc nope" { if letter == " " { break } letter } abc The body of a loop can be a code or content block: – for .. in collection {..} – for .. in collection [..] – while condition {..} – while condition [..] 3.3.6 Fields You can use dot notation to access fields on a value. For values of type content3.5.8, you can also use the fields3.5.8/3.4 function to list the fields. The value in question can be either: – a dictionary3.5.11 that has the specified key, – a symbol3.5.28 that has the specified modifier, – a module3.5.18 containing the specified definition, – content3.5.8 consisting of an element that has the specified field. The available fields match the arguments of the element function3.5.15/2 that were given when the element was constructed. #let it = [= Heading] #it.body \ #it.depth \ #it.fields() #let dict = (greet: "Hello") #dict.greet \ #emoji.face Heading 1 (depth: 1, body: [Heading]) Hello 😀 3.3.7 Methods A method call is a convenient way to call a function that is scoped to a value's type3.5.31. For example, we can call the str.len3.5.27/4.1 function in the following two equivalent ways: #str.len("abc") is the same as #"abc".len() 3 is the same as 3 The structure of a method call is value.method(..args) and its equivalent full function call is type(value).method(value, ..args). The documentation of each type lists its scoped functions. You cannot currently define your own methods. #let values = (1, 2, 3, 4) #values.pop() \ #values.len() \ #("a, b, c" .split(", ") .join[ --- ]) 4 3 a — b — c 3 is the same as 3 49 3.3 Scripting #"abc".len() is the same as #str.len("abc") There are a few special functions that modify the value they are called on (e.g. array.push3.5.2/3.5). These functions must be called in method form. In some cases, when the method is only called for its side effect, its return value should be ignored (and not participate in joining). The canonical way to discard a value is with a let binding: let _ = array.remove(1). 3.3.8 Modules You can split up your Typst projects into multiple files called modules. A module can refer to the content and definitions of another module in multiple ways: – Including: include "bar.typ" Evaluates the file at the path3.5.21 bar.typ and returns the resulting content3.5.8. – Import: import "bar.typ" Evaluates the file at the path3.5.21 bar.typ and inserts the resulting module3.5.18 into the current scope as bar (filename without extension). You can use the as keyword to rename the imported module: import "bar.typ" as baz. You can import nested items using dot notation: import "bar.typ": baz.a. – Import items: import "bar.typ": a, b Evaluates the file at the path3.5.21 bar.typ, extracts the values of the variables a and b (that need to be defined in bar.typ, e.g. through let bindings) and defines them in the current file. Replacing a, b with * loads all variables defined in a module. You can use the as keyword to rename the individual items: import "bar.typ": a as one, b as two Instead of a string or path3.5.21, you can also use a module value3.5.18, as shown in the following example: #import emoji: face #face.grin 😀 3.3.9 Packages To reuse building blocks across projects, you can also create and import Typst packages. A package import is specified as a triple of a namespace, a name, and a version. #import "@preview/example:0.1.0": add #add(2, 7) 9 The preview namespace contains packages shared by the community. You can find all available community packages on Typst Universe[A]. If you are using Typst locally, you can also create your own system-local packages. For more details on this, see the package repository[B]. 3.3.10 Operators The following table lists all available unary and binary operators with effect, arity (unary, binary) and precedence level (higher binds stronger). Some operations, such as modulus3.5.7/1.39, do not have a special syntax and can be achieved using functions from the calc3.5.7 module. Operator Effect Arity Precedence - Negation Unary 7 [A]https://typst.app/universe [B]https://github.com/typst/packages 50 https://typst.app/universe https://github.com/typst/packages https://typst.app/universe https://github.com/typst/packages 3.3 Scripting Operator Effect Arity Precedence + No effect (exists for symmetry) Unary 7 * Multiplication Binary 6 / Division Binary 6 + Addition Binary 5 - Subtraction Binary 5 == Check equality Binary 4 != Check inequality Binary 4 < Check less-than Binary 4 <= Check less-than or equal Binary 4 > Check greater-than Binary 4 >= Check greater-than or equal Binary 4 in Check if in collection Binary 4 not in Check if not in collection Binary 4 not Logical "not" Unary 3 and Short-circuiting logical "and" Binary 3 or Short-circuiting logical "or" Binary 2 = Assignment Binary 1 += Add-Assignment Binary 1 -= Subtraction-Assignment Binary 1 *= Multiplication-Assignment Binary 1 /= Division-Assignment Binary 1 51 3.4 Context Sometimes, we want to create content that reacts to its location in the document. This could be a localized phrase that depends on the configured text language or something as simple as a heading number which prints the right value based on how many headings came before it. However, Typst code isn't directly aware of its location in the document. Some code at the beginning of the source text could yield content that ends up at the back of the document. To produce content that is reactive to its surroundings, we must thus specifically instruct Typst: We do this with the context keyword, which precedes an expression and ensures that it is computed with knowledge of its environment. In return, the context expression itself ends up opaque. We cannot directly access whatever results from it in our code, precisely because it is contextual: There is no one correct result, there may be multiple results in different places of the document. For this reason, everything that depends on the contextual data must happen inside of the context expression. Aside from explicit context expressions, context is also established implicitly in some places that are also aware of their location in the document: Show rules3.2.2 provide context[A] and numberings in the outline, for instance, also provide the proper context to resolve counters. 3.4.1 Style context With set rules, we can adjust style properties for parts or the whole of our document. We cannot access these without a known context, as they may change throughout the course of the document. When context is available, we can retrieve them simply by accessing them as fields on the respective element function. #set text(lang: "de") #context text.lang de As explained above, a context expression is reactive to the different environments it is placed into. In the example below, we create a single context expression, store it in the value variable and use it multiple times. Each use properly reacts to the current surroundings. #let value = context text.lang #value #set text(lang: "de") #value #set text(lang: "fr") #value en de fr Crucially, upon creation, value becomes opaque content3.5.8 that we cannot peek into. It can only be resolved when placed somewhere because only then the context is known. The body of a context expression may be evaluated zero, one, or multiple times, depending on how many different places it is put into. 3.4.2 Location context We've already seen that context gives us access to set rule values. But it can do more: It also lets us know where in the document we currently are, relative to other elements, and absolutely on the pages. We can use this information to create very flexible interactions between different document parts. This underpins features like heading numbering, the table of contents, or page headers dependent on section headings. Some functions like counter.get3.12.1/10.1 implicitly access the current location. In the example below, we want to retrieve the value of the heading counter. Since it changes throughout the document, we need to first enter a context expression. Then, we use get to retrieve the counter's current value. This function accesses the current location from the context to resolve the counter value. Counters have multiple levels and get returns an array with the resolved numbers. Thus, we get the following result: [A]Currently, all show rules provide style context, but only show rules on locatable elements provide a location context. 52 3.4 Context #set heading(numbering: "1.") = Introduction #lorem(5) #context counter(heading).get() = Background #lorem(5) #context counter(heading).get() 1. Introduction Lorem ipsum dolor sit amet. (1,) 2. Background Lorem ipsum dolor sit amet. (2,) For more flexibility, we can also use the here3.12.2 function to directly extract the current location3.12.4 from the context. The example below demonstrates this: – We first have counter(heading).get(), which resolves to (2,) as before. – We then use the more powerful counter.at3.12.1/10.3 with here3.12.2, which in combination is equivalent to get, and thus get (2,). – Finally, we use at with a label3.5.17 to retrieve the value of the counter at a different location in the document, in our case that of the introduction heading. This yields (1,). Typst's context system gives us time travel abilities and lets us retrieve the values of any counters and states at any location in the document. #set heading(numbering: "1.") = Introduction #lorem(5) = Background #lorem(5) #context [ #counter(heading).get() \ #counter(heading).at(here()) \ #counter(heading).at() ] 1. Introduction Lorem ipsum dolor sit amet. 2. Background Lorem ipsum dolor sit amet. (2,) (2,) (1,) As mentioned before, we can also use context to get the physical position of elements on the pages. We do this with the locate3.12.3 function, which works similarly to counter.at: It takes a location or other selector3.5.25 that resolves to a unique element (could also be a label) and returns the position on the pages for that element. Background is at: \ #context locate().position() = Introduction #lorem(5) #pagebreak() = Background #lorem(5) Background is at: (page: 2, x: 15pt, y: 15pt) Introduction Lorem ipsum dolor sit amet. Background Lorem ipsum dolor sit amet. There are other functions that make use of the location context, most prominently query3.12.6. Take a look at the introspection3.12 category for more details on those. 53 3.4 Context 3.4.3 Nested contexts Context is also accessible from within function calls nested in context blocks. In the example below, foo itself becomes a contextual function, just like to-absolute3.10.13/3.5 is. #let foo() = 1em.to-absolute() #context { foo() == text.size } true Context blocks can be nested. Contextual code will then always access the innermost context. The example below demonstrates this: The first text.lang will access the outer context block's styles and as such, it will not see the effect of set text(lang: "fr"). The nested context block around the second text.lang, however, starts after the set rule and will thus show its effect. #set text(lang: "de") #context [ #set text(lang: "fr") #text.lang \ #context text.lang ] de fr You might wonder why Typst ignores the French set rule when computing the first text.lang in the example above. The reason is that, in the general case, Typst cannot know all the styles that will apply as set rules can be applied to content after it has been constructed. Below, text.lang is already computed when the template function is applied. As such, it cannot possibly be aware of the language change to French in the template. #let template(body) = { set text(lang: "fr") upper(body) } #set text(lang: "de") #context [ #show: template #text.lang \ #context text.lang ] DE FR The second text.lang, however, does react to the language change because evaluation of its surrounding context block is deferred until the styles for it are known. This illustrates the importance of picking the right insertion point for a context to get access to precisely the right styles. The same also holds true for the location context. Below, the first c.display() call will access the outer context block and will thus not see the effect of c.update(2) while the second c.display() accesses the inner context and will thus see it. #let c = counter("mycounter") #c.update(1) #context [ #c.update(2) #c.display() \ #context c.display() ] 1 2 3.4.4 Compiler iterations To resolve contextual interactions, the Typst compiler processes your document multiple times. For instance, to resolve a locate call, Typst first provides a placeholder position, layouts your document and 54 3.4 Context then recompiles with the known position from the finished layout. The same approach is taken to resolve counters, states, and queries. In certain cases, Typst may even need more than two iterations to resolve everything. While that's sometimes a necessity, it may also be a sign of misuse of contextual functions (e.g. of state3.12.7/4). If Typst cannot resolve everything within five attempts, it will stop and output the warning "document did not converge within five attempts." A very careful reader might have noticed that not all of the functions presented above actu ally make use of the current location. While counter(heading).get() definitely depends on it, counter(heading).at(), for instance, does not. However, it still requires context. While its value is always the same within one compilation iteration, it may change over the course of multiple compiler iterations. If one could call it directly at the top level of a module, the whole module and its exports could change over the course of multiple compiler iterations, which would not be desirable. 55 3.5 Foundations Foundational types and functions. Here, you'll find documentation for basic data types like integers3.5.16 and strings3.5.27 as well as details about core computational functions. Definitions 3.5.1 Arguments Captured arguments to a function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠57 3.5.2 Array A sequence of values. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠60 3.5.3 Assert Ensures that a condition is fulfilled. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠70 3.5.4 Auto A value that indicates a smart default. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠72 3.5.5 Boolean A type with two states. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠73 3.5.6 Bytes A sequence of bytes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠74 3.5.7 Calculation Module for calculations and processing of numeric values. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠76 3.5.8 Content A piece of document content. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠91 3.5.9 Datetime Represents a date, a time, or a combination of both. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠93 3.5.10 Decimal A fixed-point decimal number type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠98 3.5.11 Dictionary A map from string keys to values. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠100 3.5.12 Duration Represents a positive or negative span of time. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠103 3.5.13 Evaluate Evaluates a string as Typst code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠105 3.5.14 Float A floating-point number. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠106 3.5.15 Function A mapping from argument values to a return value. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠109 3.5.16 Integer An integer: a positive whole number, a negative whole number, or zero. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠112 3.5.17 Label A label for an element. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠117 3.5.18 Module A collection of variables and functions that are commonly related to a single theme. . . . . . . . . . . . . . . . . ⁠118 3.5.19 None A value that indicates the absence of any other value. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠119 3.5.20 Panic Fails with an error. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠120 3.5.21 Path A file system path. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠121 3.5.22 Plugin Loads a WebAssembly module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠123 3.5.23 Regex A regular expression. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠126 3.5.24 Representation Returns the string representation of a value. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠127 3.5.25 Selector A filter for selecting elements within the document. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠128 3.5.26 Standard Library A module that contains all globally accessible items. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠131 3.5.27 String A sequence of Unicode codepoints. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠132 3.5.28 Symbol A Unicode symbol. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠139 3.5.29 System Module for system interactions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠140 3.5.30 Target Returns the current export target. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠141 3.5.31 Type Describes a kind of value. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠142 3.5.32 Version A version with an arbitrary number of components. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ⁠143 56 3.5.1 arguments Captured arguments to a function. Arguments are either positional or named, and can be accessed through the pos3.5.1/4.3, named3.5.1/4.4, and at3.5.1/4.2 methods. Additionally, named arguments can be accessed with field syntax3.5.1/4.2 similar to dictionaries3.5.11. /1 Argument Sinks Like built-in functions, custom functions can also take a variable number of arguments. You can specify an argument sink which collects all excess arguments as ..sink. The resulting sink value is of the arguments type. It exposes methods to access the positional and named arguments. #let format(title, ..authors) = { let by = authors .pos() .join(", ", last: " and ") [*#title* \ _Written by #by;_] } #format("ArtosFlow", "Jane", "Joe") ArtosFlow Written by Jane and Joe /2 Spreading Inversely to an argument sink, you can spread arguments, arrays and dictionaries into a function call with the ..spread operator: #let array = (2, 3, 5) #calc.min(..array) #let dict = (fill: blue) #text(..dict)[Hello] 2 Hello /3 Constructor Construct spreadable arguments in place. This function behaves like let args(..sink) = sink. #let args = arguments(stroke: red, inset: 1em, [Body]) #box(..args) Body arguments(.. any ) → arguments /3.1 arguments any Required Positional Variadic The arguments to construct. /4 Definitions /4.1 len The number of arguments, positional or named. 57 3.5.1 arguments self.len() → int /4.2 at Returns the positional argument at the specified index, or the named argument with the specified name. If the key is an integer3.5.16, this is equivalent to first calling pos3.5.1/4.3 and then array.at3.5.2/3.4. If it is a string3.5.27, this is equivalent to first calling named3.5.1/4.4 and then dictionary.at3.5.11/3.2. Named arguments can also be accessed with field syntax (e.g. arguments(key: 42).key) if no default is needed. Unlike dictionaries3.5.11, fields on arguments cannot be modified. self.at( int str , default: any , ) → any /4.2.1 key int or str Required Positional The index or name of the argument to get. /4.2.2 default any A default value to return if the key is invalid. /4.3 pos Returns the captured positional arguments as an array. self.pos() → array /4.4 named Returns the captured named arguments as a dictionary. self.named() → dictionary /4.5 filter Produces a new arguments with only the arguments for which the value passes the test. #{ arguments(-1, a: 0, b: 1, 2) .filter(v => v > 0) } arguments(b: 1, 2) self.filter( function ) → arguments /4.5.1 test function Required Positional The function to apply to each value. Must return a boolean. /4.6 map Produces a new arguments by transforming each argument value with the passed function. #{ arguments(0, a: 1, 2) .map(v => v + 1) } arguments(1, a: 2, 3) 58 3.5.1 arguments self.map( function ) → arguments /4.6.1 mapper function Required Positional The function to apply to each value. 59 3.5.2 array A sequence of values. You can construct an array by enclosing a comma-separated sequence of values in parentheses. The values do not have to be of the same type. You can access and update array items with the .at() method. Indices are zero-based and negative indices wrap around to the end of the array. You can iterate over an array using a for loop3.3.5. Arrays can be added together with the + operator, joined together3.3.2 and multiplied with integers. Note: An array of length one needs a trailing comma, as in (1,). This is to disambiguate from a simple parenthesized expressions like (1 + 2) * 3. An empty array is written as (). /1 Example #let values = (1, 7, 4, -3, 2) #values.at(0) \ #(values.at(0) = 3) #values.at(-1) \ #values.find(calc.even) \ #values.filter(calc.odd) \ #values.map(calc.abs) \ #values.rev() \ #(1, (2, 3)).flatten() \ #(("A", "B", "C") .join(", ", last: " and ")) 1 2 4 (3, 7, -3) (3, 7, 4, 3, 2) (2, -3, 4, 7, 3) (1, 2, 3) A, B and C /2 Constructor Converts a value to an array. Note that this function is only intended for conversion of a collection-like value to an array, not for creation of an array from individual items. Use the array syntax (1, 2, 3) (or (1,) for a single-element array) instead. #let hi = "Hello 😃" #array(bytes(hi)) (72, 101, 108, 108, 111, 32, 240, 159, 152, 131) array( bytes array version ) → array /2.1 value bytes or array or version Required Positional The value that should be converted to an array. /3 Definitions /3.1 len The number of values in the array. self.len() → int /3.2 first Returns the first item in the array. May be used on the left-hand side an assignment. Returns the default value if the array is empty or fails with an error is no default value was specified. 60 3.5.2 array self.first(default: any ) → any /3.2.1 default any A default value to return if the array is empty. /3.3 last Returns the last item in the array. May be used on the left-hand side of an assignment. Returns the default value if the array is empty or fails with an error is no default value was specified. self.last(default: any ) → any /3.3.1 default any A default value to return if the array is empty. /3.4 at Returns the item at the specified index in the array. May be used on the left-hand side of an assignment. Returns the default value if the index is out of bounds or fails with an error if no default value was specified. self.at( int , default: any , ) → any /3.4.1 index int Required Positional The index at which to retrieve the item. If negative, indexes from the back. /3.4.2 default any A default value to return if the index is out of bounds. /3.5 push Adds a value to the end of the array. self.push( any ) → none /3.5.1 value any Required Positional The value to insert at the end of the array. /3.6 pop Removes the last item from the array and returns it. Fails with an error if the array is empty. self.pop() → any /3.7 insert Inserts a value into the array at the specified index, shifting all subsequent elements to the right. Fails with an error if the index is out of bounds. To replace an element of an array, use at3.5.2/3.4. self.insert( int , any , ) → none 61 3.5.2 array /3.7.1 index int Required Positional The index at which to insert the item. If negative, indexes from the back. /3.7.2 value any Required Positional The value to insert into the array. /3.8 remove Removes the value at the specified index from the array and return it. self.remove( int , default: any , ) → any /3.8.1 index int Required Positional The index at which to remove the item. If negative, indexes from the back. /3.8.2 default any A default value to return if the index is out of bounds. /3.9 slice Extracts a subslice of the array. Fails with an error if the start or end index is out of bounds. self.slice( int , none int , count: int , ) → array /3.9.1 start int Required Positional The start index (inclusive). If negative, indexes from the back. /3.9.2 end none or int Positional Default: none The end index (exclusive). If omitted, the whole slice until the end of the array is extracted. If negative, indexes from the back. /3.9.3 count int The number of items to extract. This is equivalent to passing start + count as the end position. Mutually exclusive with end. /3.10 contains Whether the array contains the specified value. This method also has dedicated syntax: You can write 2 in (1, 2, 3) instead of (1, 2, 3).contains(2). self.contains( any ) → bool /3.10.1 value any Required Positional The value to search for. /3.11 find Searches for an item for which the given function returns true and returns the first match or none if there is no match. self.find( function ) → none any 62 3.5.2 array /3.11.1 searcher function Required Positional The function to apply to each item. Must return a boolean. /3.12 position Searches for an item for which the given function returns true and returns the index of the first match or none if there is no match. self.position( function ) → none int /3.12.1 searcher function Required Positional The function to apply to each item. Must return a boolean. #let values = (1, 7, 4, 6, 9) #values.position(x => calc.even(x)) \ // Or equivalently: #values.position(calc.even) 2 2 /3.13 range Create an array consisting of a sequence of numbers. If you pass just one positional parameter, it is interpreted as the end of the range. If you pass two, they describe the start and end of the range. This function is available both in the array function's scope and globally. #range(5) \ #range(2, 5) \ #range(20, step: 4) \ #range(21, step: 4) \ #range(5, 2, step: -1) (0, 1, 2, 3, 4) (2, 3, 4) (0, 4, 8, 12, 16) (0, 4, 8, 12, 16, 20) (5, 4, 3) array.range( int , int , inclusive: bool , step: int , ) → array /3.13.1 start int Positional Default: 0 The start of the range (inclusive). /3.13.2 end int Required Positional The end of the range. /3.13.3 inclusive bool Default: false Whether end is inclusive. #range(0, inclusive: true) \ #range(7, 10, inclusive: true) \ #range(-8, -4, inclusive: true) \ #range(-6, step: -2, inclusive: true) (0,) (7, 8, 9, 10) (-8, -7, -6, -5, -4) (0, -2, -4, -6) 63 3.5.2 array /3.13.4 step int Default: 1 The distance between the generated numbers. /3.14 filter Produces a new array with only the items from the original one for which the given function returns true. self.filter( function ) → array /3.14.1 test function Required Positional The function to apply to each item. Must return a boolean. /3.15 map Produces a new array in which all items from the original one were transformed with the given function. self.map( function ) → array /3.15.1 mapper function Required Positional The function to apply to each item. /3.16 enumerate Returns a new array with the values alongside their indices. The returned array consists of (index, value) pairs in the form of length-2 arrays. These can be destructured3.3.3 with a let binding or for loop. #for (i, value) in ("A", "B", "C").enumerate() { [#i: #value \ ] } #("A", "B", "C").enumerate(start: 1) 0: A 1: B 2: C ((1, "A"), (2, "B"), (3, "C")) self.enumerate(start: int ) → array /3.16.1 start int Default: 0 The index returned for the first pair of the returned list. /3.17 zip Zips the array with other arrays. Returns an array of arrays, where the ith inner array contains all the ith elements from each original array. If the arrays to be zipped have different lengths, they are zipped up to the last element of the shortest array and all remaining elements are ignored. This function is variadic, meaning that you can zip multiple arrays together at once: (1, 2).zip(("A", "B"), (10, 20)) yields ((1, "A", 10), (2, "B", 20)). self.zip( exact: bool , 64 3.5.2 array .. array , ) → array /3.17.1 exact bool Default: false Whether all arrays have to have the same length. For example, (1, 2).zip((1, 2, 3), exact: true) produces an error. /3.17.2 others array Required Positional Variadic The arrays to zip with. /3.18 fold Folds all items into a single value using an accumulator function. #let array = (1, 2, 3, 4) #array.fold(0, (acc, x) => acc + x) 10 self.fold( any , function , ) → any /3.18.1 init any Required Positional The initial value to start with. /3.18.2 folder function Required Positional The folding function. Must have two parameters: One for the accumulated value and one for an item. /3.19 sum Sums all items (works for all types that can be added). self.sum(default: any ) → any /3.19.1 default any What to return if the array is empty. Must be set if the array can be empty. /3.20 product Calculates the product of all items (works for all types that can be multiplied). self.product(default: any ) → any /3.20.1 default any What to return if the array is empty. Must be set if the array can be empty. /3.21 any Whether the given function returns true for any item in the array. self.any( function ) → bool /3.21.1 test function Required Positional The function to apply to each item. Must return a boolean. /3.22 all Whether the given function returns true for all items in the array. 65 3.5.2 array self.all( function ) → bool /3.22.1 test function Required Positional The function to apply to each item. Must return a boolean. /3.23 flatten Combine all nested arrays into a single flat one. self.flatten() → array /3.24 rev Return a new array with the same items, but in reverse order. self.rev() → array /3.25 split Split the array at occurrences of the specified value. #(1, 1, 2, 3, 2, 4, 5).split(2) ((1, 1), (3,), (4, 5)) self.split( any ) → array /3.25.1 at any Required Positional The value to split at. /3.26 join Combine all items in the array into one. self.join( none any , last: any , default: none any , ) → any /3.26.1 separator none or any Positional Default: none A value to insert between each item of the array. /3.26.2 last any An alternative separator between the last two items. /3.26.3 default none or any Default: none What to return if the array is empty. /3.27 intersperse Returns an array with a copy of the separator value placed between adjacent elements. #("A", "B", "C").intersperse("-") ("A", "-", "B", "-", "C") 66 3.5.2 array self.intersperse( any ) → array /3.27.1 separator any Required Positional The value that will be placed between each adjacent element. /3.28 chunks Splits an array into non-overlapping chunks, starting at the beginning, ending with a single remainder chunk. All chunks but the last have chunk-size elements. If exact is set to true, the remainder is dropped if it contains less than chunk-size elements. #let array = (1, 2, 3, 4, 5, 6, 7, 8) #array.chunks(3) \ #array.chunks(3, exact: true) ((1, 2, 3), (4, 5, 6), (7, 8)) ((1, 2, 3), (4, 5, 6)) self.chunks( int , exact: bool , ) → array /3.28.1 chunk-size int Required Positional How many elements each chunk may at most contain. /3.28.2 exact bool Default: false Whether to discard the remainder if its size is less than chunk-size. /3.29 windows Returns sliding windows of window-size elements over an array. If the array length is less than window-size, this will return an empty array. #let array = (1, 2, 3, 4, 5, 6, 7, 8) #array.windows(5) ( (1, 2, 3, 4, 5), (2, 3, 4, 5, 6), (3, 4, 5, 6, 7), (4, 5, 6, 7, 8), ) self.windows( int ) → array /3.29.1 window-size int Required Positional How many elements each window will contain. /3.30 sorted Return a sorted version of this array, optionally by a given key function. The sorting algorithm used is stable. Returns an error if a pair of values selected for comparison could not be compared, or if the key or comparison function (if given) yield an error. To sort according to multiple criteria at once, e.g. in case of equality between some criteria, the key function can return an array. The results are in lexicographic order. 67 3.5.2 array #let array = ( (a: 2, b: 4), (a: 1, b: 5), (a: 2, b: 3), ) #array.sorted(key: it => (it.a, it.b)) ((a: 1, b: 5), (a: 2, b: 3), (a: 2, b: 4)) self.sorted( key: function , by: function , ) → array /3.30.1 key function If given, applies this function to each element in the array to determine the keys to sort by. /3.30.2 by function If given, uses this function to compare every two elements in the array. The function will receive two elements in the array for comparison, and should return a boolean indicating their order: true indicates that the elements are in order, while false indicates that they should be swapped. To keep the sort stable, if the two elements are equal, the function should return true. If this function does not order the elements properly (e.g., by returning false for both (x, y) and (y, x), or for (x, x)), the resulting array will be in unspecified order. When used together with key, by will be passed the keys instead of the elements. #( "sorted", "by", "decreasing", "length", ).sorted( key: s => s.len(), by: (l, r) => l >= r, ) ("decreasing", "sorted", "length", "by") /3.31 dedup Deduplicates all items in the array. Returns a new array with all duplicate items removed. Only the first element of each duplicate is kept. #(3, 3, 1, 2, 3).dedup() (3, 1, 2) self.dedup(key: function ) → array /3.31.1 key function If given, applies this function to each element in the array to determine the keys to deduplicate by. #("apple", "banana", " apple ").dedup(key: s => s.trim()) ("apple", "banana") 68 3.5.2 array /3.32 to-dict Converts an array of pairs into a dictionary. The first value of each pair is the key, the second the value. If the same key occurs multiple times, the last value is selected. #( ("apples", 2), ("peaches", 3), ("apples", 5), ).to-dict() (apples: 5, peaches: 3) self.to-dict() → dictionary /3.33 reduce Reduces the elements to a single one, by repeatedly applying a reducing operation. If the array is empty, returns none, otherwise, returns the result of the reduction. The reducing function is a closure with two arguments: an "accumulator", and an element. For arrays with at least one element, this is the same as array.fold3.5.2/3.18 with the first element of the array as the initial accumulator value, folding every subsequent element into it. #let array = (2, 1, 4, 3) #array.reduce((acc, x) => calc.max(acc, x)) 4 self.reduce( function ) → any /3.33.1 reducer function Required Positional The reducing function. Must have two parameters: One for the accumulated value and one for an item. 69 3.5.3 assert Ensures that a condition is fulfilled. Fails with an error if the condition is not fulfilled. Does not produce any output in the document. If you wish to test equality between two values, see assert.eq3.5.3/3.1 and assert.ne3.5.3/3.2. /1 Example #assert(1 < 2, message: "math broke") /2 Parameters assert( bool , message: str , ) → none /2.1 condition bool Required Positional The condition that must be true for the assertion to pass. /2.2 message str The error message when the assertion fails. /3 Definitions /3.1 eq Ensures that two values are equal. Fails with an error if the first value is not equal to the second. Does not produce any output in the document. #assert.eq(10, 10) assert.eq( any , any , message: str , ) → none /3.1.1 left any Required Positional The first value to compare. /3.1.2 right any Required Positional The second value to compare. /3.1.3 message str An optional message to display on error instead of the representations of the compared values. /3.2 ne Ensures that two values are not equal. Fails with an error if the first value is equal to the second. Does not produce any output in the document. #assert.ne(3, 4) 70 3.5.3 assert assert.ne( any , any , message: str , ) → none /3.2.1 left any Required Positional The first value to compare. /3.2.2 right any Required Positional The second value to compare. /3.2.3 message str An optional message to display on error instead of the representations of the compared values. 71 3.5.4 auto A value that indicates a smart default. The auto type has exactly one value: auto. Parameters that support the auto value have some smart default or contextual behaviour. A good example is the text direction3.7.12/2.19 parameter. Setting it to auto lets Typst automatically determine the direction from the text language3.7.12/2.16. 72 3.5.5 bool A type with two states. The boolean type has two values: true and false. It denotes whether something is active or enabled. /1 Example #false \ #true \ #(1 < 2) false true true 73 3.5.6 bytes A sequence of bytes. This is conceptually similar to an array of integers3.5.16 between 0 and 255, but represented much more efficiently. You can iterate over it using a for loop3.3.5. You can convert – a string3.5.27 or an array3.5.2 of integers to bytes with the bytes3.5.6 constructor – bytes to a string with the str3.5.27 constructor, with UTF-8 encoding – bytes to an array of integers with the array3.5.2 constructor When reading3.13.5 data from a file, you can decide whether to load it as a string or as raw bytes. #bytes((123, 160, 22, 0)) \ #bytes("Hello 😃") #let data = read( "rhino.png", encoding: none, ) // Magic bytes. #array(data.slice(0, 4)) \ #str(data.slice(1, 4)) bytes(4) bytes(10) (137, 80, 78, 71) PNG /1 Constructor Converts a value to bytes. – Strings are encoded in UTF-8. – Arrays of integers between 0 and 255 are converted directly. The dedicated byte representation is much more efficient than the array representation and thus typically used for large byte buffers (e.g. image data). #bytes("Hello 😃") \ #bytes((123, 160, 22, 0)) bytes(10) bytes(4) bytes( str bytes array ) → bytes /1.1 value str or bytes or array Required Positional The value that should be converted to bytes. /2 Definitions /2.1 len The length in bytes. self.len() → int /2.2 at Returns the byte at the specified index. Returns the default value if the index is out of bounds or fails with an error if no default value was specified. self.at( int , 74 3.5.6 bytes default: any , ) → any /2.2.1 index int Required Positional The index at which to retrieve the byte. /2.2.2 default any A default value to return if the index is out of bounds. /2.3 slice Extracts a subslice of the bytes. Fails with an error if the start or end index is out of bounds. self.slice( int , none int , count: int , ) → bytes /2.3.1 start int Required Positional The start index (inclusive). /2.3.2 end none or int Positional Default: none The end index (exclusive). If omitted, the whole slice until the end is extracted. /2.3.3 count int The number of items to extract. This is equivalent to passing start + count as the end position. Mutually exclusive with end. 75 3.5.7 Calculation Module for calculations and processing of numeric values. These definitions are part of the calc module and not imported by default. In addition to the functions listed below, the calc module also defines the constants pi, tau, e, and inf. /1 Functions /1.1 abs Calculates the absolute value of a numeric value. #calc.abs(-5) \ #calc.abs(5pt - 2cm) \ #calc.abs(2fr) \ #calc.abs(decimal("-342.440")) 5 51.69pt 2fr 342.440 calc.abs( int float length angle ratio fraction decimal ) → any /1.1.1 value int or float or length or angle or ratio or fraction or decimal Required Positional The value whose absolute value to calculate. /1.2 pow Raises a value to some exponent. #calc.pow(2, 3) \ #calc.pow(decimal("2.5"), 2) 8 6.25 calc.pow( int float decimal , int float , ) → int float decimal /1.2.1 base int or float or decimal Required Positional The base of the power. If this is a decimal3.5.10, the exponent can only be an integer3.5.16. /1.2.2 exponent int or float Required Positional The exponent of the power. /1.3 exp Raises a value to some exponent of 𝑒. #calc.exp(1) 2.7182818284590455 calc.exp( int float ) → float /1.3.1 exponent int or float Required Positional The exponent of the power. 76 3.5.7 Calculation /1.4 sqrt Calculates the square root of a number. #calc.sqrt(16) \ #calc.sqrt(2.5) 4 1.5811388300841898 calc.sqrt( int float ) → float /1.4.1 value int or float Required Positional The number whose square root to calculate. Must be non-negative. /1.5 root Calculates the real 𝑛th root of a number. If the number is negative, then 𝑛 must be odd. #calc.root(16.0, 4) \ #calc.root(27.0, 3) 2 3 calc.root( float , int , ) → float /1.5.1 radicand float Required Positional The expression to take the root of. /1.5.2 index int Required Positional The value of 𝑛. /1.6 sin Calculates the sine of an angle. When called with an integer or a float, they will be interpreted as radians. #calc.sin(1.5) \ #calc.sin(90deg) 0.9974949866040544 1 calc.sin( int float angle ) → float /1.6.1 angle int or float or angle Required Positional The angle whose sine to calculate. /1.7 cos Calculates the cosine of an angle. When called with an integer or a float, they will be interpreted as radians. 77 3.5.7 Calculation #calc.cos(1.5) \ #calc.cos(90deg) 0.0707372016677029 0.00000000000000006123233995736766 calc.cos( int float angle ) → float /1.7.1 angle int or float or angle Required Positional The angle whose cosine to calculate. /1.8 tan Calculates the tangent of an angle. When called with an integer or a float, they will be interpreted as radians. #calc.tan(1.5) \ #calc.tan(90deg) 14.101419947171719 16331239353195370 calc.tan( int float angle ) → float /1.8.1 angle int or float or angle Required Positional The angle whose tangent to calculate. /1.9 asin Calculates the arcsine of a number. #calc.asin(0) \ #calc.asin(1) 0deg 90deg calc.asin( int float ) → angle /1.9.1 value int or float Required Positional The number whose arcsine to calculate. Must be between −1 and 1. /1.10 acos Calculates the arccosine of a number. #calc.acos(0) \ #calc.acos(1) 90deg 0deg calc.acos( int float ) → angle /1.10.1 value int or float Required Positional The number whose arccosine to calculate. Must be between −1 and 1. /1.11 atan Calculates the arctangent of a number. 78 3.5.7 Calculation #calc.atan(0) \ #calc.atan(1) 0deg 45deg calc.atan( int float ) → angle /1.11.1 value int or float Required Positional The number whose arctangent to calculate. /1.12 atan2 Calculates the four-quadrant arctangent of a coordinate. The four-quadrant arctangent of (𝑥, 𝑦) is defined as the argument of the complex number 𝑥 + 𝑖𝑦. Returns an angle3.10.3 between -180deg and 180deg. Note that this function accepts (𝑥, 𝑦), not (𝑦, 𝑥). #calc.atan2(1, 1) \ #calc.atan2(-2, -3) 45deg -123.69deg calc.atan2( int float , int float , ) → angle /1.12.1 x int or float Required Positional The 𝑥 coordinate. /1.12.2 y int or float Required Positional The 𝑦 coordinate. /1.13 sinh Calculates the hyperbolic sine of a hyperbolic angle. The hyperbolic sine of 𝑥 is defined as follows: 𝑒𝑥 − 𝑒−𝑥 2 #calc.sinh(0) \ #calc.sinh(1.5) 0 2.1292794550948173 calc.sinh( float ) → float /1.13.1 value float Required Positional The hyperbolic angle whose hyperbolic sine to calculate. /1.14 cosh Calculates the hyperbolic cosine of a hyperbolic angle. The hyperbolic cosine of 𝑥 is defined as follows: 79 3.5.7 Calculation 𝑒𝑥 + 𝑒−𝑥 2 #calc.cosh(0) \ #calc.cosh(1.5) 1 2.352409615243247 calc.cosh( float ) → float /1.14.1 value float Required Positional The hyperbolic angle whose hyperbolic cosine to calculate. /1.15 tanh Calculates the hyperbolic tangent of a hyperbolic angle. The hyperbolic tangent of 𝑥 is defined as follows: 𝑒𝑥 − 𝑒−𝑥 𝑒𝑥 + 𝑒−𝑥 #calc.tanh(0) \ #calc.tanh(1.5) 0 0.9051482536448664 calc.tanh( float ) → float /1.15.1 value float Required Positional The hyperbolic angle whose hyperbolic tangent to calculate. /1.16 asinh Calculates the inverse hyperbolic sine of a number. The inverse hyperbolic sine of 𝑥 is defined as follows: ln(𝑥 + √𝑥2 + 1) #calc.asinh(0) \ #calc.asinh(1) 0 0.881373587019543 calc.asinh( float ) → float /1.16.1 value float Required Positional The number whose inverse hyperbolic sine to calculate. /1.17 acosh Calculates the inverse hyperbolic cosine of a number. The inverse hyperbolic cosine of 𝑥 is defined as follows: ln(𝑥 + √ 𝑥2 − 1) 80 3.5.7 Calculation #calc.acosh(1) \ #calc.acosh(2.5) 0 1.566799236972411 calc.acosh( float ) → float /1.17.1 value float Required Positional The number whose inverse hyperbolic cosine to calculate. Must be greater than or equal to 1. /1.18 atanh Calculates the inverse hyperbolic tangent of a number. The inverse hyperbolic tangent of 𝑥 is defined as follows: 1 2 ln(1 + 𝑥 1 − 𝑥 ) #calc.atanh(0) \ #calc.atanh(0.5) 0 0.5493061443340548 calc.atanh( float ) → float /1.18.1 value float Required Positional The number whose inverse hyperbolic tangent to calculate. Must be between −1 and 1 (exclusive). /1.19 log Calculates the logarithm of a number. If the base is not specified, the logarithm is calculated in base ten. #calc.log(100) 2 calc.log( int float , base: float , ) → float /1.19.1 value int or float Required Positional The number whose logarithm to calculate. Must be strictly positive. /1.19.2 base float Default: 10.0 The base of the logarithm. May not be zero. /1.20 ln Calculates the natural logarithm of a number. #calc.ln(calc.e) 1 81 3.5.7 Calculation calc.ln( int float ) → float /1.20.1 value int or float Required Positional The number whose logarithm to calculate. Must be strictly positive. /1.21 erf Applies the error function to a number. The value of the error function at 𝑥 is defined as follows: 2√ 𝜋 ∫ 𝑥 0 𝑒−𝑡2 d𝑡 #calc.erf(0.2) 0.22270258921047847 calc.erf( float ) → float /1.21.1 value float Required Positional The number at which to calculate the error function. /1.22 fact Calculates the factorial of a number. #calc.fact(5) 120 calc.fact( int ) → int /1.22.1 number int Required Positional The number whose factorial to calculate. Must be non-negative. /1.23 perm Calculates a permutation. Returns the 𝑘-permutation of 𝑛, or the number of ways to choose 𝑘 items from a set of 𝑛 with regard to order, defined as follows: { 0 if 𝑘 > 𝑛 𝑛! (𝑛−𝑘)! if 𝑘 ≤ 𝑛 #calc.perm(5, 3) 60 calc.perm( int , int , ) → int /1.23.1 base int Required Positional The value of 𝑛: The number of items to choose from. Must be non-negative. 82 3.5.7 Calculation /1.23.2 numbers int Required Positional The value of 𝑘: The number of items to choose. Must be non-negative. /1.24 binom Calculates a binomial coefficient. Returns the 𝑘-combination of 𝑛, or the number of ways to choose 𝑘 items from a set of 𝑛 without regard to order, defined as follows: { 𝑛! 𝑘!(𝑛−𝑘)! if 0 ≤ 𝑘 ≤ 𝑛 0 otherwise #calc.binom(10, 5) 252 calc.binom( int , int , ) → int /1.24.1 n int Required Positional The value of 𝑛: The numbers of items to choose from. Must be non-negative. /1.24.2 k int Required Positional The value of 𝑘: The number of items to choose. Must be non-negative. /1.25 gcd Calculates the greatest common divisor of two integers. This will error if the result of integer division would be larger than the maximum 64-bit signed integer. #calc.gcd(7, 42) 7 calc.gcd( int , int , ) → int /1.25.1 a int Required Positional The first integer. /1.25.2 b int Required Positional The second integer. /1.26 lcm Calculates the least common multiple of two integers. #calc.lcm(96, 13) 1248 83 3.5.7 Calculation calc.lcm( int , int , ) → int /1.26.1 a int Required Positional The first integer. /1.26.2 b int Required Positional The second integer. /1.27 floor Rounds a number down to the nearest integer. If the number is already an integer, it is returned unchanged. Note that this function will always return an integer3.5.16, and will error if the resulting float3.5.14 or decimal3.5.10 is larger than the maximum 64-bit signed integer or smaller than the minimum for that type. #calc.floor(500.1) #assert(calc.floor(3) == 3) #assert(calc.floor(3.14) == 3) #assert(calc.floor(decimal("-3.14")) == -4) 500 calc.floor( int float decimal ) → int /1.27.1 value int or float or decimal Required Positional The number to round down. /1.28 ceil Rounds a number up to the nearest integer. If the number is already an integer, it is returned unchanged. Note that this function will always return an integer3.5.16, and will error if the resulting float3.5.14 or decimal3.5.10 is larger than the maximum 64-bit signed integer or smaller than the minimum for that type. #calc.ceil(500.1) #assert(calc.ceil(3) == 3) #assert(calc.ceil(3.14) == 4) #assert(calc.ceil(decimal("-3.14")) == -3) 501 calc.ceil( int float decimal ) → int /1.28.1 value int or float or decimal Required Positional The number to round up. /1.29 trunc Returns the integer part of a number. 84 3.5.7 Calculation If the number is already an integer, it is returned unchanged. Note that this function will always return an integer3.5.16, and will error if the resulting float3.5.14 or decimal3.5.10 is larger than the maximum 64-bit signed integer or smaller than the minimum for that type. #calc.trunc(15.9) #assert(calc.trunc(3) == 3) #assert(calc.trunc(-3.7) == -3) #assert(calc.trunc(decimal("8493.12949582390")) == 8493) 15 calc.trunc( int float decimal ) → int /1.29.1 value int or float or decimal Required Positional The number to truncate. /1.30 fract Returns the fractional part of a number. If the number is an integer, returns 0. #calc.fract(-3.1) #assert(calc.fract(3) == 0) #assert(calc.fract(decimal("234.23949211")) == decimal("0.23949211")) −0.10000000000000009 calc.fract( int float decimal ) → int float decimal /1.30.1 value int or float or decimal Required Positional The number to truncate. /1.31 round Rounds a number to the nearest integer. Half-integers are rounded away from zero. Optionally, a number of decimal places can be specified. If negative, its absolute value will indicate the amount of significant integer digits to remove before the decimal point. Note that this function will return the same type as the operand. That is, applying round to a float3.5.14 will return a float, and to a decimal3.5.10, another decimal. You may explicitly convert the output of this function to an integer with int3.5.16, but note that such a conversion will error if the float or decimal is larger than the maximum 64-bit signed integer or smaller than the minimum integer. In addition, this function can error if there is an attempt to round beyond the maximum or minimum integer or decimal. If the number is a float, such an attempt will cause float.inf or -float.inf to be returned for maximum and minimum respectively. #calc.round(3.1415, digits: 2) #assert(calc.round(3) == 3) #assert(calc.round(3.14) == 3) #assert(calc.round(3.5) == 4.0) #assert(calc.round(3333.45, digits: -2) == 3300.0) 85 3.5.7 Calculation #assert(calc.round(-48953.45, digits: -3) == -49000.0) #assert(calc.round(3333, digits: -2) == 3300) #assert(calc.round(-48953, digits: -3) == -49000) #assert(calc.round(decimal("-6.5")) == decimal("-7")) #assert(calc.round(decimal("7.123456789"), digits: 6) == decimal("7.123457")) #assert(calc.round(decimal("3333.45"), digits: -2) == decimal("3300")) #assert(calc.round(decimal("-48953.45"), digits: -3) == decimal("-49000")) 3.14 calc.round( int float decimal , digits: int , ) → int float decimal /1.31.1 value int or float or decimal Required Positional The number to round. /1.31.2 digits int Default: 0 If positive, the number of decimal places. If negative, the number of significant integer digits that should be removed before the decimal point. /1.32 clamp Clamps a number between a minimum and maximum value. #calc.clamp(5, 0, 4) #assert(calc.clamp(5, 0, 10) == 5) #assert(calc.clamp(5, 6, 10) == 6) #assert(calc.clamp(decimal("5.45"), 2, decimal("45.9")) == decimal("5.45")) #assert(calc.clamp(decimal("5.45"), decimal("6.75"), 12) == decimal("6.75")) 4 calc.clamp( int float decimal , int float decimal , int float decimal , ) → int float decimal /1.32.1 value int or float or decimal Required Positional The number to clamp. /1.32.2 min int or float or decimal Required Positional The inclusive minimum value. /1.32.3 max int or float or decimal Required Positional The inclusive maximum value. /1.33 min Determines the minimum of a sequence of values. 86 3.5.7 Calculation #calc.min(1, -3, -5, 20, 3, 6) \ #calc.min("typst", "is", "cool") −5 cool calc.min(.. any ) → any /1.33.1 values any Required Positional Variadic The sequence of values from which to extract the minimum. Must not be empty. /1.34 max Determines the maximum of a sequence of values. #calc.max(1, -3, -5, 20, 3, 6) \ #calc.max("typst", "is", "cool") 20 typst calc.max(.. any ) → any /1.34.1 values any Required Positional Variadic The sequence of values from which to extract the maximum. Must not be empty. /1.35 even Determines whether an integer is even. #calc.even(4) \ #calc.even(5) \ #range(10).filter(calc.even) true false (0, 2, 4, 6, 8) calc.even( int ) → bool /1.35.1 value int Required Positional The number to check for evenness. /1.36 odd Determines whether an integer is odd. #calc.odd(4) \ #calc.odd(5) \ #range(10).filter(calc.odd) false true (1, 3, 5, 7, 9) calc.odd( int ) → bool /1.36.1 value int Required Positional The number to check for oddness. /1.37 rem Calculates the remainder of two numbers. 87 3.5.7 Calculation The value calc.rem(x, y) always has the same sign as x, and is smaller in magnitude than y. This can error if given a decimal3.5.10 input and the dividend is too small in magnitude compared to the divisor. #calc.rem(7, 3) \ #calc.rem(7, -3) \ #calc.rem(-7, 3) \ #calc.rem(-7, -3) \ #calc.rem(1.75, 0.5) 1 1 −1 −1 0.25 calc.rem( int float decimal , int float decimal , ) → int float decimal /1.37.1 dividend int or float or decimal Required Positional The dividend of the remainder. /1.37.2 divisor int or float or decimal Required Positional The divisor of the remainder. /1.38 div-euclid Performs euclidean division of two numbers. The result of this computation is that of a division rounded to the integer n such that the dividend is greater than or equal to n times the divisor. This can error if the resulting number is larger than the maximum value or smaller than the minimum value for its type. #calc.div-euclid(7, 3) \ #calc.div-euclid(7, -3) \ #calc.div-euclid(-7, 3) \ #calc.div-euclid(-7, -3) \ #calc.div-euclid(1.75, 0.5) \ #calc.div-euclid(decimal("1.75"), decimal("0.5")) 2 −2 −3 3 3 3 calc.div-euclid( int float decimal , int float decimal , ) → int float decimal /1.38.1 dividend int or float or decimal Required Positional The dividend of the division. 88 3.5.7 Calculation /1.38.2 divisor int or float or decimal Required Positional The divisor of the division. /1.39 rem-euclid This calculates the least nonnegative remainder of a division. Warning: Due to a floating point round-off error, the remainder may equal the absolute value of the divisor if the dividend is much smaller in magnitude than the divisor and the dividend is negative. This only applies for floating point inputs. In addition, this can error if given a decimal3.5.10 input and the dividend is too small in magnitude compared to the divisor. #calc.rem-euclid(7, 3) \ #calc.rem-euclid(7, -3) \ #calc.rem-euclid(-7, 3) \ #calc.rem-euclid(-7, -3) \ #calc.rem-euclid(1.75, 0.5) \ #calc.rem-euclid(decimal("1.75"), decimal("0.5")) 1 1 2 2 0.25 0.25 calc.rem-euclid( int float decimal , int float decimal , ) → int float decimal /1.39.1 dividend int or float or decimal Required Positional The dividend of the remainder. /1.39.2 divisor int or float or decimal Required Positional The divisor of the remainder. /1.40 quo Calculates the quotient (floored division) of two numbers. Note that this function will always return an integer3.5.16, and will error if the resulting number is larger than the maximum 64-bit signed integer or smaller than the minimum for that type. $ "quo"(a, b) &= floor(a/b) \ "quo"(14, 5) &= #calc.quo(14, 5) \ "quo"(3.46, 0.5) &= #calc.quo(3.46, 0.5) $ 89 3.5.7 Calculation quo(𝑎, 𝑏) = ⌊𝑎 𝑏 ⌋ quo(14, 5) = 2 quo(3.46, 0.5) = 6 calc.quo( int float decimal , int float decimal , ) → int /1.40.1 dividend int or float or decimal Required Positional The dividend of the quotient. /1.40.2 divisor int or float or decimal Required Positional The divisor of the quotient. /1.41 norm Calculates the 𝑝-norm of a sequence of values. The 𝑝-norm of 𝑥1, …, 𝑥𝑛 is defined as follows: { (∑𝑛 𝑖=1 |𝑥𝑖| 𝑝) 1/𝑝 if 0 < 𝑝 < +∞ max𝑛 𝑖=1|𝑥𝑖| if 𝑝 = +∞ #calc.norm(1, 2, -3, 0.5) \ #calc.norm(p: 3, 1, 2) 3.774917217635375 2.080083823051904 calc.norm( p: float , .. float , ) → float /1.41.1 p float Default: 2.0 The value of 𝑝. Must be greater than zero. The default value of 2.0 corresponds to the Euclidean norm: √∑ 𝑛 𝑖=1 𝑥2 𝑖 /1.41.2 values float Required Positional Variadic The sequence of values to calculate the 𝑝-norm of. Returns 0.0 if empty. 90 3.5.8 content A piece of document content. This type is at the heart of Typst. All markup you write and most functions3.5.15 you call produce content values. You can create a content value by enclosing markup in square brackets. This is also how you pass content to functions. /1 Example Type of *Hello!* is #type([*Hello!*]) Type of Hello! is content Content can be added with the + operator, joined together3.3.2 and multiplied with integers. Wherever content is expected, you can also pass a string3.5.27 or none. /2 Representation Content consists of elements with fields. When constructing an element with its element function, you provide these fields as arguments and when you have a content value, you can access its fields with field access syntax3.3.6. Some fields are required: These must be provided when constructing an element and as a consequence, they are always available through field access on content of that type. Required fields are marked as such in the documentation. Most fields are optional: Like required fields, they can be passed to the element function to configure them for a single element. However, these can also be configured with set rules3.2.1 to apply them to all elements within a scope. Optional fields are only available with field access syntax when they were explicitly passed to the element function, not when they result from a set rule. Each element has a default appearance. However, you can also completely customize its appearance with a show rule3.2.2. The show rule is passed the element. It can access the element's field and produce arbitrary content from it. In the web app, you can hover over a content variable to see exactly which elements the content is composed of and what fields they have. Alternatively, you can inspect the output of the repr3.5.24 function. /3 Definitions /3.1 func The content's element function. This function can be used to create the element contained in this content. It can be used in set and show rules for the element. Can be compared with global functions to check whether you have a specific kind of element. self.func() → function /3.2 has Whether the content has the specified field. self.has( str ) → bool /3.2.1 field str Required Positional The field to look for. /3.3 at Access the specified field on the content. Returns the default value if the field does not exist or fails with an error if no default value was specified. 91 3.5.8 content self.at( str , default: any , ) → any /3.3.1 field str Required Positional The field to access. /3.3.2 default any A default value to return if the field does not exist. /3.4 fields Returns the fields of this content. #rect( width: 10cm, height: 10cm, ).fields() (width: 0% + 283.46pt, height: 0% + 283.46pt) self.fields() → dictionary /3.5 location The location of the content. This is only available on content returned by query3.12.6 or provided by a show rule3.2.2, for other content it will be none. The resulting location can be used with counters3.12.1, state3.12.7 and queries3.12.6. self.location() → none location 92 3.5.9 datetime Represents a date, a time, or a combination of both. Can be created by either specifying a custom datetime using this type's constructor function or getting the current date with datetime.today3.5.9/5.1. /1 Example #let date = datetime( year: 2020, month: 10, day: 4, ) #date.display() \ #date.display( "y:[year repr:last_two]" ) #let time = datetime( hour: 18, minute: 2, second: 23, ) #time.display() \ #time.display( "h:[hour repr:12][period]" ) 2020-10-04 y:20 18:02:23 h:06PM /2 Datetime and Duration You can get a duration3.5.12 by subtracting two datetime: #let first-of-march = datetime(day: 1, month: 3, year: 2024) #let first-of-jan = datetime(day: 1, month: 1, year: 2024) #let distance = first-of-march - first-of-jan #distance.hours() 1440 You can also add/subtract a datetime and a duration to retrieve a new, offset datetime: #let date = datetime(day: 1, month: 3, year: 2024) #let two-days = duration(days: 2) #let two-days-earlier = date - two-days #let two-days-later = date + two-days #date.display() \ #two-days-earlier.display() \ #two-days-later.display() 93 3.5.9 datetime 2024-03-01 2024-02-28 2024-03-03 /3 Format You can specify a customized formatting using the display3.5.9/5.2 method. The format of a datetime is specified by providing components with a specified number of modifiers. A component represents a certain part of the datetime that you want to display, and with the help of modifiers you can define how you want to display that component. In order to display a component, you wrap the name of the component in square brackets (e.g. [year] will display the year). In order to add modifiers, you add a space after the component name followed by the name of the modifier, a colon and the value of the modifier (e.g. [month repr:short] will display the short representation of the month). The possible combination of components and their respective modifiers is as follows: – year: Displays the year of the datetime. – base: Can be either calendar or iso_week. Specifies whether the year is based on the Gregorian calendar or the ISO week number. – padding: Can be either zero, space or none. Specifies how the year is padded. – repr Can be either full in which case the full year is displayed or last_two in which case only the last two digits are displayed. – sign: Can be either automatic or mandatory. Specifies when the sign should be displayed. – month: Displays the month of the datetime. – padding: Can be either zero, space or none. Specifies how the month is padded. – repr: Can be either numerical, long or short. Specifies if the month should be displayed as a number or a word. Unfortunately, when choosing the word representation, it can currently only display the English version. In the future, it is planned to support localization. – day: Displays the day of the datetime. – padding: Can be either zero, space or none. Specifies how the day is padded. – week_number: Displays the week number of the datetime. – padding: Can be either zero, space or none. Specifies how the week number is padded. – repr: Can be either ISO, sunday or monday. In the case of ISO, week numbers are between 1 and 53, while the other ones are between 0 and 53. – weekday: Displays the weekday of the date. – repr Can be either long, short, sunday or monday. In the case of long and short, the corresponding English name will be displayed (same as for the month, other languages are currently not supported). In the case of sunday and monday, the numerical value will be displayed (assuming Sunday and Monday as the first day of the week, respectively). – one_indexed: Can be either true or false. Defines whether the numerical representation of the week starts with 0 or 1. – hour: Displays the hour of the date. – padding: Can be either zero, space or none. Specifies how the hour is padded. – repr: Can be either 24 or 12. Changes whether the hour is displayed in the 24-hour or 12-hour format. – period: The AM/PM part of the hour – case: Can be lower to display it in lower case and upper to display it in upper case. – minute: Displays the minute of the date. – padding: Can be either zero, space or none. Specifies how the minute is padded. – second: Displays the second of the date. – padding: Can be either zero, space or none. Specifies how the second is padded. See here[A] for more details on the supported syntax. Keep in mind that not always all components can be used. For example, if you create a new datetime with datetime(year: 2023, month: 10, day: 13), it will be stored as a plain date internally, meaning that [A]https://time-rs.github.io/book/api/format-description.html#components 94 https://time-rs.github.io/book/api/format-description.html#components https://time-rs.github.io/book/api/format-description.html#components 3.5.9 datetime you cannot use components such as hour or minute, which would only work on datetimes that have a specified time. /4 Constructor Creates a new datetime. You can specify the datetime3.5.9 using a year, month, day, hour, minute, and second. Note: Depending on which components of the datetime you specify, Typst will store it in one of the following three ways: – If you specify year, month and day, Typst will store just a date. – If you specify hour, minute and second, Typst will store just a time. – If you specify all of year, month, day, hour, minute and second, Typst will store a full datetime. Depending on how it is stored, the display3.5.9/5.2 method will choose a different formatting by default. #datetime( year: 2012, month: 8, day: 3, ).display() 2012-08-03 datetime( year: int , month: int , day: int , hour: int , minute: int , second: int , ) → datetime /4.1 year int The year of the datetime. /4.2 month int The month of the datetime. /4.3 day int The day of the datetime. /4.4 hour int The hour of the datetime. /4.5 minute int The minute of the datetime. /4.6 second int The second of the datetime. /5 Definitions /5.1 today Returns the current date. In the CLI, this can be overridden with the --creation-timestamp argument or by setting the SOURCE_DATE_EPOCH[A] environment variable. In both cases, the value should be given as a UNIX timestamp. [A]https://reproducible-builds.org/specs/source-date-epoch/ 95 https://reproducible-builds.org/specs/source-date-epoch/ https://reproducible-builds.org/specs/source-date-epoch/ 3.5.9 datetime Today's date is #datetime.today().display(). Today's date is 1970-01-01. datetime.today(offset: auto int duration ) → datetime /5.1.1 offset auto or int or duration Default: auto An offset to apply to the current UTC date. If set to auto, the offset will be the local offset. When an integer offset is given, it will be treated as a duration in hours. /5.2 display Displays the datetime in a specified format. Depending on whether you have defined just a date, a time or both, the default format will be different. If you specified a date, it will be [year]-[month]-[day]. If you specified a time, it will be [hour]:[minute]: [second]. In the case of a datetime, it will be [year]-[month]-[day] [hour]:[minute]:[second]. See the format syntax3.5.9/3 for more information. self.display( auto str ) → str /5.2.1 pattern auto or str Positional Default: auto The format used to display the datetime. /5.3 year The year if it was specified, or none for times without a date. self.year() → none int /5.4 month The month if it was specified, or none for times without a date. self.month() → none int /5.5 weekday The weekday (counting Monday as 1) or none for times without a date. self.weekday() → none int /5.6 day The day if it was specified, or none for times without a date. self.day() → none int /5.7 hour The hour if it was specified, or none for dates without a time. self.hour() → none int 96 3.5.9 datetime /5.8 minute The minute if it was specified, or none for dates without a time. self.minute() → none int /5.9 second The second if it was specified, or none for dates without a time. self.second() → none int /5.10 ordinal The ordinal (day of the year), or none for times without a date. self.ordinal() → none int 97 3.5.10 decimal A fixed-point decimal number type. This type should be used for precise arithmetic operations on numbers represented in base 10. A typical use case is representing currency. /1 Example Decimal: #(decimal("0.1") + decimal("0.2")) \ Float: #(0.1 + 0.2) Decimal: 0.3 Float: 0.30000000000000004 /2 Construction and casts To create a decimal number, use the decimal(string) constructor, such as in decimal("3.141592653") (note the double quotes). This constructor preserves all given fractional digits, provided they are repre sentable as per the limits specified below (otherwise, an error is raised). You can also convert any integer3.5.16 to a decimal with the decimal(int) constructor, e.g. decimal(59). However, note that constructing a decimal from a floating-point number3.5.14, while supported, is an impre­ cise conversion and therefore discouraged. A warning will be raised if Typst detects that there was an accidental float to decimal cast through its constructor, e.g. if writing decimal(3.14) (note the lack of double quotes, indicating this is an accidental float cast and therefore imprecise). It is recommended to use strings for constant decimal values instead (e.g. decimal("3.14")). The precision of a float to decimal cast can be slightly improved by rounding the result to 15 digits with calc.round3.5.7/1.31, but there are still no precision guarantees for that kind of conversion. /3 Operations Basic arithmetic operations are supported on two decimals and on pairs of decimals and integers. Built-in operations between float and decimal are not supported in order to guard against accidental loss of precision. They will raise an error instead. Certain calc functions, such as trigonometric functions and power between two real numbers, are also only supported for float (although raising decimal to integer exponents is supported). You can opt into potentially imprecise operations with the float(decimal) constructor, which casts the decimal number into a float, allowing for operations without precision guarantees. /4 Displaying decimals To display a decimal, simply insert the value into the document. To only display a certain number of digits, round3.5.7/1.31 the decimal first. Localized formatting of decimals and other numbers is not yet supported, but planned for the future. You can convert decimals to strings using the str3.5.27 constructor. This way, you can post-process the displayed representation, e.g. to replace the period with a comma (as a stand-in for proper built-in local ization to languages that use the comma). /5 Precision and limits A decimal number has a limit of 28 to 29 significant base-10 digits. This includes the sum of digits before and after the decimal point. As such, numbers with more fractional digits have a smaller range. The maximum and minimum decimal numbers have a value of 79228162514264337593543950335 and -79228162514264337593543950335 respectively. In contrast with float3.5.14, this type does not support infinity or NaN, so overflowing or underflowing operations will raise an error. 98 3.5.10 decimal Typical operations between decimal numbers, such as addition, multiplication, and power3.5.7/1.2 to an integer, will be highly precise due to their fixed-point representation. Note, however, that multiplication and division may not preserve all digits in some edge cases: while they are considered precise, digits past the limits specified above are rounded off and lost, so some loss of precision beyond the maximum representable digits is possible. Note that this behavior can be observed not only when dividing, but also when multiplying by numbers between 0 and 1, as both operations can push a number's fractional digits beyond the limits described above, leading to rounding. When those two operations do not surpass the digit limits, they are fully precise. /6 Constructor Converts a value to a decimal. It is recommended to use a string to construct the decimal number, or an integer3.5.16 (if desired). The string must contain a number in the format "3.14159" (or "-3.141519" for negative numbers). The fractional digits are fully preserved; if that's not possible due to the limit of significant digits (around 28 to 29) having been reached, an error is raised as the given decimal number wouldn't be representable. While this constructor can be used with floating-point numbers3.5.14 to cast them to decimal, doing so is discouraged as this cast is inherently imprecise. It is easy to accidentally perform this cast by writing decimal(1.234) (note the lack of double quotes), which is why Typst will emit a warning in that case. Please write decimal("1.234") instead for that particular case (initialization of a constant decimal). Also note that floats that are NaN or infinite cannot be cast to decimals and will raise an error. #decimal("1.222222222222222") 1.222222222222222 decimal( bool int float decimal str ) → decimal /6.1 value bool or int or float or decimal or str Required Positional The value that should be converted to a decimal. 99 3.5.11 dictionary A map from string keys to values. You can construct a dictionary by enclosing comma-separated key: value pairs in parentheses. The values do not have to be of the same type. Since empty parentheses already yield an empty array, you have to use the special (:) syntax to create an empty dictionary. A dictionary is conceptually similar to an array3.5.2, but it is indexed by strings instead of integers. You can access and create dictionary entries with the .at() method. If you know the key statically, you can alternatively use field access notation3.3.6 (.key) to access the value. To check whether a key is present in the dictionary, use the in keyword. You can iterate over the pairs in a dictionary using a for loop3.3.5. This will iterate in the order the pairs were inserted / declared initially. Dictionaries can be added with the + operator and joined together3.3.2. They can also be spread3.5.1/2 into a function call or another dictionary[A] with the ..spread operator. In each case, if a key appears multiple times, the last value will override the others. /1 Example #let dict = ( name: "Typst", born: 2019, ) #dict.name \ #(dict.launch = 20) #dict.len() \ #dict.keys() \ #dict.values() \ #dict.at("born") \ #dict.insert("city", "Berlin") #("name" in dict) Typst 3 ("name", "born", "launch") ("Typst", 2019, 20) 2019 true /2 Constructor Converts a value into a dictionary. Note that this function is only intended for conversion of a dictionary-like value to a dictionary, not for creation of a dictionary from individual pairs. Use the dictionary syntax (key: value) instead. Also see array.to-dict3.5.2/3.32 for converting arrays to dictionaries. #dictionary(sys).at("version") 0.15.0 dictionary( module ) → dictionary /2.1 value module Required Positional The value that should be converted to a dictionary. /3 Definitions /3.1 len The number of pairs in the dictionary. [A]When spreading into a dictionary, if all items between the parentheses are spread, you have to begin the container with (:, as in (: ..dict, ..other_dict). Otherwise the container is inferred to be an array and an error is raised. 100 3.5.11 dictionary self.len() → int /3.2 at Returns the value associated with the specified key in the dictionary. May be used on the left-hand side of an assignment if the key is already present in the dictionary. Returns the default value if the key is not part of the dictionary or fails with an error if no default value was specified. Values may also be accessed with field syntax (e.g. (key: 42).key) if no default is needed. self.at( str , default: any , ) → any /3.2.1 key str Required Positional The key at which to retrieve the item. /3.2.2 default any A default value to return if the key is not part of the dictionary. /3.3 insert Inserts a new pair into the dictionary. If the dictionary already contains this key, the value is updated. To insert multiple pairs at once, you can alternatively add another dictionary with the += operator. self.insert( str , any , ) → none /3.3.1 key str Required Positional The key of the pair that should be inserted. /3.3.2 value any Required Positional The value of the pair that should be inserted. /3.4 remove Removes a pair from the dictionary by key and return the value. self.remove( str , default: any , ) → any /3.4.1 key str Required Positional The key of the pair to remove. /3.4.2 default any A default value to return if the key does not exist. /3.5 keys Returns the keys of the dictionary as an array in insertion order. self.keys() → array 101 3.5.11 dictionary /3.6 values Returns the values of the dictionary as an array in insertion order. self.values() → array /3.7 pairs Returns the keys and values of the dictionary as an array of pairs. Each pair is represented as an array of length two. self.pairs() → array /3.8 filter Produces a new dictionary with only the pairs from the original one for which the given function returns true. Example · Basic usage #{ (a: 0, b: 1, c: 2) .filter(v => v > 0) } (b: 1, c: 2) Example · Filtering based on the key instead of the value #{ (a: 0, b: 1, c: 2) .pairs() .filter(((k, v)) => k != "a") .to-dict() } (b: 1, c: 2) self.filter( function ) → dictionary /3.8.1 test function Required Positional The function to apply to each value. Must return a boolean. /3.9 map Produces a new dictionary where the keys are the same, but the values are transformed with the given function. #(a: 0, b: 1, c: 2).map(v => v + 1) (a: 1, b: 2, c: 3) self.map( function ) → dictionary /3.9.1 mapper function Required Positional The function to apply to each value. 102 3.5.12 duration Represents a positive or negative span of time. /1 Constructor Creates a new duration. You can specify the duration3.5.12 using weeks, days, hours, minutes and seconds. You can also get a duration by subtracting two datetimes3.5.9. #duration( days: 3, hours: 12, ).hours() 84 duration( seconds: int , minutes: int , hours: int , days: int , weeks: int , ) → duration /1.1 seconds int Default: 0 The number of seconds. /1.2 minutes int Default: 0 The number of minutes. /1.3 hours int Default: 0 The number of hours. /1.4 days int Default: 0 The number of days. /1.5 weeks int Default: 0 The number of weeks. /2 Definitions /2.1 seconds The duration expressed in seconds. This function returns the total duration represented in seconds as a floating-point number, rather than the seconds component of the duration. self.seconds() → float /2.2 minutes The duration expressed in minutes. This function returns the total duration represented in minutes as a floating-point number, rather than the minutes component of the duration. self.minutes() → float 103 3.5.12 duration /2.3 hours The duration expressed in hours. This function returns the total duration represented in hours as a floating-point number, rather than the hours component of the duration. self.hours() → float /2.4 days The duration expressed in days. This function returns the total duration represented in days as a floating-point number, rather than the days component of the duration. self.days() → float /2.5 weeks The duration expressed in weeks. This function returns the total duration represented in weeks as a floating-point number, rather than the weeks component of the duration. self.weeks() → float 104 3.5.13 eval Evaluates a string as Typst code. This function should only be used as a last resort. /1 Example #eval("1 + 1") \ #eval("(1, 2, 3, 4)").len() \ #eval("*Markup!*", mode: "markup") \ 2 4 Markup! /2 Parameters eval( str , mode: str , scope: dictionary , ) → any /2.1 source str Required Positional A string of Typst code to evaluate. /2.2 mode str Default: "code" The syntactical mode3.1.1 in which the string is parsed. #eval("= Heading", mode: "markup") #eval("1_2^3", mode: "math") Heading 13 2 Variant Details "markup" Evaluate as markup, as in a Typst file. "math" Evaluate as math, as in an equation. "code" Evaluate as code, as after a hash. /2.3 scope dictionary Default: (:) A scope of definitions that are made available. #eval("x + 1", scope: (x: 2)) \ #eval( "abc/xyz", mode: "math", scope: ( abc: $a + b + c$, xyz: $x + y + z$, ), ) 3 𝑎+𝑏+𝑐 𝑥+𝑦+𝑧 105 3.5.14 float A floating-point number. A limited-precision representation of a real number. Typst uses 64 bits to store floats. Wherever a float is expected, you can also pass an integer3.5.16. You can convert a value to a float with this type's constructor. NaN and positive infinity are available as float.nan and float.inf respectively. /1 Example #3.14 \ #1e4 \ #(10 / 4) 3.14 10000 2.5 /2 Constructor Converts a value to a float. – Booleans are converted to 0.0 or 1.0. – Integers are converted to the closest 64-bit float. For integers with absolute value less than calc.pow(2, 53), this conversion is exact. – Ratios are divided by 100%. – Strings are parsed in base 10 to the closest 64-bit float. Exponential notation is supported. #float(false) \ #float(true) \ #float(4) \ #float(40%) \ #float("2.7") \ #float("1e5") 0 1 4 0.4 2.7 100000 float( bool int float ratio decimal str ) → float /2.1 value bool or int or float or ratio or decimal or str Required Positional The value that should be converted to a float. /3 Definitions /3.1 is-nan Checks if a float is not a number. In IEEE 754, more than one bit pattern represents a NaN. This function returns true if the float is any of those bit patterns. #float.is-nan(0) \ #float.is-nan(1) \ #float.is-nan(float.nan) false false true self.is-nan() → bool 106 3.5.14 float /3.2 is-infinite Checks if a float is infinite. Floats can represent positive infinity and negative infinity. This function returns true if the float is an infinity. #float.is-infinite(0) \ #float.is-infinite(1) \ #float.is-infinite(float.inf) false false true self.is-infinite() → bool /3.3 signum Calculates the sign of a floating point number. – If the number is positive (including +0.0), returns 1.0. – If the number is negative (including -0.0), returns -1.0. – If the number is NaN, returns float.nan. #(5.0).signum() \ #(-5.0).signum() \ #(0.0).signum() \ #float.nan.signum() 1 −1 1 NaN self.signum() → float /3.4 from-bytes Interprets bytes as a float. #float.from-bytes(bytes((0, 0, 0, 0, 0, 0, 240, 63))) \ #float.from-bytes(bytes((63, 240, 0, 0, 0, 0, 0, 0)), endian: "big") 1 1 float.from-bytes( bytes , endian: str , ) → float /3.4.1 bytes bytes Required Positional The bytes that should be converted to a float. Must have a length of either 4 or 8. The bytes are then interpreted in IEEE 754[A]'s binary32 (single- precision) or binary64 (double-precision) format depending on the length of the bytes. [A]https://en.wikipedia.org/wiki/IEEE_754 107 https://en.wikipedia.org/wiki/IEEE_754 https://en.wikipedia.org/wiki/IEEE_754 3.5.14 float /3.4.2 endian str Default: "little" The endianness of the conversion. Variant Details "big" Big-endian byte order: The highest-value byte is at the beginning of the bytes. "little" Little-endian byte order: The lowest-value byte is at the beginning of the bytes. /3.5 to-bytes Converts a float to bytes. #array(1.0.to-bytes(endian: "big")) \ #array(1.0.to-bytes()) (63, 240, 0, 0, 0, 0, 0, 0) (0, 0, 0, 0, 0, 0, 240, 63) self.to-bytes( endian: str , size: int , ) → bytes /3.5.1 endian str Default: "little" The endianness of the conversion. Variant Details "big" Big-endian byte order: The highest-value byte is at the beginning of the bytes. "little" Little-endian byte order: The lowest-value byte is at the beginning of the bytes. /3.5.2 size int Default: 8 The size of the resulting bytes. This must be either 4 or 8. The call will return the representation of this float in either IEEE 754[A]'s binary32 (single-precision) or binary64 (double-precision) format depending on the provided size. [A]https://en.wikipedia.org/wiki/IEEE_754 108 https://en.wikipedia.org/wiki/IEEE_754 https://en.wikipedia.org/wiki/IEEE_754 3.5.15 function A mapping from argument values to a return value. You can call a function by writing a comma-separated list of function arguments enclosed in parentheses directly after the function name. Additionally, you can pass any number of trailing content block arguments to a function after the normal argument list. If the normal argument list would become empty, it can be omitted. Typst supports positional and named arguments. The former are identified by position and type, while the latter are written as name: value. Within math mode, function calls have special behaviour. See the math documentation3.8 for more details. /1 Example // Call a function. #list([A], [B]) // Named arguments and trailing // content blocks. #enum(start: 2)[A][B] // Version without parentheses. #list[A][B] • A • B 2. A 3. B • A • B Functions are a fundamental building block of Typst. Typst provides functions for a variety of typesetting tasks. Moreover, the markup you write is backed by functions and all styling happens through functions. This reference lists all available functions and how you can use them. Please also refer to the documentation about set3.2.1 and show3.2.2 rules to learn about additional ways you can work with functions in Typst. /2 Element functions Some functions are associated with elements like headings3.6.10 or tables3.6.20. When called, these create an element of their respective kind. In contrast to normal functions, they can further be used in set rules3.2.1, show rules3.2.2, and selectors3.5.25. /3 Function scopes Functions can hold related definitions in their own scope, similar to a module3.3.8. Examples of this are assert.eq3.5.3/3.1 or list.item3.6.3/4.1. However, this feature is currently only available for built-in functions. /4 Defining functions You can define your own function with a let binding3.3.3 that has a parameter list after the binding's name. The parameter list can contain mandatory positional parameters, named parameters with default values and argument sinks3.5.1. The right-hand side of a function binding is the function body, which can be a block or any other expression. It defines the function's return value and can depend on the parameters. If the function body is a code block3.3.2, the return value is the result of joining the values of each expression in the block. Within a function body, the return keyword can be used to exit early and optionally specify a return value. If no explicit return value is given, the body evaluates to the result of joining all expressions preceding the return. Functions that don't return any meaningful value return none3.5.19 instead. The return type of such functions is not explicitly specified in the documentation. (An example of this is array.push3.5.2/3.5). 109 3.5.15 function #let alert(body, fill: red) = { set text(white) set align(center) rect( fill: fill, inset: 8pt, radius: 4pt, [*Warning:\ #body*], ) } #alert[ Danger is imminent! ] #alert(fill: blue)[ KEEP OFF TRACKS ] Warning: Danger is imminent! Warning: KEEP OFF TRACKS /5 Importing functions Functions can be imported from one file (module3.3.8) into another using import. For example, assume that we have defined the alert function from the previous example in a file called foo.typ. We can import it into another file by writing import "foo.typ": alert. /6 Unnamed functions You can also create an unnamed function without creating a binding by specifying a parameter list followed by => and the function body. If your function has just one parameter, the parentheses around the parameter list are optional. Unnamed functions are mainly useful for show rules, but also as arguments to other functions, like array.position3.5.2/3.12. #show "once?": it => [#it #it] once? once? once? /7 Note on function purity In Typst, all functions are pure. This means that for the same arguments, they always return the same result. They cannot "remember" things to produce another value when they are called a second time. The only exception are built-in methods like array.push(value)3.5.2/3.5. These can modify the values they are called on. /8 Definitions /8.1 with Returns a new function that has the given arguments pre-applied. self.with(.. any ) → function /8.1.1 arguments any Required Positional Variadic The arguments to apply to the function. /8.2 where Returns a selector that filters for elements belonging to this function whose fields have the values of the given arguments. 110 3.5.15 function #show heading.where(level: 2): set text(blue) = Section == Subsection === Sub-subsection Section Subsection Sub-subsection self.where(.. any ) → selector /8.2.1 fields any Required Positional Variadic The fields to filter for. 111 3.5.16 int An integer: a positive whole number, a negative whole number, or zero. Typst stores signed integers with the two's complement[A] representation in 64 bits. This allows storing numbers up to 263 − 1 or 9223372036854775807, and down to −263 or -9223372036854775808. These values are accessible as int.max and int.min. Integers can also be specified as hexadecimal, octal, or binary by starting with the prefixes: 0x, 0o, or 0b. You can convert a value to an integer with this type's constructor. /1 Example #(1 + 2) \ #(2 - 5) \ #(3 + 4 < 8) #0xff \ #0o10 \ #0b1001 #(int(3.8) + int("26")) / Max: #int.max / Min: #int.min 3 −3 true 255 8 9 29 Max 9223372036854775807 Min −9223372036854775808 /2 Constructor Converts a value to an integer. Raises an error if there is an attempt to parse an invalid string or produce an integer that doesn't fit into a 64-bit signed integer. – Booleans are converted to 0 or 1. – Floats and decimals are rounded to the next 64-bit integer towards zero. – Strings are parsed in base 10 by default. #int(false) \ #int(true) \ #int(2.7) \ #int(decimal("3.8")) \ #(int("27") + int("4")) \ #int("beef", base: 16) 0 1 2 3 31 48879 int( bool int float decimal str , base: int , ) → int /2.1 value bool or int or float or decimal or str Required Positional The value that should be converted to an integer. /2.2 base int Default: 10 The base (radix) for parsing strings, between 2 and 36. [A]https://en.wikipedia.org/wiki/Two%27s_complement 112 https://en.wikipedia.org/wiki/Two%27s_complement https://en.wikipedia.org/wiki/Two%27s_complement 3.5.16 int /3 Definitions /3.1 signum Calculates the sign of an integer. – If the number is positive, returns 1. – If the number is negative, returns -1. – If the number is zero, returns 0. #(5).signum() \ #(-5).signum() \ #(0).signum() 1 −1 0 self.signum() → int /3.2 bit-not Calculates the bitwise NOT of an integer. For the purposes of this function, the operand is treated as a signed integer of 64 bits. #4.bit-not() \ #(-1).bit-not() −5 0 self.bit-not() → int /3.3 bit-and Calculates the bitwise AND between two integers. For the purposes of this function, the operands are treated as signed integers of 64 bits. #128.bit-and(192) 128 self.bit-and( int ) → int /3.3.1 rhs int Required Positional The right-hand operand of the bitwise AND. /3.4 bit-or Calculates the bitwise OR between two integers. For the purposes of this function, the operands are treated as signed integers of 64 bits. #64.bit-or(32) 96 self.bit-or( int ) → int 113 3.5.16 int /3.4.1 rhs int Required Positional The right-hand operand of the bitwise OR. /3.5 bit-xor Calculates the bitwise XOR between two integers. For the purposes of this function, the operands are treated as signed integers of 64 bits. #64.bit-xor(96) 32 self.bit-xor( int ) → int /3.5.1 rhs int Required Positional The right-hand operand of the bitwise XOR. /3.6 bit-lshift Shifts the operand's bits to the left by the specified amount. For the purposes of this function, the operand is treated as a signed integer of 64 bits. An error will occur if the result is too large to fit in a 64-bit integer. #33.bit-lshift(2) \ #(-1).bit-lshift(3) 132 −8 self.bit-lshift( int ) → int /3.6.1 shift int Required Positional The amount of bits to shift. Must not be negative. /3.7 bit-rshift Shifts the operand's bits to the right by the specified amount. Performs an arithmetic shift by default (extends the sign bit to the left, such that negative numbers stay negative), but that can be changed by the logical parameter. For the purposes of this function, the operand is treated as a signed integer of 64 bits. #64.bit-rshift(2) \ #(-8).bit-rshift(2) \ #(-8).bit-rshift(2, logical: true) 16 −2 4611686018427387902 self.bit-rshift( int , logical: bool , ) → int /3.7.1 shift int Required Positional The amount of bits to shift. Must not be negative. Shifts larger than 63 are allowed and will cause the return value to saturate. For non-negative numbers, the return value saturates at 0, while, for negative numbers, it saturates at -1 if logical 114 3.5.16 int is set to false, or 0 if it is true. This behavior is consistent with just applying this operation multiple times. Therefore, the shift will always succeed. /3.7.2 logical bool Default: false Toggles whether a logical (unsigned) right shift should be performed instead of arithmetic right shift. If this is true, negative operands will not preserve their sign bit, and bits which appear to the left after the shift will be 0. This parameter has no effect on non-negative operands. /3.8 from-bytes Converts bytes to an integer. #int.from-bytes(bytes((0, 0, 0, 0, 0, 0, 0, 1))) \ #int.from-bytes(bytes((1, 0, 0, 0, 0, 0, 0, 0)), endian: "big") 72057594037927936 72057594037927936 int.from-bytes( bytes , endian: str , signed: bool , ) → int /3.8.1 bytes bytes Required Positional The bytes that should be converted to an integer. Must be of length at most 8 so that the result fits into a 64-bit signed integer. /3.8.2 endian str Default: "little" The endianness of the conversion. Variant Details "big" Big-endian byte order: The highest-value byte is at the beginning of the bytes. "little" Little-endian byte order: The lowest-value byte is at the beginning of the bytes. /3.8.3 signed bool Default: true Whether the bytes should be treated as a signed integer. If this is true and the most significant bit is set, the resulting number will negative. /3.9 to-bytes Converts an integer to bytes. #array(10000.to-bytes(endian: "big")) \ #array(10000.to-bytes(size: 4)) (0, 0, 0, 0, 0, 0, 39, 16) (16, 39, 0, 0) self.to-bytes( endian: str , size: int , ) → bytes 115 3.5.16 int /3.9.1 endian str Default: "little" The endianness of the conversion. Variant Details "big" Big-endian byte order: The highest-value byte is at the beginning of the bytes. "little" Little-endian byte order: The lowest-value byte is at the beginning of the bytes. /3.9.2 size int Default: 8 The size in bytes of the resulting bytes (must be at least zero). If the integer is too large to fit in the specified size, the conversion will truncate the remaining bytes based on the endianness. To keep the same resulting value, if the endianness is big-endian, the truncation will happen at the rightmost bytes. Otherwise, if the endianness is little-endian, the truncation will happen at the leftmost bytes. Be aware that if the integer is negative and the size is not enough to make the number fit, when passing the resulting bytes to int.from-bytes, the resulting number might be positive, as the most significant bit might not be set to 1. 116 3.5.17 label A label for an element. Inserting a label into content attaches it to the closest preceding element that is not a space. The preceding element must be in the same scope as the label, which means that Hello #[