├── .gitignore ├── src ├── snippets │ ├── index.md │ ├── img │ │ ├── tub.png │ │ └── landscape.png │ ├── text │ │ ├── individual_lang_fonts.md │ │ ├── line_indent.md │ │ └── text_shadows.md │ ├── layout │ │ ├── hiding.md │ │ ├── insert_lines.md │ │ ├── multiline_detect.md │ │ ├── page_setup.md │ │ ├── duplicate.md │ │ └── shapes.md │ ├── math │ │ ├── operations.md │ │ ├── fonts.md │ │ ├── calligraphic.md │ │ ├── scripts.md │ │ ├── vecs.md │ │ └── numbering.md │ ├── external.md │ ├── dataload │ │ ├── file.json │ │ └── json.md │ ├── code.md │ ├── chapters │ │ ├── page-numbering.md │ │ └── outlines.md │ ├── special │ │ └── index.md │ ├── labels.md │ ├── gradients.md │ ├── pretty.md │ ├── grids.md │ ├── scripting │ │ └── index.md │ ├── numbering.md │ └── demos.md ├── typstonomicon │ ├── tiger.jpg │ ├── index.md │ ├── math_display.md │ ├── inline_with.md │ ├── try_catch.md │ ├── remove-indent-nested.md │ ├── original_image.md │ ├── multiple-show.md │ ├── word_count.md │ ├── extract_plain_text.md │ ├── chapters.md │ └── totally-empty.md ├── basics │ ├── must_know │ │ ├── tiger.jpg │ │ ├── index.md │ │ ├── box_block.md │ │ ├── place.md │ │ ├── project_struct.md │ │ ├── spacing.md │ │ └── tables.md │ ├── tutorial │ │ ├── boxes.png │ │ ├── cheatsheet.md │ │ ├── index.md │ │ ├── templates.md │ │ ├── markup.md │ │ ├── basic_styling.md │ │ ├── functions.md │ │ └── advanced_styling.md │ ├── scripting │ │ ├── index.md │ │ ├── tips.md │ │ ├── basics.md │ │ ├── arguments.md │ │ ├── types_2.md │ │ ├── types.md │ │ ├── conditions.md │ │ └── braces.md │ ├── states │ │ ├── metadata.md │ │ ├── index.md │ │ ├── query.md │ │ ├── locate.md │ │ ├── measure.md │ │ ├── counters.md │ │ ├── context.md │ │ └── states.md │ ├── extra.md │ ├── index.md │ ├── math │ │ ├── classes.md │ │ ├── grouping.md │ │ ├── alignment.md │ │ ├── sizes.md │ │ ├── limits.md │ │ ├── operators.md │ │ ├── vec.md │ │ ├── index.md │ │ └── symbols.md │ └── special_symbols.md ├── fonts │ ├── FiraMath-Regular.otf │ └── NotoSerifThai-Regular.ttf ├── packages │ ├── img │ │ └── treemap.png │ ├── external.md │ ├── headers.md │ ├── wrapping.md │ ├── code.md │ ├── word_count.md │ ├── presentation.md │ ├── misc.md │ ├── tables.md │ ├── index.md │ ├── glossary.md │ ├── drawing.md │ ├── physics.md │ └── boxes.md ├── about.md ├── SUMMARY.md └── getting_started.md ├── theme ├── favicon.png ├── fonts │ ├── open-sans-v17-all-charsets-300.woff2 │ ├── open-sans-v17-all-charsets-600.woff2 │ ├── open-sans-v17-all-charsets-700.woff2 │ ├── open-sans-v17-all-charsets-800.woff2 │ ├── open-sans-v17-all-charsets-italic.woff2 │ ├── open-sans-v17-all-charsets-regular.woff2 │ ├── open-sans-v17-all-charsets-300italic.woff2 │ ├── open-sans-v17-all-charsets-600italic.woff2 │ ├── open-sans-v17-all-charsets-700italic.woff2 │ ├── open-sans-v17-all-charsets-800italic.woff2 │ ├── source-code-pro-v11-all-charsets-500.woff2 │ ├── fonts.css │ └── SOURCE-CODE-PRO-LICENSE.txt ├── css │ └── print.css ├── mdbook-pagetoc │ ├── style.css │ └── sidebar.js ├── highlight.css └── favicon.svg ├── .github ├── ISSUE_TEMPLATE │ ├── mistake-found.md │ └── new-snippet.md └── workflows │ └── mdbook.yml ├── book.toml ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | .vscode 3 | **/typst-src 4 | **/typst-img 5 | experimental* 6 | -------------------------------------------------------------------------------- /src/snippets/index.md: -------------------------------------------------------------------------------- 1 | # Typst Snippets 2 | Useful snippets for common (and not) tasks. 3 | -------------------------------------------------------------------------------- /theme/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/favicon.png -------------------------------------------------------------------------------- /src/snippets/img/tub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/snippets/img/tub.png -------------------------------------------------------------------------------- /src/typstonomicon/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/typstonomicon/tiger.jpg -------------------------------------------------------------------------------- /src/basics/must_know/tiger.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/basics/must_know/tiger.jpg -------------------------------------------------------------------------------- /src/basics/tutorial/boxes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/basics/tutorial/boxes.png -------------------------------------------------------------------------------- /src/fonts/FiraMath-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/fonts/FiraMath-Regular.otf -------------------------------------------------------------------------------- /src/packages/img/treemap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/packages/img/treemap.png -------------------------------------------------------------------------------- /src/snippets/img/landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/snippets/img/landscape.png -------------------------------------------------------------------------------- /src/fonts/NotoSerifThai-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/src/fonts/NotoSerifThai-Regular.ttf -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-300.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-600.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-600.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-700.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-800.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-800.woff2 -------------------------------------------------------------------------------- /src/basics/scripting/index.md: -------------------------------------------------------------------------------- 1 | # Scripting 2 | **Typst** has a complete interpreted language inside. One of key aspects of working with your document in a nicer way 3 | -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-italic.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-regular.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-300italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-300italic.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-600italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-600italic.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-700italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-700italic.woff2 -------------------------------------------------------------------------------- /theme/fonts/open-sans-v17-all-charsets-800italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/open-sans-v17-all-charsets-800italic.woff2 -------------------------------------------------------------------------------- /theme/fonts/source-code-pro-v11-all-charsets-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitandr/typst-examples-book/HEAD/theme/fonts/source-code-pro-v11-all-charsets-500.woff2 -------------------------------------------------------------------------------- /src/snippets/text/individual_lang_fonts.md: -------------------------------------------------------------------------------- 1 | # Individual language fonts 2 | 3 | ```typ 4 | A cat แปลว่า แมว 5 | 6 | #show regex("\p{Thai}+"): text.with(font: "Noto Serif Thai") 7 | 8 | A cat แปลว่า แมว 9 | ``` 10 | -------------------------------------------------------------------------------- /src/basics/tutorial/cheatsheet.md: -------------------------------------------------------------------------------- 1 | # Cheatsheet 2 | 3 | Here is a brief cheetsheet for some most needed Typst concepts (by @mewmew and @7i): 4 | 5 | ![Cheatsheet](cheat-sheet.svg) 6 | 7 | [Link to repository](https://github.com/mewmew/cheat-sheet-typ) 8 | -------------------------------------------------------------------------------- /src/basics/must_know/index.md: -------------------------------------------------------------------------------- 1 | # Must-know 2 | This section contains things, that are not general enough to be part of "tutorial", but still are very important to know for proper typesetting. 3 | 4 | Feel free to skip through things you are sure you will not use. 5 | -------------------------------------------------------------------------------- /src/basics/tutorial/index.md: -------------------------------------------------------------------------------- 1 | # Tutorial by Examples 2 | The first section of Typst Basics is very similar to [Official Tutorial](https://typst.app/docs/tutorial/), with more specialized examples and less words. It is _highly recommended to read the official tutorial anyway_. 3 | -------------------------------------------------------------------------------- /src/snippets/layout/hiding.md: -------------------------------------------------------------------------------- 1 | # Hiding things 2 | 3 | ```typ 4 | // author: GeorgeMuscat 5 | #let redact(text, fill: black, height: 1em) = { 6 | box(rect(fill: fill, height: height)[#hide(text)]) 7 | } 8 | 9 | Example: 10 | - Unredacted text 11 | - Redacted #redact("text") 12 | ``` 13 | -------------------------------------------------------------------------------- /src/packages/external.md: -------------------------------------------------------------------------------- 1 | # External 2 | These are not official packages. Maybe once they will become one. 3 | 4 | However, they may be very useful. 5 | 6 | ## Treemap display 7 | [Code Link](https://gist.github.com/taylorh140/9e353fdf737f1ef51aacb332efdd9516) 8 | 9 | ![Treemap diagram](img/treemap.png) 10 | -------------------------------------------------------------------------------- /src/basics/states/metadata.md: -------------------------------------------------------------------------------- 1 | # Metadata 2 | 3 | Metadata is invisible content that can be extracted using query or other content. 4 | This may be very useful with `typst query` to pass values to external tools. 5 | 6 | ```typ 7 | // Put metadata somewhere. 8 | #metadata("This is a note") 9 | 10 | // And find it from anywhere else. 11 | #context { 12 | query().first().value 13 | } 14 | ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/mistake-found.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Mistake found 3 | about: Point a problem in example, language, rendering or anything else 4 | title: "[What mistake you've found?]" 5 | labels: mistake 6 | assignees: sitandr 7 | 8 | --- 9 | 10 | **Issue**: [what problem have you found] 11 | 12 | **Location**: [where in the book the mistake is located, attach the url and specify the example if possible] 13 | -------------------------------------------------------------------------------- /src/snippets/math/operations.md: -------------------------------------------------------------------------------- 1 | # Operations 2 | ## Fractions 3 | ```typ 4 | $ 5 | p/q, p slash q, p\/q 6 | $ 7 | ``` 8 | 9 | ### Slightly moved: 10 | ```typ 11 | #let mfrac(a, b) = move(a, dy: -0.2em) + "/" + move(b, dy: 0.2em, dx: -0.1em) 12 | $A\/B, #mfrac($A$, $B$)$, 13 | ``` 14 | 15 | ### Large fractions 16 | ```typ 17 | #let dfrac(a, b) = $display(frac(#a, #b))$ 18 | 19 | $(x + y)/(1/x + 1/y) quad (x + y)/(dfrac(1,x) + dfrac(1, y))$ 20 | ``` 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-snippet.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New snippet 3 | about: Add new snippet to the book 4 | title: "[Snippet(s) name here]" 5 | labels: new snippet 6 | assignees: sitandr 7 | 8 | --- 9 | 10 | **Location**: [where in the book should be snippet located] 11 | 12 | **Importance**: [why should it be in the book] 13 | 14 | **Snippet**: 15 | ```typ 16 | [The code there] 17 | ``` 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/snippets/layout/insert_lines.md: -------------------------------------------------------------------------------- 1 | # Lines between list items 2 | 3 | ```typ 4 | /// author: frozolotl 5 | #show enum.where(tight: false): it => { 6 | it.children 7 | .enumerate() 8 | .map(((n, item)) => block(below: .6em, above: .6em)[#numbering("1.", n + 1) #item.body]) 9 | .join(line(length: 100%)) 10 | } 11 | 12 | + Item 1 13 | 14 | + Item 2 15 | 16 | + Item 3 17 | ``` 18 | 19 | The same approach may be easily adapted to style the enums as you want. -------------------------------------------------------------------------------- /src/typstonomicon/index.md: -------------------------------------------------------------------------------- 1 | # Typstonomicon, or The Code You Should Not Write 2 | Totally cursed examples with lots of quires, measure and other things to hack around current Typst limitations. 3 | Generally you should use this code only if you really need it. 4 | 5 |
6 | Code in this chapter may break in lots of circumstances and debugging it will be very painful. You are warned. 7 |
8 | 9 | I think that this chapter will slowly die as Typst matures. 10 | -------------------------------------------------------------------------------- /src/snippets/math/fonts.md: -------------------------------------------------------------------------------- 1 | # Fonts 2 | ## Set math font 3 | **Important:** The font you want to set for math should _contain_ necessary math symbols. That should be a special font with math. If it isn't, you are very likely to get _an error_ (remember to set `fallback: false` and check `typst fonts` to debug the fonts). 4 | 5 | ```typ 6 | #show math.equation: set text(font: "Fira Math", fallback: false) 7 | 8 | $ 9 | emptyset \ 10 | 11 | integral_a^b sum (A + B)/C dif x \ 12 | $ 13 | ``` 14 | -------------------------------------------------------------------------------- /src/typstonomicon/math_display.md: -------------------------------------------------------------------------------- 1 | # Make all math display math 2 | 3 |
4 | May slightly interfere with math blocks. 5 |
6 | 7 | ```typ 8 | // author: eric1102 9 | #show math.equation: it => { 10 | if it.body.fields().at("size", default: none) != "display" { 11 | return math.display(it) 12 | } 13 | it 14 | } 15 | 16 | Inline math: $sum_(n=0)^oo e^(x^2 - n/x^2)$\ 17 | Some other text on new line. 18 | 19 | 20 | $ 21 | sum_(n=0)^oo e^(x^2 - n/x^2) 22 | $ 23 | ``` -------------------------------------------------------------------------------- /src/snippets/external.md: -------------------------------------------------------------------------------- 1 | # Use with external tools 2 | Currently the best ways to communicate is using 3 | 4 | 1. Preprocessing. The tool should generate Typst file 5 | 2. Typst Query (CLI). See the docs [there](https://typst.app/docs/reference/meta/query#command-line-queries). 6 | 3. WebAssembly plugins. See the docs [there](https://typst.app/docs/reference/foundations/plugin/). 7 | 8 | In some time there will be examples of successful usage of first two methods. For the third one, see [packages](../packages/index.md). 9 | -------------------------------------------------------------------------------- /src/snippets/dataload/file.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sn": "1", 4 | "source": "Science", 5 | "question": "What is the chemical symbol for water?", 6 | "answer": "a", 7 | "a": "H2O", 8 | "b": "CO2", 9 | "c": "O2", 10 | "d": "N2" 11 | }, 12 | { 13 | "sn": "2", 14 | "source": "History", 15 | "question": "Who was the first president of the United States?", 16 | "answer": "a", 17 | "a": "George Washington", 18 | "b": "Abraham Lincoln", 19 | "d": "John Adams" 20 | } 21 | ] -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | author = "sitandr" 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Typst Examples Book" 7 | 8 | [preprocessor.typst-highlight] 9 | #disable_inline = true 10 | typst_default = true 11 | render = true 12 | warn_not_specified = true 13 | 14 | [output.html] 15 | additional-css = ["./theme/mdbook-pagetoc/style.css"] 16 | additional-js = ["./theme/mdbook-pagetoc/sidebar.js", "./theme/popup/popup.js"] 17 | git-repository-url = "https://github.com/sitandr/typst-examples-book" 18 | 19 | [output.html.redirect] 20 | "/snippets/hidding.html" = "./hiding.html" 21 | -------------------------------------------------------------------------------- /src/snippets/math/calligraphic.md: -------------------------------------------------------------------------------- 1 | # Calligraphic letters 2 | 3 | ```typ 4 | #let scr(it) = math.class("normal", box({ 5 | show math.equation: set text(stylistic-set: 1) 6 | $cal(it)$ 7 | })) 8 | 9 | 10 | $ scr(A) scr(B) + scr(C), -scr(D) $ 11 | ``` 12 | 13 | Unfortunately, currently just `stylistic-set` for math creates bad spacing. Math engine detects if the letter should be correctly spaced by whether it is the default font. However, just making it "normal" isn't enough, because than it can be reduced. That's way the snippet is as hacky as it is (probably should be located in Typstonomicon, but it's not large enough). -------------------------------------------------------------------------------- /src/typstonomicon/inline_with.md: -------------------------------------------------------------------------------- 1 | # Horizontally align something with something 2 | ```typ 3 | // author: tabiasgeehuman 4 | #let inline-with(select, content) = context { 5 | let target = query( 6 | selector(select) 7 | ).last().location().position().x 8 | let current = here().position().x 9 | 10 | box(inset: (x: target - current + 0.3em), content) 11 | } 12 | 13 | #let inline-label(name) = [#line(length: 0%) #name] 14 | 15 | #inline-with(selector())[= Common values] 16 | #align(left, box[$ 17 | #inline-label() "Circles"(0) =& 0 \ 18 | lim_(x -> 1) "Circles"(0) =& 0 19 | $]) 20 | ``` 21 | -------------------------------------------------------------------------------- /src/basics/extra.md: -------------------------------------------------------------------------------- 1 | # Extra 2 | 3 | ## Bibliography 4 | 5 | Typst supports bibliography using BibLaTex `.bib` file or its own Hayagriva `.yml` format. 6 | 7 | BibLaTex is wider supported, but Hayagriva is easier to work with. 8 | 9 | > Link to Hayagriva [documentation](https://github.com/typst/hayagriva/blob/main/docs/file-format.md) and some [examples](https://github.com/typst/hayagriva/blob/main/tests/data/basic.yml). 10 | 11 | ### Citation Style 12 | 13 | The style can be customized via CSL, citation style language, with more than 10 000 styles available online. 14 | See [official repository](https://github.com/citation-style-language/styles). 15 | -------------------------------------------------------------------------------- /src/basics/states/index.md: -------------------------------------------------------------------------------- 1 | # States & Query 2 | 3 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
4 | 5 | Typst tries to be a _pure language_ as much as possible. 6 | 7 | That means, a function can't change anything outside of it. That also means, if you call function, the result should be always the same. 8 | 9 | Unfortunately, our world (and therefore our documents) isn't pure. 10 | If you create a heading №2, you want the next number to be three. 11 | 12 | That section will guide you to using impure Typst. Don't overuse it, as this knowledge comes close to the Dark Arts of Typst! 13 | -------------------------------------------------------------------------------- /src/snippets/math/scripts.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | > To set scripts and limits see [Typst Basics section](../../basics/math/limits.md) 4 | 5 | ## Make every character upright when used in subscript 6 | 7 | ```typ 8 | // author: emilyyyylime 9 | 10 | $f_a, f_b, f^a, f_italic("word")$ 11 | #show math.attach: it => { 12 | import math: * 13 | if it.b != none and it.b.func() != upright[].func() and it.b.has("text") and it.b.text.len() == 1 { 14 | let args = it.fields() 15 | let _ = args.remove("base") 16 | let _ = args.remove("b") 17 | attach(it.base, b: upright(it.b), ..args) 18 | } else { 19 | it 20 | } 21 | } 22 | 23 | $f_a, f_b, f^a, f_italic("word")$ 24 | ``` -------------------------------------------------------------------------------- /src/typstonomicon/try_catch.md: -------------------------------------------------------------------------------- 1 | # Try & Catch 2 | ```typ 3 | // author: laurmaedje 4 | // Renders an image or a placeholder if it doesn't exist. 5 | // Don’t try this at home, kids! 6 | #let maybe-image(path, ..args) = context { 7 | let path-label = label(path) 8 | let first-time = query((context {}).func()).len() == 0 9 | if first-time or query(path-label).len() > 0 { 10 | [#image(path, ..args)#path-label] 11 | } else { 12 | rect(width: 50%, height: 5em, fill: luma(235), stroke: 1pt)[ 13 | #set align(center + horizon) 14 | Could not find #raw(path) 15 | ] 16 | } 17 | } 18 | 19 | #maybe-image("../tiger.jpg") 20 | #maybe-image("../tiger1.jpg") 21 | ``` 22 | -------------------------------------------------------------------------------- /src/snippets/code.md: -------------------------------------------------------------------------------- 1 | # Code formatting 2 | 3 | ## Inline highlighting 4 | 5 | ```typ 6 | #let r = raw.with(lang: "r") 7 | 8 | This can then be used like: #r("x <- c(10, 42)") 9 | ``` 10 | 11 | ## Tab size 12 | 13 | ```````typ 14 | #set raw(tab-size: 8) 15 | ```tsv 16 | Year Month Day 17 | 2000 2 3 18 | 2001 2 1 19 | 2002 3 10 20 | ``` 21 | ``````` 22 | 23 | ## Theme 24 | 25 | See [reference](https://typst.app/docs/reference/text/raw/#parameters-theme) 26 | 27 | ## Enable ligatures for code 28 | 29 | ```typ 30 | #show raw: set text(ligatures: true, font: "Cascadia Code") 31 | 32 | Then the code becomes `x <- a` 33 | ``` 34 | 35 | ## Advanced formatting 36 | 37 | See [packages](../packages/code.md) section. 38 | -------------------------------------------------------------------------------- /src/typstonomicon/remove-indent-nested.md: -------------------------------------------------------------------------------- 1 | # Remove indent from nested lists 2 | 3 | ```typ 4 | // author: fenjalien 5 | #show enum.item: it => { 6 | if repr(it.body.func()) == "sequence" { 7 | let children = it.body.children 8 | let index = children.position(x => x.func() == enum.item) 9 | if index != none { 10 | enum.item({ 11 | children.slice(0, index).join() 12 | set enum(indent: -1.2em) // Note that this stops an infinitly recursive show rule 13 | children.slice(index).join() 14 | }) 15 | } else { 16 | it 17 | } 18 | } else { 19 | it 20 | } 21 | } 22 | 23 | arst 24 | + A 25 | + b 26 | + c 27 | + d 28 | + e 29 | + f 30 | + g 31 | + h 32 | + i 33 | + 34 | ``` -------------------------------------------------------------------------------- /src/snippets/chapters/page-numbering.md: -------------------------------------------------------------------------------- 1 | # Page numbering 2 | 3 | ## Separate page numbering for each chapter 4 | 5 | ```typ 6 | /// author: tinger 7 | 8 | // unnumbered title page if needed 9 | // ... 10 | 11 | // front-matter 12 | #set page(numbering: "I") 13 | #counter(page).update(1) 14 | #lorem(50) 15 | // ... 16 | 17 | // page counter anchor 18 | #metadata(()) 19 | 20 | // main document body 21 | #set page(numbering: "1") 22 | #lorem(50) 23 | #counter(page).update(1) 24 | // ... 25 | 26 | // back-matter 27 | #set page(numbering: "I") 28 | // must take page breaks into account, may need to be offset by +1 or -1 29 | #context counter(page).update(counter(page).at().first()) 30 | #lorem(50) 31 | // ... 32 | ``` 33 | -------------------------------------------------------------------------------- /src/basics/index.md: -------------------------------------------------------------------------------- 1 | # Typst Basics 2 | This is a chapter that consistently introduces you to the most things you need to know when writing with Typst. 3 | 4 | It show much more things than official tutorial, so maybe it will be interesting to read for some of the experienced users too. 5 | 6 | Some examples are taken from [Official Tutorial](https://typst.app/docs/tutorial/) and [Official Reference](https://typst.app/docs/reference/). 7 | Most are created and edited specially for this book. 8 | 9 | > _Important:_ in most cases there will be used "clipped" examples of your rendered documents (no margins, smaller width and so on). 10 | > 11 | > To set up the spacing as you want, see [Official Page Setup Guide](https://typst.app/docs/guides/page-setup-guide/). 12 | 13 | -------------------------------------------------------------------------------- /src/typstonomicon/original_image.md: -------------------------------------------------------------------------------- 1 | # Image with original size 2 | This function renders image with the size it "naturally" has. 3 | 4 | **Note: starting from v0.11**, Typst tries using default image size when width and height are `auto`. It only uses container's size if the image doesn't fit. So this code is more like a legacy, but still may be useful. 5 | 6 | This works because measure conceptually places the image onto a page with infinite size and then the image defaults to 1pt per pixel instead of becoming infinitely larger itself. 7 | 8 | ```typ 9 | // author: laurmaedje 10 | #let natural-image(..args) = style(styles => { 11 | let (width, height) = measure(image(..args), styles) 12 | image(..args, width: width, height: height) 13 | }) 14 | 15 | #image("../tiger.jpg") 16 | #natural-image("../tiger.jpg") 17 | ``` -------------------------------------------------------------------------------- /theme/css/print.css: -------------------------------------------------------------------------------- 1 | 2 | #sidebar, 3 | #menu-bar, 4 | .nav-chapters, 5 | .mobile-nav-chapters { 6 | display: none; 7 | } 8 | 9 | #page-wrapper.page-wrapper { 10 | transform: none; 11 | margin-left: 0px; 12 | overflow-y: initial; 13 | } 14 | 15 | #content { 16 | max-width: none; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | .page { 22 | overflow-y: initial; 23 | } 24 | 25 | pre > .buttons { 26 | z-index: 2; 27 | } 28 | 29 | a, a:visited, a:active, a:hover { 30 | color: #4183c4; 31 | text-decoration: none; 32 | } 33 | 34 | h1, h2, h3, h4, h5, h6 { 35 | page-break-inside: avoid; 36 | page-break-after: avoid; 37 | } 38 | 39 | pre, code { 40 | page-break-inside: avoid; 41 | white-space: pre-wrap; 42 | } 43 | 44 | .fa { 45 | display: none !important; 46 | } 47 | -------------------------------------------------------------------------------- /src/snippets/special/index.md: -------------------------------------------------------------------------------- 1 | # Special documents 2 | ## Signature places 3 | ```typ 4 | #block(width: 150pt)[ 5 | #line(length: 100%) 6 | #align(center)[Signature] 7 | ] 8 | ``` 9 | 10 | ## Presentations 11 | See [polylux](../../packages/). 12 | 13 | 14 | ## Forms 15 | ### Form with placeholder 16 | ```typ 17 | #grid( 18 | columns: 2, 19 | rows: 4, 20 | gutter: 1em, 21 | 22 | [Student:], 23 | [#block()#align(bottom)[#line(length: 10em, stroke: 0.5pt)]], 24 | [Teacher:], 25 | [#block()#align(bottom)[#line(length: 10em, stroke: 0.5pt)]], 26 | [ID:], 27 | [#block()#align(bottom)[#line(length: 10em, stroke: 0.5pt)]], 28 | [School:], 29 | [#block()#align(bottom)[#line(length: 10em, stroke: 0.5pt)]], 30 | ) 31 | ``` 32 | 33 | ### Interactive 34 | > Presentation interactive forms are coming! They are currently under heavy work by @tinger. 35 | -------------------------------------------------------------------------------- /src/packages/headers.md: -------------------------------------------------------------------------------- 1 | # Headers 2 | 3 | ## `hydra`: Contextual headers 4 | 5 | We have discussed in `Typst Basics` how to get current heading with `query(selector(heading).before(here()))` for headers. However, this works badly for nested headings with numbering and similar things. For these cases there is `hydra`: 6 | 7 | ```typ 8 | #import "@preview/hydra:0.6.1": hydra 9 | 10 | #set page(height: 10 * 20pt, margin: (y: 4em), numbering: "1", header: context { 11 | if calc.odd(here().page()) { 12 | align(right, emph(hydra(1))) 13 | } else { 14 | align(left, emph(hydra(2))) 15 | } 16 | line(length: 100%) 17 | }) 18 | #set heading(numbering: "1.1") 19 | #show heading.where(level: 1): it => pagebreak(weak: true) + it 20 | 21 | = Introduction 22 | #lorem(50) 23 | 24 | = Content 25 | == First Section 26 | #lorem(50) 27 | == Second Section 28 | #lorem(100) 29 | ``` 30 | -------------------------------------------------------------------------------- /src/snippets/labels.md: -------------------------------------------------------------------------------- 1 | # Labels 2 | ## Get chapter of label 3 | ```typ 4 | #let ref-heading(label) = context { 5 | let elems = query(label) 6 | if elems.len() != 1 { 7 | panic("found multiple elements") 8 | } 9 | let element = elems.first() 10 | if element.func() != heading { 11 | panic("label must target heading") 12 | } 13 | link(label, element.body) 14 | } 15 | 16 | = Design 17 | #lorem(20) 18 | 19 | = Implementation 20 | In #ref-heading(), we discussed... 21 | ``` 22 | 23 | ## Allow missing references 24 | 25 | ```typ 26 | // author: Enivex 27 | #set heading(numbering: "1.") 28 | 29 | #let myref(label) = context { 30 | if query(label).len() != 0 { 31 | ref(label) 32 | } else { 33 | // missing reference 34 | text(fill: red)[???] 35 | } 36 | } 37 | 38 | = Second 39 | 40 | #myref() 41 | 42 | #myref() 43 | ``` 44 | -------------------------------------------------------------------------------- /src/packages/wrapping.md: -------------------------------------------------------------------------------- 1 | # Wrapping figures 2 | 3 | The better native support for wrapping is planned, however, something is already possible via package: 4 | 5 | ```typ 6 | #import "@preview/wrap-it:0.1.1": wrap-content, wrap-top-bottom 7 | 8 | #set par(justify: true) 9 | #let fig = figure( 10 | rect(fill: teal, radius: 0.5em, width: 8em), 11 | caption: [A figure], 12 | ) 13 | #let body = lorem(40) 14 | #wrap-content(fig, body) 15 | 16 | #wrap-content( 17 | fig, 18 | body, 19 | align: bottom + right, 20 | column-gutter: 2em 21 | ) 22 | 23 | #let boxed = box(fig, inset: 0.5em) 24 | #wrap-content(boxed)[ 25 | #lorem(40) 26 | ] 27 | 28 | #let fig2 = figure( 29 | rect(fill: lime, radius: 0.5em), 30 | caption: [Another figure], 31 | ) 32 | #wrap-top-bottom(boxed, fig2, lorem(60)) 33 | ``` 34 | 35 |
Limitations: non-ideal spacing near warping, only top-bottom left/right are supported.
-------------------------------------------------------------------------------- /src/snippets/text/line_indent.md: -------------------------------------------------------------------------------- 1 | # First line indent 2 | 3 | [Official docs](https://typst.app/docs/reference/model/par/#parameters-first-line-indent) 4 | 5 | A very common need in terms of text formatting is adding indent to first line of all paragraph. That is known as pilcrow (¶) or "red line" in some languages or conventions. 6 | 7 | By default, Typst applies it to all paragraphs _except the first_ (or one coming after title). To change it, use (all: true): 8 | 9 | ```typ 10 | #set block(spacing: 1.2em) 11 | #set par( 12 | first-line-indent: 1.5em, 13 | spacing: 0.65em, 14 | ) 15 | 16 | The first paragraph is not affected 17 | by the indent. 18 | 19 | But the second paragraph is. 20 | 21 | #line(length: 100%) 22 | 23 | #set par(first-line-indent: ( 24 | amount: 1.5em, 25 | all: true, 26 | )) 27 | 28 | Now all paragraphs are affected 29 | by the first line indent. 30 | 31 | Even the first one. 32 | ``` 33 | -------------------------------------------------------------------------------- /src/basics/math/classes.md: -------------------------------------------------------------------------------- 1 | # Classes 2 | 3 | > See [official documentation](https://typst.app/docs/reference/math/class/) 4 | 5 | Each math symbol has its own "class", the way it behaves. That's one of the main reasons why they are layouted differently. 6 | 7 | ## Classes 8 | 9 | ```typ 10 | $ 11 | a b c\ 12 | a class("normal", b) c\ 13 | a class("punctuation", b) c\ 14 | a class("opening", b) c\ 15 | a lr(b c]) c\ 16 | a lr(class("opening", b) c ]) c\ // notice it is moved vertically 17 | a class("closing", b) c\ 18 | a class("fence", b) c\ 19 | a class("large", b) c\ 20 | a class("relation", b) c\ 21 | a class("unary", b) c\ 22 | a class("binary", b) c\ 23 | a class("vary", b) c\ 24 | $ 25 | ``` 26 | 27 | ## Setting class for symbol 28 | 29 | ```typ 30 | Default: 31 | 32 | $square circle square$ 33 | 34 | With `#h(0)`: 35 | 36 | $square #h(0pt) circle #h(0pt) square$ 37 | 38 | With `math.class`: 39 | 40 | #show math.circle: math.class.with("normal") 41 | $square circle square$ 42 | ``` 43 | -------------------------------------------------------------------------------- /src/packages/code.md: -------------------------------------------------------------------------------- 1 | # Code 2 | 3 | ## `codly` 4 | 5 | > See docs [there](https://github.com/Dherse/codly) 6 | 7 | ``````typ 8 | #import "@preview/codly:0.1.0": codly-init, codly, disable-codly 9 | #show: codly-init.with() 10 | 11 | #codly(languages: ( 12 | typst: (name: "Typst", color: rgb("#41A241"), icon: none), 13 | ), 14 | breakable: false 15 | ) 16 | 17 | ```typst 18 | #import "@preview/codly:0.1.0": codly-init 19 | #show: codly-init.with() 20 | ``` 21 | 22 | // Still formatted! 23 | ```rust 24 | pub fn main() { 25 | println!("Hello, world!"); 26 | } 27 | ``` 28 | 29 | #disable-codly() 30 | `````` 31 | 32 | ## Codelst 33 | 34 | ``````typ 35 | #import "@preview/codelst:2.0.0": sourcecode 36 | 37 | #sourcecode[```typ 38 | #show "ArtosFlow": name => box[ 39 | #box(image( 40 | "logo.svg", 41 | height: 0.7em, 42 | )) 43 | #name 44 | ] 45 | 46 | This report is embedded in the 47 | ArtosFlow project. ArtosFlow is a 48 | project of the Artos Institute. 49 | ```] 50 | `````` -------------------------------------------------------------------------------- /src/snippets/layout/multiline_detect.md: -------------------------------------------------------------------------------- 1 | # Multiline detection 2 | 3 | Detects if figure caption (may be any other element) _has more than one line_. 4 | 5 | If the caption is multiline, it makes it left-aligned. 6 | 7 |
8 | Breaks on manual linebreaks. 9 |
10 | 11 | `````typ 12 | #show figure.caption: it => { 13 | layout(size => context [ 14 | #let text-size = measure( 15 | ..size, 16 | it.supplement + it.separator + it.body, 17 | ) 18 | 19 | #let my-align 20 | 21 | #if text-size.width < size.width { 22 | my-align = center 23 | } else { 24 | my-align = left 25 | } 26 | 27 | #align(my-align, it) 28 | ]) 29 | } 30 | 31 | #figure(caption: lorem(6))[ 32 | ```rust 33 | pub fn main() { 34 | println!("Hello, world!"); 35 | } 36 | ``` 37 | ] 38 | 39 | #figure(caption: lorem(20))[ 40 | ```rust 41 | pub fn main() { 42 | println!("Hello, world!"); 43 | } 44 | ``` 45 | ] 46 | ````` 47 | -------------------------------------------------------------------------------- /src/basics/scripting/tips.md: -------------------------------------------------------------------------------- 1 | # Tips 2 | 3 | There are lots of elements in Typst scripting that are not obvious, but important. All the book is designated to show them, but some of them 4 | 5 | ## Equality 6 | 7 | Equality doesn't mean objects are really the same, like in many other objects: 8 | 9 | ```typ 10 | #let a = 7 11 | #let b = 7.0 12 | #(a == b) 13 | #(type(a) == type(b)) 14 | ``` 15 | 16 | That may be less obvious for dictionaries. In dictionaries **the order may matter**, so equality doesn't mean they behave exactly the same way: 17 | 18 | ```typ 19 | #let a = (x: 1, y: 2) 20 | #let b = (y: 2, x: 1) 21 | #(a == b) 22 | #(a.pairs() == b.pairs()) 23 | ``` 24 | 25 | ## Check key is in dictionary 26 | 27 | Use the keyword `in`, like in `Python`: 28 | 29 | ```typ 30 | #let dict = (a: 1, b: 2) 31 | 32 | #("a" in dict) 33 | // gives the same as 34 | #(dict.keys().contains("a")) 35 | ``` 36 | 37 | Note it works for lists too: 38 | 39 | ```typ 40 | #("a" in ("b", "c", "a")) 41 | #(("b", "c", "a").contains("a")) 42 | ``` -------------------------------------------------------------------------------- /src/snippets/gradients.md: -------------------------------------------------------------------------------- 1 | # Color & Gradients 2 | 3 | ## Gradients 4 | 5 | Gradients may be very cool for presentations or just a pretty look. 6 | 7 | ```typ 8 | /// author: frozolotl 9 | #set page(paper: "presentation-16-9", margin: 0pt) 10 | #set text(fill: white, font: "Inter") 11 | 12 | #let grad = gradient.linear(rgb("#953afa"), rgb("#c61a22"), angle: 135deg) 13 | 14 | #place(horizon + left, image(width: 60%, "../img/landscape.png")) 15 | 16 | #place(top, polygon( 17 | (0%, 0%), 18 | (70%, 0%), 19 | (70%, 25%), 20 | (0%, 29%), 21 | fill: white, 22 | )) 23 | #place(bottom, polygon( 24 | (0%, 100%), 25 | (100%, 100%), 26 | (100%, 30%), 27 | (60%, 30% + 60% * 4%), 28 | (60%, 60%), 29 | (0%, 64%), 30 | fill: grad, 31 | )) 32 | 33 | #place(top + right, block(inset: 7pt, image(height: 19%, "../img/tub.png"))) 34 | 35 | #place(bottom, block(inset: 40pt)[ 36 | #text(size: 30pt)[ 37 | Presentation Title 38 | ] 39 | 40 | #text(size: 16pt)[#lorem(20) | #datetime.today().display()] 41 | ]) 42 | ``` -------------------------------------------------------------------------------- /src/snippets/text/text_shadows.md: -------------------------------------------------------------------------------- 1 | # Fake italic & Text shadows 2 | 3 | ## Skew 4 | 5 | ```typ 6 | // author: Enivex 7 | #set page(width: 21cm, height: 3cm) 8 | #set text(size:25pt) 9 | #let skew(angle,vscale: 1,body) = { 10 | let (a,b,c,d)= (1,vscale*calc.tan(angle),0,vscale) 11 | let E = (a + d)/2 12 | let F = (a - d)/2 13 | let G = (b + c)/2 14 | let H = (c - b)/2 15 | let Q = calc.sqrt(E*E + H*H) 16 | let R = calc.sqrt(F*F + G*G) 17 | let sx = Q + R 18 | let sy = Q - R 19 | let a1 = calc.atan2(F,G) 20 | let a2 = calc.atan2(E,H) 21 | let theta = (a2 - a1) /2 22 | let phi = (a2 + a1)/2 23 | 24 | set rotate(origin: bottom+center) 25 | set scale(origin: bottom+center) 26 | 27 | rotate(phi,scale(x: sx*100%, y: sy*100%,rotate(theta,body))) 28 | } 29 | 30 | #let fake-italic(body) = skew(-12deg,body) 31 | #fake-italic[This is fake italic text] 32 | 33 | #let shadowed(body) = box(place(skew(-50deg, vscale: 0.8, text(fill:luma(200),body)))+place(body)) 34 | #shadowed[This is some fancy text with a shadow] 35 | ``` -------------------------------------------------------------------------------- /src/basics/math/grouping.md: -------------------------------------------------------------------------------- 1 | # Grouping 2 | 3 | Every grouping can be (currently) done by parenthesis. 4 | So the parenthesis may be both "real" parenthesis and grouping ones. 5 | 6 | For example, these parentheses specify nominator of the fraction: 7 | 8 | ```typ 9 | $ (a^2 + b^2)/2 $ 10 | ``` 11 | 12 | ## Left-right 13 | > See [official documentation](https://typst.app/docs/reference/math/lr). 14 | 15 | If there are two matching braces of any kind, they will be wrapped as `lr` (left-right) group. 16 | 17 | ```typ 18 | $ 19 | {[((a + b)/2) + 1]_0} 20 | $ 21 | ``` 22 | 23 | You can disable it by escaping. 24 | 25 | You can also match braces of any kind by using `lr` directly: 26 | 27 | ```typ 28 | $ 29 | lr([a/2, b)) \ 30 | lr([a/2, b), size: #150%) 31 | $ 32 | ``` 33 | 34 | ## Fences 35 | 36 | Fences _are not matched automatically_ because of large amount of false-positives. 37 | 38 | You can use `abs` or `norm` to match them: 39 | 40 | ```typ 41 | $ 42 | abs(a + b), norm(a + b), floor(a + b), ceil(a + b), round(a + b) 43 | $ 44 | ``` -------------------------------------------------------------------------------- /src/packages/word_count.md: -------------------------------------------------------------------------------- 1 | # Counting words 2 | 3 | ## Wordometr 4 | 5 | ```typ 6 | #import "@preview/wordometer:0.1.4": word-count, total-words 7 | 8 | #show: word-count 9 | 10 | In this document, there are #total-words words all up. 11 | 12 | #word-count(total => [ 13 | The number of words in this block is #total.words 14 | and there are #total.characters letters. 15 | ]) 16 | ``` 17 | 18 | ### Excluding elements 19 | You can exclude elements by name (e.g., `"caption"`), function (e.g., `figure.caption`), where-selector (e.g., `raw.where(block: true)`), or `label` (e.g., ``). 20 | 21 | ```typ 22 | #import "@preview/wordometer:0.1.4": word-count, total-words 23 | 24 | #show: word-count.with(exclude: (heading.where(level: 1), strike)) 25 | 26 | = This Heading Doesn't Count 27 | == But I do! 28 | 29 | In this document #strike[(excluding me)], there are #total-words words all up. 30 | 31 | #word-count(total => [ 32 | You can exclude elements by label, too. 33 | #[That was #total-words, excluding this sentence!] 34 | ], exclude: ) 35 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 sitandr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/basics/math/alignment.md: -------------------------------------------------------------------------------- 1 | # Alignment 2 | 3 | ## General alignment 4 | 5 | By default display math is center-aligned, but that can be set up with `show` rule: 6 | 7 | ```typ 8 | #show math.equation: set align(right) 9 | 10 | $ 11 | (a + b)/2 12 | $ 13 | ``` 14 | 15 | Or using `align` element: 16 | 17 | ```typ 18 | #align(left, block($ x = 5 $)) 19 | ``` 20 | 21 | ## Alignment points 22 | 23 | When equations include multiple alignment points (&), this creates blocks of alternatingly _right-_ and _left-_ aligned columns. 24 | 25 | In the example below, the expression `(3x + y) / 7` is _right-aligned_ and `= 9` is _left-aligned_. 26 | 27 | ```typ 28 | $ (3x + y) / 7 &= 9 && "given" \ 29 | 3x + y &= 63 & "multiply by 7" \ 30 | 3x &= 63 - y && "subtract y" \ 31 | x &= 21 - y/3 & "divide by 3" $ 32 | ``` 33 | 34 | The word "given" is also left-aligned because `&&` creates two alignment points in a row, _alternating the alignment twice_. 35 | 36 | `& &` and `&&` behave exactly the same way. 37 | Meanwhile, "multiply by 7" is left-aligned because just one `&` precedes it. 38 | 39 | **Each alignment point simply alternates between right-aligned/left-aligned.** -------------------------------------------------------------------------------- /src/basics/math/sizes.md: -------------------------------------------------------------------------------- 1 | # Location and sizes 2 | 3 | We talked already about display and inline math. 4 | They differ not only by aligning and spacing, but also by size and style: 5 | 6 | ```typ 7 | Inline: $a/(b + 1/c), sum_(n=0)^3 x_n$ 8 | 9 | $ 10 | a/(b + 1/c), sum_(n=0)^3 x_n 11 | $ 12 | ``` 13 | 14 | The size and style of current environment is described by Math Size, see [reference](https://typst.app/docs/reference/math/sizes). 15 | 16 | There are for sizes: 17 | 18 | - Display math size (`display`) 19 | - Inline math size (`inline`) 20 | - Script math size (`script`) 21 | - Sub/super script math size (`sscript`) 22 | 23 | Each time thing is used in fraction, script or exponent, it is moved several "levels lowers", becoming smaller and more "crapping". `sscript` isn't reduced father: 24 | 25 | ```typ 26 | $ 27 | "display:" 1/("inline:" a + 1/("script:" b + 1/("sscript:" c + 1/("sscript:" d + 1/("sscript:" e + 1/f))))) 28 | $ 29 | ``` 30 | 31 | ## Setting sizes manually 32 | 33 | Just use the corresponding command: 34 | 35 | ```typ 36 | Inine: $sum_0^oo e^x^a$\ 37 | Inline with limits: $limits(sum)_0^oo e^x^a$\ 38 | Inline, but like true display: $display(sum_0^oo e^x^a)$ 39 | ``` 40 | -------------------------------------------------------------------------------- /src/snippets/dataload/json.md: -------------------------------------------------------------------------------- 1 | # JSON 2 | 3 | `author: MuhammadAly11` 4 | 5 | Here's an example of how you could import and use json array form json file. 6 | 7 | Consider the following example of data for the test you want to write: 8 | 9 | ```json 10 | [ 11 | { 12 | "sn": "1", 13 | "source": "Science", 14 | "question": "What is the chemical symbol for water?", 15 | "answer": "a", 16 | "a": "H₂O", 17 | "b": "CO₂", 18 | "c": "O₂", 19 | "d": "N₂", 20 | }, 21 | { 22 | "sn": "2", 23 | "source": "History", 24 | "question": "Who was the first president of the United States?", 25 | "answer": "a", 26 | "a": "George Washington", 27 | "b": "Abraham Lincoln", 28 | "d": "John Adams", 29 | } 30 | ] 31 | ``` 32 | 33 | You can import this file and use it in Typst: 34 | 35 | ```typ 36 | #let json_data = json("../file.json") 37 | 38 | #for mcq in json_data { 39 | [== #mcq.sn. #mcq.question: ] 40 | for opt in ("a", "b", "c", "d", "e", "f", "g") { 41 | if opt in mcq and mcq.at(opt) != "" { 42 | [- #opt) #mcq.at(opt)] 43 | } 44 | } 45 | } 46 | ``` 47 | -------------------------------------------------------------------------------- /src/typstonomicon/multiple-show.md: -------------------------------------------------------------------------------- 1 | ## Multiple show rules 2 | 3 | Sometimes there is a need to apply several rules that look very similar. Or generate them from code. One of the ways to deal with this, the most cursed one, is this: 4 | 5 | ```typ 6 | #let rules = (math.sum, math.product, math.root) 7 | 8 | #let apply-rules(rules, it) = { 9 | if rules.len() == 0 { 10 | return it 11 | } 12 | show rules.pop(): math.display 13 | apply-rules(rules, it) 14 | } 15 | 16 | $product/sum root(3, x)/2$ 17 | 18 | #show: apply-rules.with(rules) 19 | 20 | $product/sum root(3, x)/2$ 21 | ``` 22 | 23 | The recursion problem may be avoided with the power of `fold`, with basically the same idea: 24 | 25 | ```typ 26 | // author: Eric 27 | #let kind_supp = (code: "Listing", algo: "Algorithme") 28 | #show: it => kind_supp.pairs().fold(it, (acc, (kind, supp)) => { 29 | show figure.where(kind: kind): set figure(supplement: supp) 30 | acc 31 | }) 32 | ``` 33 | 34 | Note that just in case of symbols (if you don't need element functions), one can use regular expressions. That is a more robust way: 35 | 36 | ```typ 37 | #show regex("[" + math.product + math.sum + "]"): math.display 38 | 39 | $product/sum root(3, x)/2$ 40 | ``` -------------------------------------------------------------------------------- /src/basics/scripting/basics.md: -------------------------------------------------------------------------------- 1 | # Basics 2 | ## Variables I 3 | Let's start with _variables_. 4 | 5 | The concept is very simple, just some value you can reuse: 6 | ```typ 7 | #let author = "John Doe" 8 | 9 | This is a book by #author. #author is a great guy. 10 | 11 | #quote(block: true, attribution: author)[ 12 | \ 13 | ] 14 | ``` 15 | 16 | ## Variables II 17 | You can store _any_ Typst value in variable: 18 | 19 | ```typ 20 | #let block_text = block(stroke: red, inset: 1em)[Text] 21 | 22 | #block_text 23 | 24 | #figure(caption: "The block", block_text) 25 | ``` 26 | 27 | ## Functions 28 | We have already seen some "custom" functions 29 | in [Advanced Styling](../tutorial/advanced_styling.md) chapter. 30 | 31 | Functions are values that take some values 32 | and output some values: 33 | 34 | ```typ 35 | // This is a syntax that we have seen earlier 36 | #let f = (name) => "Hello, " + name 37 | 38 | #f("world!") 39 | ``` 40 | 41 | ### Alternative syntax 42 | You can write the same shorter: 43 | 44 | ```typ 45 | // The following syntaxes are equivalent 46 | #let f = (name) => "Hello, " + name 47 | #let f(name) = "Hello, " + name 48 | 49 | #f("world!") 50 | ``` 51 | -------------------------------------------------------------------------------- /src/basics/math/limits.md: -------------------------------------------------------------------------------- 1 | # Setting limits 2 | 3 | Sometimes we want to change how the default attaching should work. 4 | 5 | ## Limits 6 | For example, in many countries it is common to write definite integrals with limits below and above. 7 | To set this, use `limits` function: 8 | 9 | ```typ 10 | $ 11 | integral_a^b\ 12 | limits(integral)_a^b 13 | $ 14 | ``` 15 | 16 | You can set this by default using `show` rule: 17 | 18 | ```typ 19 | #show math.integral: math.limits 20 | 21 | $ 22 | integral_a^b 23 | $ 24 | 25 | This is inline equation: $integral_a^b$ 26 | ``` 27 | 28 | ## Only display mode 29 | 30 | Notice that this will also affect inline equations. To enable limits for display math only, use `limits(inline: false)`: 31 | 32 | ```typ 33 | #show math.integral: math.limits.with(inline: false) 34 | 35 | $ 36 | integral_a^b 37 | $ 38 | 39 | This is inline equation: $integral_a^b$. 40 | ``` 41 | 42 | Of course, it is possible to move them back as bottom attachments: 43 | 44 | ```typ 45 | $ 46 | sum_a^b, scripts(sum)_a^b 47 | $ 48 | ``` 49 | 50 | 51 | ## Operations 52 | 53 | The same scheme works for operations. By default, they are attached to the bottom and top: 54 | 55 | ```typ 56 | $a =_"By lemme 1" b, a scripts(=)_+ b$ 57 | ``` 58 | -------------------------------------------------------------------------------- /src/snippets/layout/page_setup.md: -------------------------------------------------------------------------------- 1 | # Page setup 2 | 3 | > See [Official Page Setup guide](https://typst.app/docs/guides/page-setup-guide/) 4 | 5 | 6 | ```typ 7 | #set page( 8 | width: 3cm, 9 | margin: (x: 0cm), 10 | ) 11 | 12 | #for i in range(3) { 13 | box(square(width: 1cm)) 14 | } 15 | ``` 16 | 17 | ```typ 18 | #set page(columns: 2, height: 4.8cm) 19 | Climate change is one of the most 20 | pressing issues of our time, with 21 | the potential to devastate 22 | communities, ecosystems, and 23 | economies around the world. It's 24 | clear that we need to take urgent 25 | action to reduce our carbon 26 | emissions and mitigate the impacts 27 | of a rapidly changing climate. 28 | ``` 29 | 30 | ```typ 31 | #set page(fill: rgb("444352")) 32 | #set text(fill: rgb("fdfdfd")) 33 | *Dark mode enabled.* 34 | ``` 35 | 36 | ```typ 37 | #set par(justify: true) 38 | #set page( 39 | margin: (top: 32pt, bottom: 20pt), 40 | header: [ 41 | #set text(8pt) 42 | #smallcaps[Typst Academcy] 43 | #h(1fr) _Exercise Sheet 3_ 44 | ], 45 | ) 46 | 47 | #lorem(19) 48 | ``` 49 | 50 | ```typ 51 | #set page(foreground: text(24pt)[🥸]) 52 | 53 | Reviewer 2 has marked our paper 54 | "Weak Reject" because they did 55 | not understand our approach... 56 | ``` -------------------------------------------------------------------------------- /src/snippets/pretty.md: -------------------------------------------------------------------------------- 1 | # Pretty things 2 | ## Set bar to the text's left 3 | (also known as quote formatting) 4 | 5 | ```typ 6 | #let line-block = rect.with(fill: luma(240), stroke: (left: 0.25em)) 7 | 8 | + #lorem(10) \ 9 | #line-block[ 10 | *Solution:* #lorem(10) 11 | 12 | $ a_(n+1)x^n = 2... $ 13 | ] 14 | ``` 15 | 16 | ## Text on box top 17 | ```typ 18 | // author: gaiajack 19 | #let todo(body) = block( 20 | above: 2em, stroke: 0.5pt + red, 21 | width: 100%, inset: 14pt 22 | )[ 23 | #set text(font: "Noto Sans", fill: red) 24 | #place( 25 | top + left, 26 | dy: -6pt - 14pt, // Account for inset of block 27 | dx: 6pt - 14pt, 28 | block(fill: white, inset: 2pt)[*DRAFT*] 29 | ) 30 | #body 31 | ] 32 | 33 | #todo(lorem(100)) 34 | ``` 35 | 36 | ## Book Ornament 37 | 38 | ```typ 39 | // author: thevec 40 | 41 | #let parSepOrnament = [\ \ #h(1fr) $#line(start:(0em,-.15em), end:(12em,-.15em), stroke: (cap: "round", paint:gradient.linear(white,black,white))) #move(dx:.5em,dy:0em,"🙠")#text(15pt)[🙣] #h(0.4em) #move(dy:-0.25em,text(12pt)[✢]) #h(0.4em) #text(15pt)[🙡]#move(dx:-.5em,dy:0em,"🙢") #line(start:(0em,-.15em), end:(12em,-.15em), stroke: (cap: "round", paint:gradient.linear(white,black,white)))$ #h(1fr)\ \ ]; 42 | 43 | #lorem(30) 44 | #parSepOrnament 45 | #lorem(30) 46 | ``` 47 | -------------------------------------------------------------------------------- /theme/mdbook-pagetoc/style.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width:1439px) { 2 | .sidetoc { 3 | display: none; 4 | } 5 | } 6 | 7 | @media only screen and (min-width:1440px) { 8 | main { 9 | position: relative; 10 | } 11 | .sidetoc { 12 | margin-left: auto; 13 | margin-right: auto; 14 | left: calc(100% + (var(--content-max-width))/4 - 140px); 15 | position: absolute; 16 | } 17 | .pagetoc { 18 | position: fixed; 19 | width: 200px; 20 | height: calc(100vh - var(--menu-bar-height) - 0.67em * 4); 21 | overflow: auto; 22 | } 23 | .pagetoc a { 24 | border-left: 1px solid var(--sidebar-bg); 25 | color: var(--fg) !important; 26 | display: block; 27 | padding-bottom: 5px; 28 | padding-top: 5px; 29 | padding-left: 10px; 30 | text-align: left; 31 | text-decoration: none; 32 | } 33 | .pagetoc a:hover, 34 | .pagetoc a.active { 35 | background: var(--sidebar-bg); 36 | color: var(--sidebar-fg) !important; 37 | } 38 | .pagetoc .active { 39 | background: var(--sidebar-bg); 40 | color: var(--sidebar-fg); 41 | } 42 | } 43 | 44 | @media print { 45 | .sidetoc { 46 | display: none; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/basics/must_know/box_block.md: -------------------------------------------------------------------------------- 1 | # Boxing & Blocking 2 | ```typ 3 | You can use boxes to wrap anything 4 | into text: #box(image("../tiger.jpg", height: 2em)). 5 | 6 | Blocks will always be "separate paragraphs". 7 | They will not fit into a text: #block(image("../tiger.jpg", height: 2em)) 8 | ``` 9 | 10 | Both have similar useful properties: 11 | ```typ 12 | #box(stroke: red, inset: 1em)[Box text] 13 | #block(stroke: red, inset: 1em)[Block text] 14 | ``` 15 | 16 | ## `rect` 17 | There is also `rect` that works like `block`, but has useful default inset and stroke: 18 | ```typ 19 | #rect[Block text] 20 | ``` 21 | 22 | ## Figures 23 | 24 | For the purposes of adding a _figure_ to your document, use `figure` function. Don't try to use boxes or blocks there. 25 | 26 | Figures are that things like centered images (probably with captions), tables, even code. 27 | 28 | 29 | ```typ 30 | @tiger shows a tiger. Tigers 31 | are animals. 32 | 33 | #figure( 34 | image("../tiger.jpg", width: 80%), 35 | caption: [A tiger.], 36 | ) 37 | ``` 38 | 39 | In fact, you can put there anything you want: 40 | 41 | ```typ 42 | They told me to write a letter to you. Here it is: 43 | 44 | #figure( 45 | text(size: 5em)[I], 46 | caption: [I'm cool, right?], 47 | ) 48 | ``` 49 | 50 | -------------------------------------------------------------------------------- /theme/highlight.css: -------------------------------------------------------------------------------- 1 | /* 2 | * An increased contrast highlighting scheme loosely based on the 3 | * "Base16 Atelier Dune Light" theme by Bram de Haan 4 | * (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) 5 | * Original Base16 color scheme by Chris Kempson 6 | * (https://github.com/chriskempson/base16) 7 | */ 8 | 9 | /* Comment */ 10 | .hljs-comment, 11 | .hljs-quote { 12 | color: #575757; 13 | } 14 | 15 | /* Red */ 16 | .hljs-variable, 17 | .hljs-template-variable, 18 | .hljs-attribute, 19 | .hljs-tag, 20 | .hljs-name, 21 | .hljs-regexp, 22 | .hljs-link, 23 | .hljs-name, 24 | .hljs-selector-id, 25 | .hljs-selector-class { 26 | color: #d70025; 27 | } 28 | 29 | /* Orange */ 30 | .hljs-number, 31 | .hljs-meta, 32 | .hljs-built_in, 33 | .hljs-builtin-name, 34 | .hljs-literal, 35 | .hljs-type, 36 | .hljs-params { 37 | color: #b21e00; 38 | } 39 | 40 | /* Green */ 41 | .hljs-string, 42 | .hljs-symbol, 43 | .hljs-bullet { 44 | color: #008200; 45 | } 46 | 47 | /* Blue */ 48 | .hljs-title, 49 | .hljs-section { 50 | color: #0030f2; 51 | } 52 | 53 | /* Purple */ 54 | .hljs-keyword, 55 | .hljs-selector-tag { 56 | color: #9d00ec; 57 | } 58 | 59 | .hljs { 60 | display: block; 61 | overflow-x: auto; 62 | background: #f6f7f6; 63 | color: #000; 64 | } 65 | 66 | .hljs-emphasis { 67 | font-style: italic; 68 | } 69 | 70 | .hljs-strong { 71 | font-weight: bold; 72 | } 73 | 74 | .hljs-addition { 75 | color: #22863a; 76 | background-color: #f0fff4; 77 | } 78 | 79 | .hljs-deletion { 80 | color: #b31d28; 81 | background-color: #ffeef0; 82 | } 83 | -------------------------------------------------------------------------------- /src/basics/scripting/arguments.md: -------------------------------------------------------------------------------- 1 | # Advanced arguments 2 | ## Spreading arguments from list 3 | 4 | Spreading operator allows you to "unpack" the list of values into arguments of function: 5 | 6 | ```typ 7 | #let func(a, b, c, d, e) = [#a #b #c #d #e] 8 | #func(..(([hi],) * 5)) 9 | ``` 10 | 11 | This may be super useful in tables: 12 | 13 | ```typ 14 | #let a = ("hi", "b", "c") 15 | 16 | #table(columns: 3, 17 | [test], [x], [hello], 18 | ..a 19 | ) 20 | ``` 21 | 22 | ## Key arguments 23 | 24 | The same idea works with key arguments: 25 | 26 | ```typ 27 | #let text-params = (fill: blue, size: 0.8em) 28 | 29 | Some #text(..text-params)[text]. 30 | ``` 31 | 32 | # Managing arbitrary arguments 33 | 34 | Typst allows taking as many arbitrary positional and key arguments as you want. 35 | 36 | In that case function is given special `arguments` object that stores in it 37 | positional and named arguments. 38 | 39 | > Link to [reference](https://typst.app/docs/reference/foundations/arguments/) 40 | 41 | ```typ 42 | #let f(..args) = [ 43 | #args.pos()\ 44 | #args.named() 45 | ] 46 | 47 | #f(1, "a", width: 50%, block: false) 48 | ``` 49 | 50 | You can combine them with other arguments. Spreading operator will "eat" all remaining arguments: 51 | 52 | ```typ 53 | #let format(title, ..authors) = { 54 | let by = authors 55 | .pos() 56 | .join(", ", last: " and ") 57 | 58 | [*#title* \ _Written by #by;_] 59 | } 60 | 61 | #format("ArtosFlow", "Jane", "Joe") 62 | ``` 63 | 64 | ## Optional argument 65 | 66 | _Currently the only way in Typst to create optional positional arguments is using `arguments` object:_ 67 | 68 | TODO 69 | -------------------------------------------------------------------------------- /src/packages/presentation.md: -------------------------------------------------------------------------------- 1 | # Presentations 2 | ## Polylux 3 | 4 | > See [polylux book](https://polylux.dev/book/) 5 | 6 | ```typ 7 | // Get Polylux from the official package repository 8 | #import "@preview/polylux:0.3.1": * 9 | 10 | // Make the paper dimensions fit for a presentation and the text larger 11 | #set page(paper: "presentation-16-9") 12 | #set text(size: 25pt) 13 | 14 | // Use #polylux-slide to create a slide and style it using your favourite Typst functions 15 | #polylux-slide[ 16 | #align(horizon + center)[ 17 | = Very minimalist slides 18 | 19 | A lazy author 20 | 21 | July 23, 2023 22 | ] 23 | ] 24 | 25 | #polylux-slide[ 26 | == First slide 27 | 28 | Some static text on this slide. 29 | ] 30 | 31 | #polylux-slide[ 32 | == This slide changes! 33 | 34 | You can always see this. 35 | // Make use of features like #uncover, #only, and others to create dynamic content 36 | #uncover(2)[But this appears later!] 37 | ] 38 | ``` 39 | 40 | ## Slydst 41 | > See the documentation [there](https://github.com/glambrechts/slydst?ysclid=lr2gszrkck541184604). 42 | 43 | Much more simpler and less powerful than polulyx: 44 | 45 | ```typ 46 | #import "@preview/slydst:0.1.0": * 47 | 48 | #show: slides.with( 49 | title: "Insert your title here", // Required 50 | subtitle: none, 51 | date: none, 52 | authors: (), 53 | layout: "medium", 54 | title-color: none, 55 | ) 56 | 57 | == Outline 58 | 59 | #outline() 60 | 61 | = First section 62 | 63 | == First slide 64 | 65 | #figure(rect(width: 60%), caption: "Caption") 66 | 67 | #v(1fr) 68 | 69 | #lorem(20) 70 | 71 | #definition(title: "An interesting definition")[ 72 | #lorem(20) 73 | ] 74 | ``` -------------------------------------------------------------------------------- /src/basics/math/operators.md: -------------------------------------------------------------------------------- 1 | # Operators 2 | 3 | > See [reference](https://typst.app/docs/reference/math/op/). 4 | 5 | There are lots of built-in "text operators" in Typst math. This is a symbol that behaves very close to plain text. Nevertheless, it is different: 6 | 7 | ```typ 8 | $ 9 | lim x_n, "lim" x_n, "lim"x_n 10 | $ 11 | ``` 12 | ## Predefined operators 13 | 14 | Here are all text operators Typst has built-in: 15 | 16 | ```typ 17 | $ 18 | arccos, arcsin, arctan, arg, cos, cosh, cot, coth, csc,\ 19 | csch, ctg, deg, det, dim, exp, gcd, hom, id, im, inf, ker,\ 20 | lg, lim, liminf, limsup, ln, log, max, min, mod, Pr, sec,\ 21 | sech, sin, sinc, sinh, sup, tan, tanh, tg "and" tr 22 | $ 23 | ``` 24 | 25 | ## Creating custom operator 26 | 27 | Of course, there always will be some text operators you will need that are not in the list. 28 | 29 | But don't worry, it is very easy to add your own: 30 | 31 | ```typ 32 | #let arcsinh = math.op("arcsinh") 33 | 34 | $ 35 | arcsinh x 36 | $ 37 | ``` 38 | 39 | ### Limits for operators 40 | 41 | When creating operators (upright text with proper spacing), you can set limits for _display mode_ at the same time: 42 | 43 | ```typ 44 | $ 45 | op("liminf")_a, op("liminf", limits: #true)_a 46 | $ 47 | ``` 48 | 49 | This is roughly equivalent to 50 | 51 | ```typ 52 | $ 53 | limits(op("liminf"))_a 54 | $ 55 | ``` 56 | 57 | Everything can be combined to create new operators: 58 | 59 | ```typ 60 | #let liminf = math.op(math.underline(math.lim), limits: true) 61 | #let limsup = math.op(math.overline(math.lim), limits: true) 62 | #let integrate = math.op($integral dif x$) 63 | 64 | $ 65 | liminf_(x->oo)\ 66 | limsup_(x->oo)\ 67 | integrate x^2 68 | $ 69 | ``` 70 | -------------------------------------------------------------------------------- /src/typstonomicon/word_count.md: -------------------------------------------------------------------------------- 1 | # Word count 2 | 3 |
This chapter is deprecated now. It will be removed soon.
4 | 5 | ## Recommended solution 6 | 7 | Use `wordometr` [package](https://github.com/Jollywatt/typst-wordometer): 8 | 9 | ```typ 10 | #import "@preview/wordometer:0.1.4": word-count, total-words 11 | 12 | #show: word-count 13 | 14 | In this document, there are #total-words words all up. 15 | 16 | #word-count(total => [ 17 | The number of words in this block is #total.words 18 | and there are #total.characters letters. 19 | ]) 20 | ``` 21 | 22 | ## Just count _all_ words in document 23 | ```typ 24 | // original author: laurmaedje 25 | #let words = counter("words") 26 | #show regex("\p{L}+"): it => it + words.step() 27 | 28 | == A heading 29 | #lorem(50) 30 | 31 | === Strong chapter 32 | #strong(lorem(25)) 33 | 34 | // it is ignoring comments 35 | 36 | #align(right)[(#context words.display() words)] 37 | ``` 38 | 39 | ## Count only some elements, ignore others 40 | 41 | ```typ 42 | // original author: jollywatt 43 | #let count-words(it) = { 44 | let fn = repr(it.func()) 45 | if fn == "sequence" { it.children.map(count-words).sum() } 46 | else if fn == "text" { it.text.split().len() } 47 | else if fn in ("styled") { count-words(it.child) } 48 | else if fn in ("highlight", "item", "strong", "link") { count-words(it.body) } 49 | else if fn in ("footnote", "heading", "equation") { 0 } 50 | else { 0 } 51 | } 52 | 53 | #show: rest => { 54 | let n = count-words(rest) 55 | rest + align(right, [(#n words)]) 56 | } 57 | 58 | == A heading (shouldn't be counted) 59 | #lorem(50) 60 | 61 | === Strong chapter 62 | #strong(lorem(25)) // counted too! 63 | ``` -------------------------------------------------------------------------------- /src/basics/states/query.md: -------------------------------------------------------------------------------- 1 | # Query 2 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
3 | 4 | > Link [to reference](https://typst.app/docs/reference/introspection/query/) 5 | 6 | Query is a thing that allows you getting _a location_ (an object that represents literally a place in document, see [docs here](https://typst.app/docs/reference/introspection/location/)) by _selector_ (this is the same thing we used in show rules). 7 | 8 | That enables "time travel", getting information about document from its parts and so on. _That is a way to violate Typst's purity._ 9 | 10 | It is currently one of the _the darkest magics currently existing in Typst_. It gives you great powers, but with great power comes great responsibility. 11 | 12 | ## Time travel 13 | 14 | ```typ 15 | #let s = state("x", 0) 16 | #let compute(expr) = [ 17 | #s.update(x => 18 | eval(expr.replace("x", str(x))) 19 | ) 20 | New value is #context s.get(). 21 | ] 22 | 23 | Value at `` is 24 | #context s.at( 25 | query() 26 | .first() 27 | .location() 28 | ) 29 | 30 | #compute("10") \ 31 | #compute("x + 3") \ 32 | *Here.* \ 33 | #compute("x * 2") \ 34 | #compute("x - 5") 35 | ``` 36 | 37 | ## Getting nearest chapter 38 | ```typ 39 | #set page(header: context { 40 | let elems = query( 41 | selector(heading).before(here()) 42 | ) 43 | let academy = smallcaps[ 44 | Typst Academy 45 | ] 46 | if elems == () { 47 | align(right, academy) 48 | } else { 49 | let body = elems.last().body 50 | academy + h(1fr) + emph(body) 51 | } 52 | }) 53 | 54 | = Introduction 55 | #lorem(23) 56 | 57 | = Background 58 | #lorem(30) 59 | 60 | = Analysis 61 | #lorem(15) 62 | ``` 63 | -------------------------------------------------------------------------------- /src/about.md: -------------------------------------------------------------------------------- 1 | # Typst Examples Book 2 | 3 | This book provides an extended _tutorial_ and lots of [Typst](https://github.com/typst/typst) snippets that can help you to write better Typst code. 4 | 5 |
6 | This is an unofficial book. Some snippets & suggestions here may be outdated or useless (please let me know if you find some). 7 |
8 | 9 | However, _all of them should compile on last version of Typst[^1]_. 10 | 11 | **CAUTION:** the book is (probably forever) a **WIP**, so don't rely on it. 12 | 13 | If you like it, consider [giving a star on GitHub](https://github.com/sitandr/typst-examples-book)! 14 | 15 | This will help me to stay motivated and continue working on this book. 16 | 17 | ## Navigation 18 | The book consists of several chapters, each with its own goal: 19 | 20 | 1. [Typst Basics](./basics/index.md) 21 | 2. [Typst Snippets](./snippets/index.md) 22 | 3. [Typst Packages](./packages/index.md) 23 | 4. [Typstonomicon](./typstonomicon/index.md) 24 | 25 | ## Contributions 26 | 27 | Any contributions are very welcome! If you have a good code snippet that you want to share, feel free to submit an issue with snippet or make a PR in the [repository](https://github.com/sitandr/typst-examples-book). 28 | 29 | I will especially appreciate submissions of active community members and compiler contributors! 30 | 31 | However, I will also really appreciate feedback from beginners to make the book as comprehensible as possible! 32 | 33 | ## Acknowledgements 34 | 35 | Thanks to everyone in the community who published their code snippets! 36 | 37 | If someone doesn't like their code and/or name being published, please contact me. 38 | 39 | [^1]: When a new version launches, it may take some time to update the book, feel free to tag me to speed up the process. 40 | -------------------------------------------------------------------------------- /src/basics/states/locate.md: -------------------------------------------------------------------------------- 1 | # Locate 2 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
3 | 4 | ## Location 5 | > Link to [reference](https://typst.app/docs/reference/meta/location/) 6 | 7 | ```typ 8 | My location: #context #here()! 9 | ``` 10 | 11 | ## `state.at(loc)` 12 | Given a location, returns _value of state in that location_. 13 | That allows kind of _time travel_, you can get location at _any place of document_. 14 | 15 | `state.display` is roughly equivalent to 16 | ```typ 17 | #let display(state) = locate(location => { 18 | state.at(location) 19 | }) 20 | 21 | #let x = state("x", 0) 22 | #x.display() \ 23 | #x.update(n => n + 3) 24 | #display(x) 25 | ``` 26 | 27 | ## Final 28 | Calculates the _final value_ of state. 29 | 30 | The location there is needed to restrict what content will change within recompilations. 31 | That greatly increases speed and better resolves "conflicts". 32 | ```typ 33 | #let x = state("x", 5) 34 | x = #x.display() \ 35 | 36 | #locate(loc => [ 37 | The final x value is #x.final(loc) 38 | ]) 39 | 40 | #x.update(-3) 41 | x = #x.display() 42 | 43 | #x.update(n => n + 1) 44 | x = #x.display() 45 | ``` 46 | 47 | ## Convergence 48 | Sometimes layout _will not converge_. For example, imagine this: 49 | 50 | ```typ 51 | #let x = state("x", 5) 52 | x = #x.display() \ 53 | 54 | #locate(loc => [ 55 | // let's set x to final x + 1 56 | // and see what will go on? 57 | #x.update(x.final(loc) + 1) 58 | #x.display() 59 | ]) 60 | ``` 61 | 62 | **WARNING**: layout did not converge within 5 attempts 63 | 64 | It is impossible to resolve that layout, so Typst gives up and gives you a warning. 65 | 66 | That means you _should be careful_ with states! 67 | 68 | This is a _dark, **dark magic**_ that requires large sacrifices! 69 | -------------------------------------------------------------------------------- /theme/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/packages/misc.md: -------------------------------------------------------------------------------- 1 | # Misc 2 | 3 | hydra () 4 | outrageous (outline styling, upcoming release with aligned repeated dots) 5 | 6 | # Formatting strings 7 | 8 | ## `oxifmt`, general purpose string formatter 9 | 10 | ```typ 11 | #import "@preview/oxifmt:0.2.1": strfmt 12 | #strfmt("I'm {}. I have {num} cars. I'm {0}. {} is {{cool}}.", "John", "Carl", num: 10) \ 13 | #strfmt("{0:?}, {test:+012e}, {1:-<#8x}", "hi", -74, test: 569.4) \ 14 | #strfmt("{:_>+11.5}", 59.4) \ 15 | #strfmt("Dict: {:!<10?}", (a: 5)) 16 | ``` 17 | 18 | ```typ 19 | #import "@preview/oxifmt:0.2.1": strfmt 20 | #strfmt("First: {}, Second: {}, Fourth: {3}, Banana: {banana} (brackets: {{escaped}})", 1, 2.1, 3, label("four"), banana: "Banana!!")\ 21 | #strfmt("The value is: {:?} | Also the label is {:?}", "something", label("label"))\ 22 | #strfmt("Values: {:?}, {1:?}, {stuff:?}", (test: 500), ("a", 5.1), stuff: [a])\ 23 | #strfmt("Left5 {:_<5}, Right6 {:*>6}, Center10 {centered: ^10?}, Left3 {tleft:_<3}", "xx", 539, tleft: "okay", centered: [a])\ 24 | ``` 25 | 26 | ```typ 27 | #import "@preview/oxifmt:0.2.1": strfmt 28 | #repr(strfmt("Left-padded7 numbers: {:07} {:07} {:07} {3:07}", 123, -344, 44224059, 45.32))\ 29 | #strfmt("Some numbers: {:+} {:+08}; With fill and align: {:_<+8}; Negative (no-op): {neg:+}", 123, 456, 4444, neg: -435)\ 30 | #strfmt("Bases (10, 2, 8, 16(l), 16(U):) {0} {0:b} {0:o} {0:x} {0:X} | W/ prefixes and modifiers: {0:#b} {0:+#09o} {0:_>+#9X}", 124)\ 31 | #strfmt("{0:.8} {0:.2$} {0:.potato$}", 1.234, 0, 2, potato: 5)\ 32 | #strfmt("{0:e} {0:E} {0:+.9e} | {1:e} | {2:.4E}", 124.2312, 50, -0.02)\ 33 | #strfmt("{0} {0:.6} {0:.5e}", 1.432, fmt-decimal-separator: ",") 34 | ``` 35 | 36 | ## `name-it`, integer to text 37 | ```typ 38 | #import "@preview/name-it:0.1.0": name-it 39 | 40 | - #name-it(2418345) 41 | ``` 42 | 43 | ## `nth`, Nth element 44 | ```typ 45 | #import "@preview/nth:0.2.0": nth 46 | #nth(3), #nth(5), #nth(2421) 47 | ``` -------------------------------------------------------------------------------- /src/typstonomicon/extract_plain_text.md: -------------------------------------------------------------------------------- 1 | # Extracting plain text 2 | ```typ 3 | // original author: ntjess 4 | #let stringify-by-func(it) = { 5 | let func = it.func() 6 | return if func in (parbreak, pagebreak, linebreak) { 7 | "\n" 8 | } else if func == smartquote { 9 | if it.double { "\"" } else { "'" } // " 10 | } else if it.fields() == (:) { 11 | // a fieldless element is either specially represented (and caught earlier) or doesn't have text 12 | "" 13 | } else { 14 | panic("Not sure how to handle type `" + repr(func) + "`") 15 | } 16 | } 17 | 18 | #let plain-text(it) = { 19 | return if type(it) == str { 20 | it 21 | } else if it == [ ] { 22 | " " 23 | } else if it.has("children") { 24 | it.children.map(plain-text).join() 25 | } else if it.has("body") { 26 | plain-text(it.body) 27 | } else if it.has("text") { 28 | if type(it.text) == str { 29 | it.text 30 | } else { 31 | plain-text(it.text) 32 | } 33 | } else { 34 | // remove this to ignore all other non-text elements 35 | stringify-by-func(it) 36 | } 37 | } 38 | 39 | #plain-text(`raw inline text`) 40 | 41 | #plain-text(highlight[Highlighted text]) 42 | 43 | #plain-text[List 44 | - With 45 | - Some 46 | - Elements 47 | 48 | + And 49 | + Enumerated 50 | + Too 51 | ] 52 | 53 | #plain-text(underline[Underlined]) 54 | 55 | #plain-text($sin(x + y)$) 56 | 57 | #for el in ( 58 | circle, 59 | rect, 60 | ellipse, 61 | block, 62 | box, 63 | par, 64 | raw.with(block: true), 65 | raw.with(block: false), 66 | heading, 67 | ) { 68 | plain-text(el(repr(el))) 69 | linebreak() 70 | } 71 | 72 | // Some empty elements 73 | #plain-text(circle()) 74 | #plain-text(line()) 75 | 76 | #for spacer in (linebreak, pagebreak, parbreak) { 77 | plain-text(spacer()) 78 | } 79 | ``` 80 | -------------------------------------------------------------------------------- /src/snippets/layout/duplicate.md: -------------------------------------------------------------------------------- 1 | # Duplicate content 2 | 3 |
4 | Notice that this implementation will mess up with labels and similar things. 5 | For complex cases see one below. 6 |
7 | ```typ 8 | #set page(paper: "a4", flipped: true) 9 | #show: body => grid( 10 | columns: (1fr, 1fr), 11 | column-gutter: 1cm, 12 | body, body, 13 | ) 14 | #lorem(200) 15 | ``` 16 | 17 | ## Advanced 18 | ```typ 19 | /// author: frozolotl 20 | #set page(paper: "a4", flipped: true) 21 | #set heading(numbering: "1.1") 22 | #show ref: it => { 23 | if it.element != none { 24 | it 25 | } else { 26 | let targets = query(it.target) 27 | if targets.len() == 2 { 28 | let target = targets.first() 29 | if target.func() == heading { 30 | let num = numbering(target.numbering, ..counter(heading).at(target.location())) 31 | [#target.supplement #num] 32 | } else if target.func() == figure { 33 | let num = numbering(target.numbering, ..target.counter.at(target.location())) 34 | [#target.supplement #num] 35 | } else { 36 | it 37 | } 38 | } else { 39 | it 40 | } 41 | } 42 | } 43 | #show link: it => context { 44 | let dest = query(it.dest) 45 | if dest.len() == 2 { 46 | link(dest.first().location(), it.body) 47 | } else { 48 | it 49 | } 50 | } 51 | #show: body => context grid( 52 | columns: (1fr, 1fr), 53 | column-gutter: 1cm, 54 | body, 55 | { 56 | let reset-counter(kind) = counter(kind).update(counter(kind).get()) 57 | reset-counter(heading) 58 | reset-counter(figure.where(kind: image)) 59 | reset-counter(figure.where(kind: raw)) 60 | set heading(outlined: false) 61 | set figure(outlined: false) 62 | body 63 | }, 64 | ) 65 | 66 | #outline() 67 | 68 | = Foo 69 | See @foo and @foobar. 70 | 71 | #figure(rect[This is an image], caption: [Foobar], kind: raw) 72 | 73 | == Bar 74 | == Baz 75 | #link()[Click to visit Foo] 76 | ``` -------------------------------------------------------------------------------- /src/packages/tables.md: -------------------------------------------------------------------------------- 1 | # Tables 2 | 3 | ## Tada: data manipulation 4 | 5 | ```typ 6 | #import "@preview/tada:0.2.0" 7 | 8 | #let column-data = ( 9 | name: ("Bread", "Milk", "Eggs"), 10 | price: (1.25, 2.50, 1.50), 11 | quantity: (2, 1, 3), 12 | ) 13 | #let record-data = ( 14 | (name: "Bread", price: 1.25, quantity: 2), 15 | (name: "Milk", price: 2.50, quantity: 1), 16 | (name: "Eggs", price: 1.50, quantity: 3), 17 | ) 18 | #let row-data = ( 19 | ("Bread", 1.25, 2), 20 | ("Milk", 2.50, 1), 21 | ("Eggs", 1.50, 3), 22 | ) 23 | 24 | #import tada: TableData, to-tablex 25 | #let td = TableData(data: column-data) 26 | // Equivalent to: 27 | #let td2 = tada.from-records(record-data) 28 | // _Not_ equivalent to (since field names are unknown): 29 | #let td3 = tada.from-rows(row-data) 30 | 31 | #to-tablex(td) 32 | #to-tablex(td2) 33 | #to-tablex(td3) 34 | ``` 35 | 36 | ## Tablem: markdown tables 37 | 38 | > See documentation [there](https://github.com/OrangeX4/typst-tablem) 39 | 40 | Render markdown tables in Typst. 41 | 42 | ```typ 43 | #import "@preview/tablem:0.2.0": tablem 44 | 45 | #tablem[ 46 | | *Name* | *Location* | *Height* | *Score* | 47 | | ------ | ---------- | -------- | ------- | 48 | | John | Second St. | 180 cm | 5 | 49 | | Wally | Third Av. | 160 cm | 10 | 50 | ] 51 | ``` 52 | 53 | ### Custom render 54 | 55 | ```typ 56 | #import "@preview/tablex:0.0.6": tablex, hlinex 57 | #import "@preview/tablem:0.1.0": tablem 58 | 59 | #let three-line-table = tablem.with( 60 | render: (columns: auto, ..args) => { 61 | tablex( 62 | columns: columns, 63 | auto-lines: false, 64 | align: center + horizon, 65 | hlinex(y: 0), 66 | hlinex(y: 1), 67 | ..args, 68 | hlinex(), 69 | ) 70 | } 71 | ) 72 | 73 | #three-line-table[ 74 | | *Name* | *Location* | *Height* | *Score* | 75 | | ------ | ---------- | -------- | ------- | 76 | | John | Second St. | 180 cm | 5 | 77 | | Wally | Third Av. | 160 cm | 10 | 78 | ] 79 | ``` 80 | -------------------------------------------------------------------------------- /src/basics/states/measure.md: -------------------------------------------------------------------------------- 1 | # Measure, Layout 2 |
This section is outdated. It may be still useful, but it is strongly recommended to study new context system (using the reference).
3 | 4 | ## Style & Measure 5 | 6 | > Style [documentation](https://typst.app/docs/reference/foundations/style/). 7 | 8 | > Measure [documentation](https://typst.app/docs/reference/layout/measure/). 9 | 10 | `measure` returns _the element size_. This command is extremely helpful when doing custom layout with `place`. 11 | 12 | However, there is a catch. Element size depends on styles, applied to this element. 13 | 14 | ```typ 15 | #let content = [Hello!] 16 | #content 17 | #set text(14pt) 18 | #content 19 | ``` 20 | 21 | So if we will set the big text size for some part of our text, to measure the element's size, 22 | we have to know _where the element is located_. Without knowing it, we can't tell what styles should be applied. 23 | 24 | So yep, you are right. We need the `context`. 25 | 26 | ```typ 27 | #let thing(body) = context { 28 | let size = measure(body) 29 | [Width of "#body" is #size.width] 30 | } 31 | 32 | #thing[Hey] \ 33 | #thing[Welcome] 34 | ``` 35 | 36 | # Layout 37 | 38 | Layout is similar to `measure`, but it returns current scope **parent size**. 39 | 40 | If you are putting elements in block, that will be block's size. If you are just putting right on the page, that will be page's size. 41 | 42 | For some technical reasons, however, it can't use `context` and needs to use the very similar scheme (it is the one the `context` has emerged from, in fact): 43 | 44 | ```typ 45 | /// It's a black box that receives the parent size and renders something with it: 46 | #layout(size => { 47 | let half = 50% * size.width 48 | [Half a page is #half wide.] 49 | }) 50 | ``` 51 | 52 | It may be extremely useful to combine `layout` with `measure`, to get width of things that depend on parent's size: 53 | 54 | ```typ 55 | #let text = lorem(30) 56 | #layout(size => context [ 57 | #let (height,) = measure( 58 | block(width: size.width, text) 59 | ) 60 | This text is #height high with 61 | the current page width: \ 62 | #text 63 | ]) 64 | ``` -------------------------------------------------------------------------------- /src/basics/must_know/place.md: -------------------------------------------------------------------------------- 1 | # Placing, Moving, Scale & Hide 2 | 3 | This is **a very important section** if you want to do arbitrary things with layout, 4 | create custom elements and hacking a way around current Typst limitations. 5 | 6 | TODO: WIP, add text and better examples 7 | 8 | # Place 9 | 10 | _Ignore layout_, just put some object somehow relative to parent and current position. 11 | The placed object _will not_ affect layouting 12 | 13 | > Link to [reference](https://typst.app/docs/reference/layout/place/) 14 | 15 | ```typ 16 | #set page(height: 60pt) 17 | Hello, world! 18 | 19 | #place( 20 | top + right, // place at the page right and top 21 | square( 22 | width: 20pt, 23 | stroke: 2pt + blue 24 | ), 25 | ) 26 | ``` 27 | 28 | ### Basic floating with place 29 | 30 | ```typ 31 | #set page(height: 150pt) 32 | #let note(where, body) = place( 33 | center + where, 34 | float: true, 35 | clearance: 6pt, 36 | rect(body), 37 | ) 38 | 39 | #lorem(10) 40 | #note(bottom)[Bottom 1] 41 | #note(bottom)[Bottom 2] 42 | #lorem(40) 43 | #note(top)[Top] 44 | #lorem(10) 45 | ``` 46 | 47 | ### dx, dy 48 | Manually change position by `(dx, dy)` relative to intended. 49 | 50 | ```typ 51 | #set page(height: 100pt) 52 | #for i in range(16) { 53 | let amount = i * 4pt 54 | place(center, dx: amount - 32pt, dy: amount)[A] 55 | } 56 | ``` 57 | 58 | # Move 59 | > Link to [reference](https://typst.app/docs/reference/layout/move/) 60 | 61 | ```typ 62 | #rect(inset: 0pt, move( 63 | dx: 6pt, dy: 6pt, 64 | rect( 65 | inset: 8pt, 66 | fill: white, 67 | stroke: black, 68 | [Abra cadabra] 69 | ) 70 | )) 71 | ``` 72 | 73 | # Scale 74 | 75 | Scale content _without affecting the layout_. 76 | 77 | > Link to [reference](https://typst.app/docs/reference/layout/scale/) 78 | 79 | ```typ 80 | #scale(x: -100%)[This is mirrored.] 81 | ``` 82 | 83 | ```typ 84 | A#box(scale(75%)[A])A \ 85 | B#box(scale(75%, origin: bottom + left)[B])B 86 | ``` 87 | 88 | # Hide 89 | 90 | Don't show content, but leave empty space there. 91 | 92 | > Link to [reference](https://typst.app/docs/reference/layout/hide/) 93 | 94 | ```typ 95 | Hello Jane \ 96 | #hide[Hello] Joe 97 | ``` 98 | -------------------------------------------------------------------------------- /src/snippets/math/vecs.md: -------------------------------------------------------------------------------- 1 | # Vectors & Matrices 2 | 3 | You can easily note that the gap isn't necessarily even or the same in different vectors and matrices: 4 | 5 | ```typ 6 | $ 7 | mat(0, 1, -1; -1, 0, 1; 1, -1, 0) vec(a/b, a/b, a/b) = vec(c, d, e) 8 | $ 9 | ``` 10 | That happens because `gap` refers to _spacing between_ elements, not the distance between their centers. 11 | 12 | To fix this, you can use this snippet: 13 | 14 | ```typ 15 | // Fixed height vector 16 | #let fvec(..children, delim: "(", gap: 1.5em) = { // change default gap there 17 | context math.vec( 18 | delim: delim, 19 | gap: 0em, 20 | ..for el in children.pos() { 21 | ({ 22 | box( 23 | width: measure(el).width, 24 | height: gap, place(horizon, el) 25 | ) 26 | },) // this is an array 27 | // `for` merges all these arrays, then we pass it to arguments 28 | } 29 | ) 30 | } 31 | 32 | // fixed hight matrix 33 | // accepts also row-gap, column-gap and gap 34 | #let fmat(..rows, delim: "(", augment: none) = { 35 | let args = rows.named() 36 | let (gap, row-gap, column-gap) = (none,)*3; 37 | 38 | if "gap" in args { 39 | gap = args.at("gap") 40 | row-gap = args.at("row-gap", default: gap) 41 | column-gap = args.at("row-gap", default: gap) 42 | } 43 | else { 44 | // change default vertical there 45 | row-gap = args.at("row-gap", default: 1.5em) 46 | // and horizontal there 47 | column-gap = rows.named().at("column-gap", default: 0.5em) 48 | } 49 | 50 | context math.mat( 51 | delim: delim, 52 | row-gap: 0em, 53 | column-gap: column-gap, 54 | ..for row in rows.pos() { 55 | (for el in row { 56 | ({ 57 | box( 58 | width: measure(el).width, 59 | height: row-gap, place(horizon, el) 60 | ) 61 | },) 62 | }, ) 63 | } 64 | ) 65 | } 66 | 67 | $ 68 | "Before:"& vec(((a/b))/c, a/b, c) = vec(1, 1, 1)\ 69 | "After:"& fvec(((a/b))/c, a/b, c) = fvec(1, 1, 1)\ 70 | 71 | "Before:"& mat(a, b; c, d) vec(e, dot) = vec(c/d, e/f)\ 72 | "After:"& fmat(a, b; c, d) fvec(e, dot) = fvec(c/d, e/f) 73 | $ 74 | ``` 75 | 76 | -------------------------------------------------------------------------------- /src/packages/index.md: -------------------------------------------------------------------------------- 1 | # Packages 2 | Once the [Typst Universe](https://typst.app/universe) was launched, this chapter has become almost redundant. The Universe is actually a very cool place to look for packages. 3 | 4 | However, there are still some cool examples of interesting package usage. 5 | 6 | ## General 7 | Typst has packages, but, unlike LaTeX, you need to remember: 8 | 9 | - You need them only for some specialized tasks, basic formatting _can be totally done without them_. 10 | - Packages are much lighter and much easier "installed" than LaTeX ones. 11 | - Packages are just plain Typst files (and sometimes plugins), so you can easily write your own! 12 | 13 | To use mighty package, just write, like this: 14 | 15 | ```typ 16 | #import "@preview/cetz:0.3.4": canvas, draw 17 | #import "@preview/cetz-plot:0.1.1": plot 18 | 19 | #set page(width: auto, height: auto, margin: .5cm) 20 | 21 | #let style = (stroke: black, fill: rgb(0, 0, 200, 75)) 22 | 23 | #let f1(x) = calc.sin(x) 24 | #let fn = ( 25 | ($ x - x^3"/"3! $, x => x - calc.pow(x, 3)/6), 26 | ($ x - x^3"/"3! - x^5"/"5! $, x => x - calc.pow(x, 3)/6 + calc.pow(x, 5)/120), 27 | ($ x - x^3"/"3! - x^5"/"5! - x^7"/"7! $, x => x - calc.pow(x, 3)/6 + calc.pow(x, 5)/120 - calc.pow(x, 7)/5040), 28 | ) 29 | 30 | #set text(size: 10pt) 31 | 32 | #canvas({ 33 | import draw: * 34 | 35 | // Set-up a thin axis style 36 | set-style(axes: (stroke: .5pt, tick: (stroke: .5pt)), 37 | legend: (stroke: none, orientation: ttb, item: (spacing: .3), scale: 80%)) 38 | 39 | plot.plot(size: (12, 8), 40 | x-tick-step: calc.pi/2, 41 | x-format: plot.formats.multiple-of, 42 | y-tick-step: 2, y-min: -2.5, y-max: 2.5, 43 | legend: "inner-north", 44 | { 45 | let domain = (-1.1 * calc.pi, +1.1 * calc.pi) 46 | 47 | for ((title, f)) in fn { 48 | plot.add-fill-between(f, f1, domain: domain, 49 | style: (stroke: none), label: title) 50 | } 51 | plot.add(f1, domain: domain, label: $ sin x $, 52 | style: (stroke: black)) 53 | }) 54 | }) 55 | ``` 56 | 57 | ## Contributing 58 | If you are author of a package or just want to make a fair overview, 59 | feel free to make issues/PR-s! 60 | -------------------------------------------------------------------------------- /src/packages/glossary.md: -------------------------------------------------------------------------------- 1 | # Glossary 2 | 3 | ## glossarium 4 | 5 | >[Link to the universe](https://typst.app/universe/package/glossarium) 6 | 7 | Package to manage glossary and abbreviations. 8 | 9 |
One of the very first cool packages of Typst, made specially for (probably) the first thesis written in Typst.
10 | 11 | ```typ 12 | #import "@preview/glossarium:0.5.4": make-glossary, register-glossary, print-glossary, gls, glspl 13 | #show: make-glossary 14 | 15 | // for better link visibility 16 | #show link: set text(fill: blue.darken(60%)) 17 | 18 | #let entry-list = ( 19 | ( 20 | // minimal term 21 | (key: "kuleuven", short: "KU Leuven"), 22 | 23 | // a term with a long form and a group 24 | (key: "unamur", short: "UNamur", long: "Namur University", group: "Universities"), 25 | 26 | // a term with a markup description 27 | ( 28 | key: "oidc", 29 | short: "OIDC", 30 | long: "OpenID Connect", 31 | description: [OpenID is an open standard and decentralized authentication protocol promoted by the non-profit 32 | #link("https://en.wikipedia.org/wiki/OpenID#OpenID_Foundation")[OpenID Foundation].], 33 | group: "Accronyms", 34 | ), 35 | 36 | // a term with a short plural 37 | ( 38 | key: "potato", 39 | short: "potato", 40 | // "plural" will be used when "short" should be pluralized 41 | plural: "potatoes", 42 | description: [#lorem(10)], 43 | ), 44 | 45 | // a term with a long plural 46 | ( 47 | key: "dm", 48 | short: "DM", 49 | long: "diagonal matrix", 50 | // "longplural" will be used when "long" should be pluralized 51 | longplural: "diagonal matrices", 52 | description: "Probably some math stuff idk", 53 | ), 54 | ) 55 | ) 56 | 57 | #register-glossary(entry-list) 58 | 59 | // Your document body 60 | #print-glossary( 61 | entry-list 62 | ) 63 | 64 | // referencing the OIDC term using gls 65 | #gls("oidc") 66 | // displaying the long form forcibly 67 | #gls("oidc", long: true) 68 | 69 | // referencing the OIDC term using the reference syntax 70 | @oidc 71 | 72 | Plural: #glspl("potato") 73 | 74 | #gls("oidc", display: "whatever you want") 75 | ``` 76 | -------------------------------------------------------------------------------- /theme/mdbook-pagetoc/sidebar.js: -------------------------------------------------------------------------------- 1 | // Un-active everything when you click it 2 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 3 | el.addEventHandler("click", function() { 4 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 5 | el.classList.remove("active"); 6 | }); 7 | el.classList.add("active"); 8 | }); 9 | }); 10 | 11 | var updateFunction = function() { 12 | 13 | var id; 14 | var elements = document.getElementsByClassName("header"); 15 | Array.prototype.forEach.call(elements, function(el) { 16 | if (window.pageYOffset >= el.offsetTop) { 17 | id = el; 18 | } 19 | }); 20 | 21 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 22 | el.classList.remove("active"); 23 | }); 24 | 25 | Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el) { 26 | if (id.href.localeCompare(el.href) == 0) { 27 | el.classList.add("active"); 28 | } 29 | }); 30 | }; 31 | 32 | // Populate sidebar on load 33 | window.addEventListener('load', function() { 34 | var pagetoc = document.getElementsByClassName("pagetoc")[0]; 35 | var elements = document.getElementsByClassName("header"); 36 | Array.prototype.forEach.call(elements, function(el) { 37 | var link = document.createElement("a"); 38 | 39 | // Indent shows hierarchy 40 | var indent = ""; 41 | switch (el.parentElement.tagName) { 42 | case "H2": 43 | indent = "20px"; 44 | break; 45 | case "H3": 46 | indent = "40px"; 47 | break; 48 | case "H4": 49 | indent = "60px"; 50 | break; 51 | default: 52 | break; 53 | } 54 | 55 | link.appendChild(document.createTextNode(el.text)); 56 | link.style.paddingLeft = indent; 57 | link.href = el.href; 58 | pagetoc.appendChild(link); 59 | }); 60 | updateFunction.call(); 61 | }); 62 | 63 | 64 | 65 | // Handle active elements on scroll 66 | window.addEventListener("scroll", updateFunction); 67 | -------------------------------------------------------------------------------- /src/basics/tutorial/templates.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | ## Templates 3 | If you want to reuse styling in other files, you can use the _template_ idiom. 4 | Because `set` and `show` rules are only active in their current scope, they 5 | will not affect content in a file you imported your file into. But functions 6 | can circumvent this in a predictable way: 7 | ```typ-norender 8 | // define a function that: 9 | // - takes content 10 | // - applies styling to it 11 | // - returns the styled content 12 | #let apply-template(body) = [ 13 | #show heading.where(level: 1): emph 14 | #set heading(numbering: "1.1") 15 | // ... 16 | #body 17 | ] 18 | ``` 19 | 20 | This is equivalent to: 21 | ```typ-norender 22 | // we can reduce the number of hashes needed here by using scripting mode 23 | // same as above but we exchanged `[...]` for `{...}` to switch from markup 24 | // into scripting mode 25 | #let apply-template(body) = { 26 | show heading.where(level: 1): emph 27 | set heading(numbering: "1.1") 28 | // ... 29 | body 30 | } 31 | ``` 32 | 33 | Then in your main file: 34 | ```typ-norender 35 | #import "template.typ": apply-template 36 | #show: apply-template 37 | ``` 38 | 39 | _This will apply a "template" function to the rest of your document!_ 40 | 41 | ### Passing arguments 42 | ```typ-norender 43 | // add optional named arguments 44 | #let apply-template(body, name: "My document") = { 45 | show heading.where(level: 1): emph 46 | set heading(numbering: "1.1") 47 | 48 | align(center, text(name, size: 2em)) 49 | 50 | body 51 | } 52 | ``` 53 | 54 | Then, in template file: 55 | ```typ-norender 56 | #import "template.typ": apply-template 57 | 58 | // `func.with(..)` applies the arguments to the function and returns the new 59 | // function with those defaults applied 60 | #show: apply-template.with(name: "Report") 61 | 62 | // it is functionally the same as this 63 | #let new-template(..args) = apply-template(name: "Report", ..args) 64 | #show: new-template 65 | ``` 66 | 67 | Writing templates is fairly easy if you understand [scripting](../scripting/index.md). 68 | 69 | See more information about writing templates in [Official Tutorial](https://typst.app/docs/tutorial/making-a-template/). 70 | 71 | There is no official repository for templates yet, but there are a plenty community ones in [awesome-typst](https://github.com/qjcg/awesome-typst?ysclid=lj8pur1am7431908794#general). -------------------------------------------------------------------------------- /src/basics/scripting/types_2.md: -------------------------------------------------------------------------------- 1 | # Types, part II 2 | In Typst, most of things are **immutable**. You can't change content, you can just create new using this one (for example, using addition). 3 | 4 | Immutability is very important for Typst since it tries to be _as pure language as possible_. Functions do nothing outside of returning some value. 5 | 6 | However, purity is partly "broken" by these types. They are *super-useful* and not adding them would make Typst much pain. 7 | 8 | However, using them adds complexity. 9 | 10 | ## Arrays (`array`) 11 | > [Link to Reference](https://typst.app/docs/reference/foundations/array/). 12 | 13 | Mutable object that stores data with their indices. 14 | 15 | ### Working with indices 16 | ```typ 17 | #let values = (1, 7, 4, -3, 2) 18 | 19 | // take value at index 0 20 | #values.at(0) \ 21 | // set value at 0 to 3 22 | #(values.at(0) = 3) 23 | // negative index => start from the back 24 | #values.at(-1) \ 25 | // add index of something that is even 26 | #values.find(calc.even) 27 | ``` 28 | 29 | ### Iterating methods 30 | ```typ 31 | #let values = (1, 7, 4, -3, 2) 32 | 33 | // leave only what is odd 34 | #values.filter(calc.odd) \ 35 | // create new list of absolute values of list values 36 | #values.map(calc.abs) \ 37 | // reverse 38 | #values.rev() \ 39 | // convert array of arrays to flat array 40 | #(1, (2, 3)).flatten() \ 41 | // join array of string to string 42 | #(("A", "B", "C") 43 | .join(", ", last: " and ")) 44 | ``` 45 | 46 | ### List operations 47 | ```typ 48 | // sum of lists: 49 | #((1, 2, 3) + (4, 5, 6)) 50 | 51 | // list product: 52 | #((1, 2, 3) * 4) 53 | ``` 54 | 55 | ### Empty list 56 | ```typ 57 | #() \ // this is an empty list 58 | #(1,) \ // this is a list with one element 59 | BAD: #(1) // this is just an element, not a list! 60 | ``` 61 | 62 | ## Dictionaries (`dict`) 63 | > [Link to Reference](https://typst.app/docs/reference/foundations/dictionary/). 64 | 65 | Dictionaries are objects that store a string "key" and a value, associated with that key. 66 | ```typ 67 | #let dict = ( 68 | name: "Typst", 69 | born: 2019, 70 | ) 71 | 72 | #dict.name \ 73 | #(dict.launch = 20) 74 | #dict.len() \ 75 | #dict.keys() \ 76 | #dict.values() \ 77 | #dict.at("born") \ 78 | #dict.insert("city", "Berlin ") 79 | #("name" in dict) 80 | ``` 81 | 82 | ### Empty dictionary 83 | ```typ 84 | This is an empty list: #() \ 85 | This is an empty dict: #(:) 86 | ``` 87 | -------------------------------------------------------------------------------- /src/basics/states/counters.md: -------------------------------------------------------------------------------- 1 | # Counters 2 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
3 | 4 | Counters are special states that _count_ elements of some type. 5 | As with states, you can create your own with identifier strings. 6 | 7 | _Important:_ to initiate counters of elements, you need to _set numbering for them_. 8 | 9 | ## States methods 10 | Counters are states, so they can do all things states can do. In particular, everything about `context` still applies there. 11 | 12 | ```typ 13 | #set heading(numbering: "1.") 14 | 15 | = Background 16 | #counter(heading).update(3) 17 | #counter(heading).update(n => n * 2) 18 | 19 | == Analysis 20 | Current heading number: #context counter(heading).get(). 21 | 22 | You can also display it with a special method that can render it beautifully with arbitrary numbering pattern: #context counter(heading).display("I: 1."). 23 | 24 | Or use current display style: #context counter(heading).display() 25 | 26 | It depends on current set style: 27 | 28 | #set heading(numbering: ":1:1:") 29 | #context counter(heading).display() 30 | ``` 31 | 32 | Ok, here are some more examples. They are quite simple, so I hope no comments are needed. `:)` 33 | 34 | ```typ 35 | #let mine = counter("mycounter") 36 | #context mine.display() 37 | 38 | #mine.step() 39 | #context mine.display() 40 | 41 | #mine.update(c => c * 3) 42 | #context mine.display() 43 | ``` 44 | 45 | Counters also support displaying _both current and final values_ out-of-box, this requires option `both: true`: 46 | 47 | ```typ 48 | #set heading(numbering: "1.") 49 | 50 | = Introduction 51 | Some text here. 52 | 53 | #context counter(heading).display(both: true) \ 54 | #context counter(heading).display("1 of 1", both: true) \ 55 | #context counter(heading).display( 56 | (num, max) => [#num of #max], 57 | both: true 58 | ) 59 | 60 | = Background 61 | The current value is: #context counter(heading).display() 62 | ``` 63 | 64 | ## Step 65 | 66 | That's quite easy, for counters you can increment value using `step`. It works the same way as `update`. 67 | ```typ 68 | #set heading(numbering: "1.") 69 | 70 | = Introduction 71 | #context counter(heading).step() 72 | 73 | = Analysis 74 | Let's skip 3.1. 75 | #context counter(heading).step(level: 2) 76 | 77 | == Analysis 78 | At #context counter(heading).display(). 79 | ``` 80 | 81 | ## You can use counters in your functions: 82 | ```typ 83 | #let c = counter("theorem") 84 | #let theorem(it) = block[ 85 | #c.step() 86 | *Theorem #context c.display():* 87 | #it 88 | ] 89 | 90 | #theorem[$1 = 1$] 91 | #theorem[$2 < 3$] 92 | ``` 93 | -------------------------------------------------------------------------------- /.github/workflows/mdbook.yml: -------------------------------------------------------------------------------- 1 | # Sample workflow for building and deploying a mdBook site to GitHub Pages 2 | # 3 | # To get started with mdBook see: https://rust-lang.github.io/mdBook/index.html 4 | # 5 | name: Deploy mdBook site to Pages 6 | 7 | on: 8 | # Runs on pushes targeting the default branch 9 | push: 10 | branches: ["main"] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 16 | permissions: 17 | contents: read 18 | pages: write 19 | id-token: write 20 | 21 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 22 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 23 | concurrency: 24 | group: "pages" 25 | cancel-in-progress: false 26 | 27 | jobs: 28 | # Build job 29 | build: 30 | runs-on: ubuntu-latest 31 | env: 32 | MDBOOK_VERSION: 0.4.34 33 | RUST_BACKTRACE: full 34 | steps: 35 | - uses: actions/checkout@v3 36 | - name: Install mdBook 37 | run: | 38 | curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.34/mdbook-v0.4.34-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=. 39 | - name: Install mdbook-typst-highlight 40 | run: | 41 | curl -sSL https://github.com/sitandr/mdbook-typst-highlight/releases/download/v0.2.4/mdbook-typst-highlight-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=. 42 | - name: Install typst 43 | run: | 44 | curl -sSL https://github.com/typst/typst/releases/download/v0.13.1/typst-x86_64-unknown-linux-musl.tar.xz | tar -xJ --directory=. 45 | mv typst-x86_64-unknown-linux-musl/typst . 46 | echo `pwd` >> $GITHUB_PATH 47 | - name: Setup Pages 48 | id: pages 49 | uses: actions/configure-pages@v3 50 | - name: Build with mdBook 51 | run: | 52 | mdbook build 53 | mdbook build 54 | # building two times to prevent any packages from interfering, hopefully can remove in future 55 | - name: Upload artifact 56 | uses: actions/upload-pages-artifact@v3 57 | with: 58 | path: . 59 | 60 | # Deployment job 61 | deploy: 62 | environment: 63 | name: github-pages 64 | url: ${{ steps.deployment.outputs.page_url }} 65 | runs-on: ubuntu-latest 66 | needs: build 67 | steps: 68 | - name: Deploy to GitHub Pages 69 | id: deployment 70 | uses: actions/deploy-pages@v4 71 | -------------------------------------------------------------------------------- /src/typstonomicon/chapters.md: -------------------------------------------------------------------------------- 1 | # Create zero-level chapters 2 | 3 | ```typ 4 | // author: tinger 5 | 6 | #let chapter = figure.with( 7 | kind: "chapter", 8 | // same as heading 9 | numbering: none, 10 | // this cannot use auto to translate this automatically as headings can, auto also means something different for figures 11 | supplement: "Chapter", 12 | // empty caption required to be included in outline 13 | caption: [], 14 | ) 15 | 16 | // emulate element function by creating show rule 17 | #show figure.where(kind: "chapter"): it => { 18 | set text(22pt) 19 | counter(heading).update(0) 20 | if it.numbering != none { strong(it.counter.display(it.numbering)) } + [ ] + strong(it.body) 21 | } 22 | 23 | // no access to element in outline(indent: it => ...), so we must do indentation in here instead of outline 24 | #show outline.entry: it => { 25 | if it.element.func() == figure { 26 | // we're configuring chapter printing here, effectively recreating the default show impl with slight tweaks 27 | let res = link(it.element.location(), 28 | // we must recreate part of the show rule from above once again 29 | if it.element.numbering != none { 30 | numbering(it.element.numbering, ..it.element.counter.at(it.element.location())) 31 | } + [ ] + it.element.body 32 | ) 33 | 34 | if it.fill != none { 35 | res += [ ] + box(width: 1fr, it.fill) + [ ] 36 | } else { 37 | res += h(1fr) 38 | } 39 | 40 | res += link(it.element.location(), it.page()) 41 | strong(res) 42 | } else { 43 | // we're doing indenting here 44 | h(1em * it.level) + it 45 | } 46 | } 47 | 48 | // new target selector for default outline 49 | #let chapters-and-headings = figure.where(kind: "chapter", outlined: true).or(heading.where(outlined: true)) 50 | 51 | // 52 | // start of actual doc prelude 53 | // 54 | 55 | #set heading(numbering: "1.") 56 | 57 | // can't use set, so we reassign with default args 58 | #let chapter = chapter.with(numbering: "I") 59 | 60 | // an example of a "show rule" for a chapter 61 | // can't use chapter because it's not an element after using .with() anymore 62 | #show figure.where(kind: "chapter"): set text(red) 63 | 64 | // 65 | // start of actual doc 66 | // 67 | 68 | // as you can see these are not elements like headings, which makes the setup a bit harder 69 | // because the chapters are not headings, the numbering does not include their chapter, but could using a show rule for headings 70 | 71 | #outline(target: chapters-and-headings) 72 | 73 | #chapter[Chapter] 74 | = Chap Heading 75 | == Sub Heading 76 | 77 | #chapter[Chapter again] 78 | = Chap Heading 79 | = Chap Heading 80 | == Sub Heading 81 | === Sub Sub Heading 82 | == Sub Heading 83 | 84 | #chapter[Chapter yet again] 85 | ``` 86 | -------------------------------------------------------------------------------- /src/snippets/grids.md: -------------------------------------------------------------------------------- 1 | ## Fractional grids 2 | 3 | For tables with lines of changing length, you can try using _grids in grids_. 4 | 5 |
6 | Don't use this where cell.colspan and rowspan will do. 7 |
8 | 9 | ```typ 10 | // author: jimpjorps 11 | 12 | #grid( 13 | columns: (1fr,), 14 | grid( 15 | columns: (1fr,)*2, inset: 5pt, stroke: 1pt, [hello], [world] 16 | ), 17 | grid( 18 | columns: (1fr,)*3, inset: 5pt, stroke: 1pt, [foo], [bar], [baz] 19 | ), 20 | grid.cell(inset: 5pt, stroke: 1pt)[abcxyz] 21 | ) 22 | ``` 23 | 24 | ## Automerge adjacent cells with same values 25 | 26 | This example works for adjacent cells horizontally, but it's not hard to upgrade it to columns too. 27 | 28 | ```typ 29 | // author: tebine 30 | #let merge(children, n-cols) = { 31 | let rows = children.chunks(n-cols) 32 | let new-children = () 33 | for r in rows { 34 | // First group starts at index 0 35 | let i = 0 36 | // Search next group 37 | while i < r.len() { 38 | // Group starts with one cell 39 | let c = r.at(i).body 40 | let n = 1 41 | for j in range(i+1, r.len()) { 42 | let c-next = r.at(j).body 43 | if c-next == c { 44 | // Add cell to group 45 | n += 1 46 | } else { 47 | break 48 | } 49 | } 50 | // Group is finished 51 | new-children.push(table.cell(colspan: n, c)) 52 | i += n 53 | } 54 | } 55 | return new-children 56 | } 57 | #show table: it => { 58 | let merged = merge(it.children, it.columns.len()) 59 | if it.children.len() == merged.len() { // trick to avoid recursion 60 | return it 61 | } 62 | table(columns: it.columns.len(), ..merged) 63 | } 64 | #table(columns: 2, 65 | [1], [2], 66 | [3], [3], 67 | [4], [5], 68 | ) 69 | ``` 70 | 71 | ## Slanted column headers with slanted borders 72 | 73 | ```typ 74 | // author: tebine 75 | #let slanted(it, alpha: 45deg, len: 2.5cm) = layout(size => { 76 | let width = size.width 77 | let b = box(inset: 5pt, rotate(-alpha, reflow: true, it)) 78 | let b-size = measure(b) 79 | let l = line(angle: -alpha, length: len) 80 | let l-width = len * calc.cos(alpha) 81 | let l-height = len * calc.sin(alpha) 82 | place(bottom+left, l) 83 | place(bottom+left, l, dx: width) 84 | place(bottom+left, line(length: width), dx: l-width, dy: -l-height) 85 | place(bottom+left, dx: width/2, b) 86 | box(height: l-height) // invisible box to set the height 87 | }) 88 | 89 | #table( 90 | columns: 2, 91 | align: center, 92 | table.header( 93 | table.cell(stroke: none, inset: 0pt, slanted[*AAA*]), 94 | table.cell(stroke: none, inset: 0pt, slanted[*BBBBBB*]), 95 | ), 96 | [aaaaa], [bbbbbb], [c], [d], 97 | ) 98 | ``` 99 | -------------------------------------------------------------------------------- /src/snippets/math/numbering.md: -------------------------------------------------------------------------------- 1 | # Math Numbering 2 | ## Number by current heading 3 | 4 | > See also built-in numbering in [math package section](../../packages/math.md#theorems) 5 | 6 | ```typ 7 | /// original author: laurmaedje 8 | #set heading(numbering: "1.") 9 | 10 | // reset counter at each chapter 11 | // if you want to change the number of displayed 12 | // section numbers, change the level there 13 | #show heading.where(level:1): it => { 14 | counter(math.equation).update(0) 15 | it 16 | } 17 | 18 | #set math.equation(numbering: n => { 19 | numbering("(1.1)", counter(heading).get().first(), n) 20 | // if you want change the number of number of displayed 21 | // section numbers, modify it this way: 22 | /* 23 | let count = counter(heading).get() 24 | let h1 = count.first() 25 | let h2 = count.at(1, default: 0) 26 | numbering("(1.1.1)", h1, h2, n) 27 | */ 28 | }) 29 | 30 | 31 | = Section 32 | == Subsection 33 | 34 | $ 5 + 3 = 8 $ 35 | $ 5 + 3 = 8 $ 36 | 37 | = New Section 38 | == Subsection 39 | $ 5 + 3 = 8 $ 40 | == Subsection 41 | $ 5 + 3 = 8 $ 42 | 43 | Mentioning @a and @b. 44 | ``` 45 | 46 | ## Number only labeled equations 47 | ### Simple code 48 | ```typ 49 | // author: shampoohere 50 | #show math.equation:it => { 51 | if it.fields().keys().contains("label"){ 52 | math.equation(block: true, numbering: "(1)", it) 53 | // Don't forget to change your numbering style in `numbering` 54 | // to the one you actually want to use. 55 | // 56 | // Note that you don't need to #set the numbering now. 57 | } else { 58 | it 59 | } 60 | } 61 | 62 | $ sum_x^2 $ 63 | $ dif/(dif x)(A(t)+B(x))=dif/(dif x)A(t)+dif/(dif x)B(t) $ 64 | $ sum_x^2 $ 65 | $ dif/(dif x)(A(t)+B(x))=dif/(dif x)A(t)+dif/(dif x)B(t) $ 66 | ``` 67 | 68 | ### Make the hacked references clickable again 69 | ```typ 70 | // author: gijsleb 71 | #show math.equation:it => { 72 | if it.has("label") { 73 | // Don't forget to change your numbering style in `numbering` 74 | // to the one you actually want to use. 75 | math.equation(block: true, numbering: "(1)", it) 76 | } else { 77 | it 78 | } 79 | } 80 | 81 | #show ref: it => { 82 | let el = it.element 83 | if el != none and el.func() == math.equation { 84 | link(el.location(), numbering( 85 | // don't forget to change the numbering according to the one 86 | // you are actually using (e.g. section numbering) 87 | "(1)", 88 | counter(math.equation).at(el.location()).at(0) + 1 89 | )) 90 | } else { 91 | it 92 | } 93 | } 94 | 95 | $ sum_x^2 $ 96 | $ dif/(dif x)(A(t)+B(x))=dif/(dif x)A(t)+dif/(dif x)B(t) $ 97 | $ sum_x^2 $ 98 | $ dif/(dif x)(A(t)+B(x))=dif/(dif x)A(t)+dif/(dif x)B(t) $ 99 | In @ep-2 and @ep-3 we see equations 100 | ``` 101 | -------------------------------------------------------------------------------- /src/basics/must_know/project_struct.md: -------------------------------------------------------------------------------- 1 | # Project structure 2 | ## Large document 3 | 4 | Once the document becomes large enough, it becomes harder to navigate it. If you haven't reached that size yet, you can ignore that section. 5 | 6 | For managing that I would recommend splitting your document into _chapters_. It is just a way to work with this, but once you understand how it works, you can do anything you want. 7 | 8 | Let's say you have two chapters, then the recommended structure will look like this: 9 | 10 | ```typ 11 | #import "@preview/treet:0.1.1": * 12 | 13 | #show list: tree-list 14 | #set par(leading: 0.8em) 15 | #show list: set text(font: "DejaVu Sans Mono", size: 0.8em) 16 | - chapters/ 17 | - chapter_1.typ 18 | - chapter_2.typ 19 | - main.typ 👁 #text(gray)[← document entry point] 20 | - template.typ 21 | ``` 22 | 23 |
24 | The exact file names are up to you. 25 |
26 | 27 | Let's see what to put in each of these files. 28 | 29 | ### Template 30 | 31 | In the "template" file goes _all useful functions and variables_ you will use across the chapters. If you have your own template or want to write one, you can write it there. 32 | 33 | ```typ -norender 34 | // template.typ 35 | 36 | #let template = doc => { 37 | set page(header: "My super document") 38 | show "physics": "magic" 39 | doc 40 | } 41 | 42 | #let infoblock = block.with(stroke: blue, fill: blue.lighten(70%)) 43 | #let author = "@sitandr" 44 | ``` 45 | 46 | ### Main 47 | 48 | **This file should be compiled** to get the whole compiled document. 49 | 50 | ```typ -norender 51 | // main.typ 52 | 53 | #import "template.typ": * 54 | // if you have a template 55 | #show: template 56 | 57 | = This is the document title 58 | 59 | // some additional formatting 60 | 61 | #show emph: set text(blue) 62 | 63 | // but don't define functions or variables there! 64 | // chapters will not see it 65 | 66 | // Now the chapters themselves as some Typst content 67 | #include("chapters/chapter_1.typ") 68 | #include("chapters/chapter_1.typ") 69 | ``` 70 | 71 | ### Chapter 72 | 73 | ```typ -norender 74 | // chapter_1.typ 75 | 76 | #import "../template.typ": * 77 | 78 | That's just content with _styling_ and blocks: 79 | 80 | #infoblock[Some information]. 81 | 82 | // just any content you want to include in the document 83 | ``` 84 | 85 | ## Notes 86 | 87 | Note that modules in Typst can see only what they created themselves or imported. Anything else is invisible for them. That's why you need `template.typ` file to define all functions within. 88 | 89 | That means chapters _don't see each other either_, only what is in the template. 90 | 91 | ## Cyclic imports 92 | 93 | **Important:** Typst _forbids_ cyclic imports. That means you can't import `chapter_1` from `chapter_2` and `chapter_2` from `chapter_1` at the same time! 94 | 95 | But the good news is that you can always create some other file to import variable from. 96 | -------------------------------------------------------------------------------- /src/basics/tutorial/markup.md: -------------------------------------------------------------------------------- 1 | # Markup language 2 | ## Starting 3 | ```typ 4 | Starting typing in Typst is easy. 5 | You don't need packages or other weird things for most of things. 6 | 7 | Blank line will move text to a new paragraph. 8 | 9 | Btw, you can use any language and unicode symbols 10 | without any problems as long as the font supports it: ßçœ̃ɛ̃ø∀αβёыა😆… 11 | ``` 12 | 13 | ## Markup 14 | ```typ 15 | = Markup 16 | 17 | This was a heading. Number of `=` in front of name corresponds to heading level. 18 | 19 | == Second-level heading 20 | 21 | Okay, let's move to _emphasis_ and *bold* text. 22 | 23 | Markup syntax is generally similar to 24 | `AsciiDoc` (this was `raw` for monospace text!) 25 | ``` 26 | 27 | ## New lines & Escaping 28 | ```typ 29 | You can break \ 30 | line anywhere you \ 31 | want using "\\" symbol. 32 | 33 | Also you can use that symbol to 34 | escape \_all the symbols you want\_, 35 | if you don't want it to be interpreted as markup 36 | or other special symbols. 37 | ``` 38 | 39 | ## Comments & codeblocks 40 | ```````typ 41 | You can write comments with `//` and `/* comment */`: 42 | // Like this 43 | /* Or even like 44 | this */ 45 | 46 | ```typ 47 | Just in case you didn't read source, 48 | this is how it is written: 49 | 50 | // Like this 51 | /* Or even like 52 | this */ 53 | 54 | By the way, I'm writing it all in a _fenced code block_ with *syntax highlighting*! 55 | ``` 56 | ``````` 57 | 58 | ## Smart quotes 59 | 60 | ```typ 61 | == What else? 62 | 63 | There are not much things in basic "markup" syntax, 64 | but we will see much more interesting things very soon! 65 | I hope you noticed auto-matched "smart quotes" there. 66 | ``` 67 | 68 | ## Lists 69 | ```typ 70 | - Writing lists in a simple way is great. 71 | - Nothing complex, start your points with `-` 72 | and this will become a list. 73 | - Indented lists are created via indentation. 74 | 75 | + Numbered lists start with `+` instead of `-`. 76 | + There is no alternative markup syntax for lists 77 | + So just remember `-` and `+`, all other symbols 78 | wouldn't work in an unintended way. 79 | + That is a general property of Typst's markup. 80 | + Unlike Markdown, there is only one way 81 | to write something with it. 82 | ``` 83 | 84 | **Notice:** 85 | ```typ 86 | Typst numbered lists differ from markdown-like syntax for lists. If you write them by hand, numbering is preserved: 87 | 88 | 1. Apple 89 | 1. Orange 90 | 1. Peach 91 | ``` 92 | 93 | ## Math 94 | ```typ 95 | 96 | I will just mention math ($a + b/c = sum_i x^i$) 97 | is possible and quite pretty there: 98 | 99 | $ 100 | 7.32 beta + 101 | sum_(i=0)^nabla 102 | (Q_i (a_i - epsilon)) / 2 103 | $ 104 | 105 | To learn more about math, see corresponding chapter. 106 | ``` 107 | -------------------------------------------------------------------------------- /src/basics/math/vec.md: -------------------------------------------------------------------------------- 1 | # Vectors, matrices, semicolumn syntax 2 | 3 | ## Vectors 4 | 5 | > By vector we mean a column there. \ 6 | > To write arrow notations for letters, use `$arrow(v)$` \ 7 | > I recommend to create shortcut for this, like `#let arr = math.arrow` 8 | 9 | To write columns, use `vec` command: 10 | 11 | ```typ 12 | $ 13 | vec(a, b, c) + vec(1, 2, 3) = vec(a + 1, b + 2, c + 3) 14 | $ 15 | ``` 16 | 17 | ### Delimiter 18 | You can change parentheses around the column or even remove them: 19 | 20 | ```typ 21 | $ 22 | vec(1, 2, 3, delim: "{") \ 23 | vec(1, 2, 3, delim: bar.double) \ 24 | vec(1, 2, 3, delim: #none) 25 | $ 26 | ``` 27 | 28 | ### Gap 29 | 30 | You can change the size of gap between rows: 31 | 32 | ```typ 33 | $ 34 | vec(a, b, c) 35 | vec(a, b, c, gap:#0em) 36 | vec(a, b, c, gap:#1em) 37 | $ 38 | ``` 39 | 40 | ### Making gap even 41 | 42 | You can easily note that the gap isn't necessarily even or the same in different vectors: 43 | 44 | ```typ 45 | $ 46 | vec(a/b, a/b, a/b) = vec(1, 1, 1) 47 | $ 48 | ``` 49 | That happens because `gap` refers to _spacing between_ elements, not the distance between their centers. 50 | 51 | To fix this, you can use [this snippet](../../snippets/math/vecs.md). 52 | 53 | ## Matrix 54 | 55 | > See [official reference](https://typst.app/docs/reference/math/mat/) 56 | 57 | Matrix is very similar to `vec`, but accepts rows, separated by `;`: 58 | 59 | ```typ 60 | $ 61 | mat( 62 | 1, 2, ..., 10; 63 | 2, 2, ..., 10; 64 | dots.v, dots.v, dots.down, dots.v; 65 | 10, 10, ..., 10; // `;` in the end is optional 66 | ) 67 | $ 68 | ``` 69 | 70 | ### Delimiters and gaps 71 | 72 | You can specify them the same way as for vectors. 73 | 74 |
75 | Specify the arguments either before the content, or after the semicolon. The code will panic if there is no semicolon! 76 |
77 | 78 | ```typ 79 | $ 80 | mat( 81 | delim: "|", 82 | 1, 2, ..., 10; 83 | 2, 2, ..., 10; 84 | dots.v, dots.v, dots.down, dots.v; 85 | 10, 10, ..., 10; 86 | gap: #0.3em 87 | ) 88 | $ 89 | ``` 90 | 91 | ## Semicolon syntax 92 | 93 | When you use semicolons, the arguments _between the semicolons_ are merged into arrays. See yourself: 94 | 95 | ```typ 96 | #let fun(..args) = { 97 | args.pos() 98 | } 99 | 100 | $ 101 | fun(1, 2;3, 4; 6, ; 8) 102 | $ 103 | ``` 104 | 105 | If you miss some of elements, they will be replaced by `none`-s. 106 | 107 | You can mix semicolon syntax and named arguments, but be careful! 108 | 109 | ```typ 110 | #let fun(..args) = { 111 | repr(args.pos()) 112 | repr(args.named()) 113 | } 114 | 115 | $ 116 | fun(1, 2; gap: #3em, 4) 117 | $ 118 | ``` 119 | 120 | For example, this will not work: 121 | 122 | ```typ-norender 123 | $ 124 | // ↓ there is no `;`, so it tries to add (gap:) to array 125 | mat(1, 2; 4, gap: #3em) 126 | $ 127 | ``` 128 | -------------------------------------------------------------------------------- /src/basics/special_symbols.md: -------------------------------------------------------------------------------- 1 | # Special symbols 2 | 3 | > _Important:_ I'm not great with special symbols, so I would additionally appreciate additions and corrections. 4 | 5 | Typst has a great support of _unicode_. That also means it supports _special symbols_. They may be very useful for typesetting. 6 | 7 | In most cases, you shouldn't use these symbols directly often. If possible, use them with show rules (for example, replace all `-th` with `\u{2011}th`, a non-breaking hyphen). 8 | 9 | ## Non-breaking symbols 10 | 11 | Non-breaking symbols can make sure the word/phrase will not be separated. Typst will try to put them as a whole. 12 | 13 | ### Non-breaking space 14 | 15 | > _Important:_ As it is spacing symbols, copy-pasting it will not help. 16 | > Typst will see it as just a usual spacing symbol you used for your source code to look nicer in your editor. Again, it will interpret it _as a basic space_. 17 | 18 | This is a symbol you should't use often (use Typst boxes instead), but it is a good demonstration of how non-breaking symbol work: 19 | 20 | ```typ 21 | #set page(width: 9em) 22 | 23 | // Cruel and world are separated. 24 | // Imagine this is a phrase that can't be split, what to do then? 25 | Hello cruel world 26 | 27 | // Let's connect them with a special space! 28 | 29 | // No usual spacing is allowed, so either use semicolumn... 30 | Hello cruel#sym.space.nobreak;world 31 | 32 | // ...parentheses... 33 | Hello cruel#(sym.space.nobreak)world 34 | 35 | // ...or unicode code 36 | Hello cruel\u{00a0}world 37 | 38 | // Well, to achieve the same effect I recommend using box: 39 | Hello #box[cruel world] 40 | ``` 41 | 42 | ### Non-breaking hyphen 43 | 44 | ```typ 45 | #set page(width: 8em) 46 | 47 | This is an $i$-th element. 48 | 49 | This is an $i$\u{2011}th element. 50 | 51 | // the best way would be 52 | #show "-th": "\u{2011}th" 53 | 54 | This is an $i$-th element. 55 | ``` 56 | 57 | ## Connectors and separators 58 | 59 | ### World joiner 60 | 61 | Initially, world joiner indicates that no line break should occur at this position. It is also a zero-width symbol (invisible), so it can be used as a space removing thing: 62 | 63 | ```typ 64 | #set page(width: 9em) 65 | #set text(hyphenate: true) 66 | 67 | Thisisawordthathastobreak 68 | 69 | // Be careful, there is no line break at all now! 70 | Thisi#sym.wj;sawordthathastobreak 71 | 72 | // code from `physica` package 73 | // word joiner here is used to avoid extra spacing 74 | #let just-hbar = move(dy: -0.08em, strike(offset: -0.55em, extent: -0.05em, sym.planck)) 75 | #let hbar = (sym.wj, just-hbar, sym.wj).join() 76 | 77 | $ a #just-hbar b, a hbar b$ 78 | ``` 79 | 80 | ### Zero width space 81 | 82 | Similar to word-joiner, but this is a _space_. It doesn't prevent word break. On the contrary, it breaks it without any hyphen at all! 83 | 84 | ```typ 85 | #set page(width: 9em) 86 | #set text(hyphenate: true) 87 | 88 | // There is a space inside! 89 | Thisisa#sym.zws;word 90 | 91 | // Be careful, there is no hyphen at all now! 92 | Thisisawo#sym.zws;rdthathastobreak 93 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Typst Examples Book 2 | 3 | See the book there: https://sitandr.github.io/typst-examples-book/book/ 4 | 5 | ## Highlight & rendering 6 | 7 | Currently powered by https://github.com/sitandr/mdbook-typst-highlight. 8 | 9 | ## Contributing 10 | 11 | If you have a snippet you want to have in a book, feel free to create an issue. 12 | 13 | Any PR-s are very welcome! 14 | 15 | Generally encouraged: 16 | 17 | - Editing (expanding examples, fixing bad language issues) 18 | - Selecting any really useful code examples from Discord and Github 19 | - Ideas (just any ideas how to make the book more useful) 20 | 21 | Currently needed: 22 | - Help with updating state manual to context expressions. 23 | - Updating examples with possibilities of new Typst versions 24 | - Some impressive demos 25 | 26 | If you think you can do some large work, please DM me in Discord (@sitandr) or mail (andr.sitnikov34@gmail.com) to avoid duplication. 27 | 28 | Also please DM me if I'm forgetting about your PR. I have bad memory. 29 | 30 | ## Rules 31 | 32 | 1. Many snippets are taken from Discord, Github or other places. Without using them that book would much, much more harder to write. However, getting a consent for every snippet will be a total disaster. 33 | So, as a general rule, if the snippet is a non-trivial one (one that combines typst functions in a smart way), there should be a credit to original author (of course, the credit will be removed if author objects). 34 | 2. In "Typst by Example" section the concepts that are not told yet should be avoided if possible. Although it is okay to use them if they are really intuitive and without them the demonstration would be too dull. 35 | 3. "Typst Snippets" and "Typstonomicon" should not include staff that is already present in official packages. Instead, there should be a link to a package. However, it is allowed to use packages as a tool in snippets, if the package using is "secondary" there or the idea of using that package for that task is not obvious. 36 | 4. Giant queries and hack things should go to "Typstonomicon", not "Typst snippets", even if they are super-useful. "Typst snippets" should contain code as clean as possible. 37 | 38 | ## Cleaning cached Typst files 39 | 40 | ```bash 41 | git clean -d -X -i 42 | ``` 43 | 44 | Make sure to avoid deleting something useful. 45 | 46 | ## Compiling 47 | 48 | To compile the book, you need `typst` cli installed, `mdbook` and my highlighting & rendering preprocessor `mdbook-typst-highlight`. Assuming `typst` is already installed, installation using cargo: 49 | 50 | ```bash 51 | cargo install mdbook 52 | cargo install --git https://github.com/sitandr/mdbook-typst-highlight 53 | ``` 54 | 55 | Alternatively you can install them precompiled from `mdbook` and `mdbook-typst-highlight` releases. In the end you should have to have the latest versions of them all in your PATH. 56 | 57 | After everything installed, `mdbook build` will build the book. You can also use `mdbook watch` for continuous rebuilding, and `--open` option to open the book in your browser. For more details on building, see `mdbook` documentation. 58 | -------------------------------------------------------------------------------- /src/packages/drawing.md: -------------------------------------------------------------------------------- 1 | # Drawing 2 | ## `cetz` 3 | 4 | Cetz is an analogue of LaTeX's `tikz`. Maybe it is not as powerful yet, but certainly easier to learn and use. 5 | 6 | It is the best choice in most of cases you want to draw something in Typst. 7 | 8 | ```typ 9 | #import "@preview/cetz:0.3.4" 10 | 11 | #cetz.canvas(length: 1cm, { 12 | import cetz.draw: * 13 | import cetz.angle: angle 14 | let (a, b, c) = ((0,0), (-1,1), (1.5,0)) 15 | line(a, b) 16 | line(a, c) 17 | set-style(angle: (radius: 1, label-radius: .5), stroke: blue) 18 | angle(a, c, b, label: $alpha$, mark: (end: ">"), stroke: blue) 19 | set-style(stroke: red) 20 | angle(a, b, c, label: n => $#{n/1deg} degree$, 21 | mark: (end: ">"), stroke: red, inner: false) 22 | }) 23 | ``` 24 | 25 | ```typ 26 | #import "@preview/cetz:0.3.4": canvas, draw 27 | 28 | #canvas(length: 1cm, { 29 | import draw: * 30 | intersections(name: "demo", { 31 | circle((0, 0)) 32 | bezier((0,0), (3,0), (1,-1), (2,1)) 33 | line((0,-1), (0,1)) 34 | rect((1.5,-1),(2.5,1)) 35 | }) 36 | for-each-anchor("demo", (name) => { 37 | circle("demo." + name, radius: .1, fill: black) 38 | }) 39 | }) 40 | ``` 41 | 42 | ```typ 43 | #import "@preview/cetz:0.3.4": canvas, draw 44 | 45 | #canvas(length: 1cm, { 46 | import draw: * 47 | let (a, b, c) = ((0, 0), (1, 1), (2, -1)) 48 | line(a, b, c, stroke: gray) 49 | bezier-through(a, b, c, name: "b") 50 | // Show calculated control points 51 | line(a, "b.ctrl-1", "b.ctrl-2", c, stroke: gray) 52 | }) 53 | ``` 54 | 55 | ```typ 56 | #import "@preview/cetz:0.3.4": canvas, draw 57 | 58 | #canvas(length: 1cm, { 59 | import draw: * 60 | group(name: "g", { 61 | rotate(45deg) 62 | rect((0,0), (1,1), name: "r") 63 | copy-anchors("r") 64 | }) 65 | circle("g.top", radius: .1, fill: black) 66 | }) 67 | ``` 68 | 69 | ```typ 70 | // author: LDemetrios 71 | #import "@preview/cetz:0.3.4" 72 | 73 | #cetz.canvas({ 74 | let left = (a:2, b:1, d:-1, e:-2) 75 | let right = (p:2.7, q: 1.8, r: 0.9, s: -.3, t: -1.5, u: -2.4) 76 | let edges = "as,bq,dq,et".split(",") 77 | 78 | let ell-width = 1.5 79 | let ell-height = 3 80 | let dist = 5 81 | let dot-radius = 0.1 82 | let dot-clr = blue 83 | 84 | import cetz.draw: * 85 | circle((-dist/2, 0), radius:(ell-width , ell-height)) 86 | circle((+dist/2, 0), radius:(ell-width , ell-height)) 87 | 88 | for (name, y) in left { 89 | circle((-dist/2, y), radius:dot-radius, fill:dot-clr, name:name) 90 | content(name, anchor:"east", pad(right:.7em, text(fill:dot-clr, name))) 91 | } 92 | 93 | for (name, y) in right { 94 | circle((dist/2, y), radius:dot-radius, fill:dot-clr, name:name) 95 | content(name, anchor:"west", pad(left:.7em, text(fill:dot-clr, name))) 96 | } 97 | 98 | for edge in edges { 99 | let from = edge.at(0) 100 | let to = edge.at(1) 101 | line(from, to) 102 | mark(from, to, symbol: ">", fill: black) 103 | } 104 | 105 | content((0, - ell-height), text(fill:blue)[APPLICATION], anchor:"south") 106 | }) 107 | ``` -------------------------------------------------------------------------------- /src/basics/must_know/spacing.md: -------------------------------------------------------------------------------- 1 | # Using spacing 2 | Most time you will pass spacing into functions. There are special function fields that take only _size_. 3 | They are usually called like `width, length, in(out)set, spacing` and so on. 4 | 5 | Like in CSS, one of the ways to set up spacing in Typst is setting margins and padding of elements. 6 | However, you can also insert spacing directly using functions `h` (horizontal spacing) and `v` (vertical spacing). 7 | 8 | > Links to reference: [h](https://typst.app/docs/reference/layout/h/), [v](https://typst.app/docs/reference/layout/v/). 9 | 10 | ```typ 11 | Horizontal #h(1cm) spacing. 12 | #v(1cm) 13 | And some vertical too! 14 | ``` 15 | 16 | # Absolute length units 17 | > Link to [reference](https://typst.app/docs/reference/layout/length/) 18 | 19 | Absolute length (aka just "length") units are not affected by outer content and size of parent. 20 | ```typ 21 | #set rect(height: 1em) 22 | #table( 23 | columns: 2, 24 | [Points], rect(width: 72pt), 25 | [Millimeters], rect(width: 25.4mm), 26 | [Centimeters], rect(width: 2.54cm), 27 | [Inches], rect(width: 1in), 28 | ) 29 | ``` 30 | 31 | ## Relative to current font size 32 | `1em = 1 current font size`: 33 | 34 | ```typ 35 | #set rect(height: 1em) 36 | #table( 37 | columns: 2, 38 | [Centimeters], rect(width: 2.54cm), 39 | [Relative to font size], rect(width: 6.5em) 40 | ) 41 | 42 | Double font size: #box(stroke: red, baseline: 40%, height: 2em, width: 2em) 43 | ``` 44 | 45 | It is a very convenient unit, so it is used a lot in Typst. 46 | 47 | ## Combined 48 | 49 | ```typ 50 | Combined: #box(rect(height: 5pt + 1em)) 51 | 52 | #(5pt + 1em).abs 53 | #(5pt + 1em).em 54 | ``` 55 | 56 | 57 | # Ratio length 58 | > Link to [reference](https://typst.app/docs/reference/layout/ratio/) 59 | 60 | `1% = 1% from parent size in that dimension` 61 | 62 | ```typ 63 | This line width is 50% of available page size (without margins): 64 | 65 | #line(length: 50%) 66 | 67 | This line width is 50% of the box width: #box(stroke: red, width: 4em, inset: (y: 0.5em), line(length: 50%)) 68 | ``` 69 | 70 | # Relative length 71 | > Link to [reference](https://typst.app/docs/reference/layout/relative/) 72 | 73 | You can _combine_ absolute and ratio lengths into _relative length_: 74 | 75 | ```typ 76 | #rect(width: 100% - 50pt) 77 | 78 | #(100% - 50pt).length \ 79 | #(100% - 50pt).ratio 80 | ``` 81 | 82 | # Fractional length 83 | > Link to [reference](https://typst.app/docs/reference/layout/fraction/) 84 | 85 | Single fraction length just takes _maximum size possible_ to fill the parent: 86 | 87 | ```typ 88 | Left #h(1fr) Right 89 | 90 | #rect(height: 1em)[ 91 | #h(1fr) 92 | ] 93 | ``` 94 | 95 | There are not many places you can use fractions, mainly those are `h` and `v`. 96 | 97 | ## Several fractions 98 | If you use several fractions inside one parent, they will take all remaining space 99 | _proportional to their number_: 100 | 101 | ```typ 102 | Left #h(1fr) Left-ish #h(2fr) Right 103 | ``` 104 | 105 | ## Nested layout 106 | 107 | Remember that fractions work in parent only, don't _rely on them in nested layout_: 108 | 109 | ```typ 110 | Word: #h(1fr) #box(height: 1em, stroke: red)[ 111 | #h(2fr) 112 | ] 113 | ``` -------------------------------------------------------------------------------- /src/snippets/scripting/index.md: -------------------------------------------------------------------------------- 1 | # Scripting 2 | ## Unflatten arrays 3 | 4 | ```typ 5 | // author: PgSuper 6 | #let unflatten(arr, n) = { 7 | let columns = range(0, n).map(_ => ()) 8 | for (i, x) in arr.enumerate() { 9 | columns.at(calc.rem(i, n)).push(x) 10 | } 11 | array.zip(..columns) 12 | } 13 | 14 | #unflatten((1, 2, 3, 4, 5, 6), 2) 15 | #unflatten((1, 2, 3, 4, 5, 6), 3) 16 | ``` 17 | 18 | ## Create an abbreviation 19 | ```typ 20 | #let full-name = "Federal University of Ceará" 21 | 22 | #let letts = { 23 | full-name 24 | .split() 25 | .map(word => word.at(0)) // filter only capital letters 26 | .filter(l => upper(l) == l) 27 | .join() 28 | } 29 | #letts 30 | ``` 31 | 32 | ## Split the string retrieving separators 33 | 34 | ```typ 35 | #",this, is a a a a; a. test? string!".matches(regex("(\b[\P{Punct}\s]+\b|\p{Punct})")).map(x => x.captures).join() 36 | ``` 37 | 38 | ## Create selector matching any values in an array 39 | 40 | This snippet creates a selector (that is then used in a show rule) that 41 | matches any of the values inside the array. Here, it is used to highlight 42 | a few raw lines, but it can be easily adapted to any kind of selector. 43 | 44 | ````typ 45 | // author: Blokyk 46 | #let lines = (2, 3, 5) 47 | #let lines-selectors = lines.map(lineno => raw.line.where(number: lineno)) 48 | #let lines-combined-selector = lines-selectors.fold( 49 | // start with the first selector by default 50 | // you can also use a selector that wouldn't ever match anything, if possible 51 | lines-selectors.at(0), 52 | selector.or // create an OR of all selectors (alternatively: (acc, sel) => acc.or(sel)) 53 | ) 54 | 55 | #show lines-combined-selector: highlight 56 | 57 | ```py 58 | def foo(x, y): 59 | if x == y: 60 | return False 61 | z = x + y 62 | return z * x - z * y >= z 63 | ``` 64 | ```` 65 | 66 | ## Synthesize show (or show-set) rules from dictionnary 67 | 68 | This snippet applies a show-set rule to any element inside a dictionary, 69 | by using the key as the selector and the value as the parameter to set. 70 | In this example, it's used to give custom supplements to custom figure 71 | kinds, based on a dictionnary of correspondances. 72 | 73 | ```typ 74 | // author: laurmaedje 75 | #let kind_supp_dict = ( 76 | algo: "Pseudo-code", 77 | ex: "Example", 78 | prob: "Problem", 79 | ) 80 | 81 | // apply this rule to the whole (rest of the) document 82 | #show: it => { 83 | kind_supp_dict 84 | .pairs() // get an array of key-value pairs 85 | .fold( // we're going to stack show-set rules before the document 86 | it, // start with the default document 87 | (acc, (kind, supp)) => { 88 | // add the curent kind-supp combination on top of the rest 89 | show figure.where(kind: kind): set figure(supplement: supp) 90 | acc 91 | } 92 | ) 93 | } 94 | #figure( 95 | kind: "algo", 96 | caption: [My code], 97 | ```Algorithm there``` 98 | ) 99 | ``` 100 | 101 | Additonnaly, as this is applied at the position where you 102 | write it, these show-set rules will appear as if they were added in 103 | the same place where you wrote this rule. This means that you can 104 | override them later, just like any other show-set rules. 105 | -------------------------------------------------------------------------------- /src/basics/states/context.md: -------------------------------------------------------------------------------- 1 | ## Context for styling 2 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
3 | 4 | > [Context in Reference](https://typst.app/docs/reference/context/) 5 | 6 | (if you haven't read the `state` section yet, read it; the `context` is started to be discussed there) 7 | 8 | As we've already seen in `states` chapter, `context` is kind of object that stores the "layout instructions" of content that may be heavily dependent on outer states. These instructions are rendered later. 9 | 10 | What is important to know is that _the "outer states" I mention there include not just `state`_ (and counters, that are just special states for counting), but also _styling_. 11 | 12 | What do I mean? 13 | 14 | Well, see yourself: 15 | 16 | ### Getting current style 17 | 18 | ```typ 19 | Current font: #context text.font 20 | ``` 21 | 22 | We just got the current font that easily, and that works basically for **any settable property**! Isn't that neat? 23 | 24 | See another example that demonstrates the properties of context better. Let's create a `box` that would be always the color of text: 25 | 26 | ```typ 27 | #let colorful-rect = context box(stroke: text.fill, inset: 0.3em)[#repr(text.fill)] 28 | 29 | Current color in box of the same color: #colorful-rect. 30 | 31 | #set text(red) 32 | 33 | Current color in box of the same color: #colorful-rect. 34 | ``` 35 | 36 | ### How to get things out of context? 37 | 38 | That's the neat part, _you don't_! 39 | 40 | Why? That's easy: for Typst the `context` block is a black box that can be opened only during rendering, when put inside the documents. 41 | 42 | So if you want to get something, you should get it _inside `context`_. 43 | 44 | ### Writing functions 45 | 46 | Important fact: function, as any other content, may be _context-depending_ without any declarations. And it is usually better to allow user to wrap them in context themselves instead of putting it in `context`. 47 | 48 | 49 | Let's say you want to create a list that depends on some style (or maybe `state`) things. It would require context, so you can wrap it in context: 50 | 51 | ```typ 52 | (Bad) 53 | 54 | #let page-dimensions = context (page.width, page.height) 55 | #page-dimensions, representation of that object is: #repr(page-dimensions) 56 | ``` 57 | 58 | That object would be almost useless. It's black box, so you can only put into the doc and that's all. 59 | 60 | Hover, you can do this instead: 61 | 62 | ```typ 63 | (Good!) 64 | 65 | // To be context-dependent function it needs to be function, not just a fixed content 66 | #let page-dimensions() = (page.width, page.height) 67 | 68 | #context page-dimensions() 69 | 70 | #context [ 71 | #let (x, y) = page-dimensions() 72 | Half-width is: #(x/2), height is #y 73 | ] 74 | ``` 75 | 76 | So with context-dependent functions you allow user to put `context` anywhere they want. 77 | 78 | ### Rules inside of context 79 | 80 | As we've already discussed, `context` captures the _outer_ state of the document, and doesn't see anything that happens inside it. So if you do 81 | 82 | ```typ 83 | #context [ 84 | Text, color: #text.fill 85 | 86 | #set text(blue) 87 | 88 | Text, color: #text.fill 89 | ] 90 | ``` 91 | 92 | ...right, the rules inside wouldn't affect style inside the context. -------------------------------------------------------------------------------- /src/basics/must_know/tables.md: -------------------------------------------------------------------------------- 1 | # Tables and grids 2 | 3 | While tables are not that necessary to know if you don't plan to use them in your documents, grids may be very useful for _document layout_. We will use both of them them in the book later. 4 | 5 | Let's not bother with copying examples from official documentation. Just make sure to skim through it, okay? 6 | 7 | ## Basic snippets 8 | 9 | ### Spreading 10 | 11 | Spreading operators (see [there](../scripting/arguments.md)) may be especially useful for the tables: 12 | 13 | ```typ 14 | #set text(size: 9pt) 15 | 16 | #let yield_cells(n) = { 17 | for i in range(0, n + 1) { 18 | for j in range(0, n + 1) { 19 | let product = if i * j != 0 { 20 | // math is used for the better look 21 | if j <= i { $#{ j * i }$ } 22 | else { 23 | // upper part of the table 24 | text(gray.darken(50%), str(i * j)) 25 | } 26 | } else { 27 | if i == j { 28 | // the top right corner 29 | $times$ 30 | } else { 31 | // on of them is zero, we are at top/left 32 | $#{i + j}$ 33 | } 34 | } 35 | // this is an array, for loops merge them together 36 | // into one large array of cells 37 | ( 38 | table.cell( 39 | fill: if i == j and j == 0 { orange } // top right corner 40 | else if i == j { yellow } // the diagonal 41 | else if i * j == 0 { blue.lighten(50%) }, // multipliers 42 | product,), 43 | ) 44 | } 45 | } 46 | } 47 | 48 | #let n = 10 49 | #table( 50 | columns: (0.6cm,) * (n + 1), rows: (0.6cm,) * (n + 1), align: center + horizon, inset: 3pt, ..yield_cells(n), 51 | ) 52 | ``` 53 | 54 | ### Highlighting table row 55 | 56 | ```typ 57 | #table( 58 | columns: 2, 59 | fill: (x, y) => if y == 2 { highlight.fill }, 60 | [A], [B], 61 | [C], [D], 62 | [E], [F], 63 | [G], [H], 64 | ) 65 | ``` 66 | 67 | For individual cells, use 68 | 69 | ```typ 70 | #table( 71 | columns: 2, 72 | [A], [B], 73 | table.cell(fill: yellow)[C], table.cell(fill: yellow)[D], 74 | [E], [F], 75 | [G], [H], 76 | ) 77 | ``` 78 | 79 | ### Splitting tables 80 | 81 | Tables are split between pages automatically. 82 | ```typ 83 | #set page(height: 8em) 84 | #( 85 | table( 86 | columns: 5, 87 | [Aligner], [publication], [Indexing], [Pairwise alignment], [Max. read length (bp)], 88 | [BWA], [2009], [BWT-FM], [Semi-Global], [125], 89 | [Bowtie], [2009], [BWT-FM], [HD], [76], 90 | [CloudBurst], [2009], [Hashing], [Landau-Vishkin], [36], 91 | [GNUMAP], [2009], [Hashing], [NW], [36] 92 | ) 93 | ) 94 | ``` 95 | 96 | However, if you want to make it breakable inside other element, you'll have to make that element breakable too: 97 | 98 | ```typ 99 | #set page(height: 8em) 100 | // Without this, the table fails to split upon several pages 101 | #show figure: set block(breakable: true) 102 | #figure( 103 | table( 104 | columns: 5, 105 | [Aligner], [publication], [Indexing], [Pairwise alignment], [Max. read length (bp)], 106 | [BWA], [2009], [BWT-FM], [Semi-Global], [125], 107 | [Bowtie], [2009], [BWT-FM], [HD], [76], 108 | [CloudBurst], [2009], [Hashing], [Landau-Vishkin], [36], 109 | [GNUMAP], [2009], [Hashing], [NW], [36] 110 | ) 111 | ) 112 | ``` -------------------------------------------------------------------------------- /src/snippets/chapters/outlines.md: -------------------------------------------------------------------------------- 1 | # Outlines 2 | 3 | # Outlines 4 | 5 | > Lots of outlines examples are already available in [official reference](https://typst.app/docs/reference/model/outline/) 6 | 7 | ## Table of contents 8 | 9 | ```typ 10 | #outline() 11 | 12 | = Introduction 13 | #lorem(5) 14 | 15 | = Prior work 16 | #lorem(10) 17 | ``` 18 | 19 | ## Outline of figures 20 | 21 | ```typ 22 | #outline( 23 | title: [List of Figures], 24 | target: figure.where(kind: table), 25 | ) 26 | 27 | #figure( 28 | table( 29 | columns: 4, 30 | [t], [1], [2], [3], 31 | [y], [0.3], [0.7], [0.5], 32 | ), 33 | caption: [Experiment results], 34 | ) 35 | ``` 36 | 37 | You can use arbitrary selector there, so you can do any crazy things. 38 | 39 | 40 | 41 | ## Ignore low-level headings 42 | 43 | ```typ 44 | #set heading(numbering: "1.") 45 | #outline(depth: 2) 46 | 47 | = Yes 48 | Top-level section. 49 | 50 | == Still 51 | Subsection. 52 | 53 | === Nope 54 | Not included. 55 | ``` 56 | 57 | ## Set indentation 58 | 59 | ```typ 60 | #set heading(numbering: "1.a.") 61 | 62 | #outline( 63 | title: [Contents (Automatic)], 64 | indent: auto, 65 | ) 66 | 67 | #outline( 68 | title: [Contents (Length)], 69 | indent: 2em, 70 | ) 71 | 72 | #set outline.entry(fill: "→") 73 | #outline( 74 | title: [Contents (Function)], 75 | ) 76 | 77 | = About ACME Corp. 78 | == History 79 | === Origins 80 | #lorem(10) 81 | 82 | == Products 83 | #lorem(10) 84 | ``` 85 | 86 | ## Replace default dots 87 | 88 | ```typ 89 | #set outline.entry(fill: line(length: 100%)) 90 | #outline(indent: 2em) 91 | 92 | = First level 93 | == Second level 94 | ``` 95 | 96 | ## Make different outline levels look different 97 | 98 | ```typ 99 | #set heading(numbering: "1.") 100 | 101 | #show outline.entry.where( 102 | level: 1 103 | ): it => { 104 | v(12pt, weak: true) 105 | strong(it) 106 | } 107 | 108 | #outline(indent: auto) 109 | 110 | = Introduction 111 | = Background 112 | == History 113 | == State of the Art 114 | = Analysis 115 | == Setup 116 | ``` 117 | 118 | ## Long and short captions for the outline 119 | 120 | ```typ 121 | // author: laurmaedje 122 | // Put this somewhere in your template or at the start of your document. 123 | #let in-outline = state("in-outline", false) 124 | #show outline: it => { 125 | in-outline.update(true) 126 | it 127 | in-outline.update(false) 128 | } 129 | 130 | #let flex-caption(long, short) = context if in-outline.get() { short } else { long } 131 | 132 | // And this is in the document. 133 | #outline(title: [Figures], target: figure) 134 | 135 | #figure( 136 | rect(), 137 | caption: flex-caption( 138 | [This is my long caption text in the document.], 139 | [This is short], 140 | ) 141 | ) 142 | ``` 143 | 144 | ## Ignore citations and footnotes 145 | 146 | That's a workaround a problem that if you make a footnote a heading, its number will be displayed in outline: 147 | 148 | ```typ 149 | 150 | = Heading #footnote[A footnote] 151 | 152 | Text 153 | 154 | #outline() // bad :( 155 | 156 | #pagebreak() 157 | #{ 158 | set footnote.entry( 159 | separator: none 160 | ) 161 | show footnote.entry: hide 162 | show ref: none 163 | show footnote: none 164 | 165 | outline() 166 | } 167 | ``` 168 | -------------------------------------------------------------------------------- /src/basics/math/index.md: -------------------------------------------------------------------------------- 1 | # Math 2 | 3 | Math is a special environment that has special features related to... math. 4 | 5 | ## Syntax 6 | To start math environment, `$`. The spacing around `$` will make it either 7 | _inline_ math (smaller, used in text) or _display_ math (used on math equations on their own). 8 | 9 | ```typ 10 | // This is inline math 11 | Let $a$, $b$, and $c$ be the side 12 | lengths of right-angled triangle. 13 | Then, we know that: 14 | 15 | // This is display math 16 | $ a^2 + b^2 = c^2 $ 17 | 18 | Prove by induction: 19 | 20 | // You can use new lines as spacing too! 21 | $ 22 | sum_(k=1)^n k = (n(n+1)) / 2 23 | $ 24 | ``` 25 | 26 | ## Math.equation 27 | 28 | The element that math is displayed in is called `math.equation`. You can use it for set/show rules: 29 | 30 | ```typ 31 | #show math.equation: set text(red) 32 | 33 | $ 34 | integral_0^oo (f(t) + g(t))/2 35 | $ 36 | ``` 37 | 38 | Any symbol/command that is available in math, _is also available_ in code mode using `math.command`: 39 | 40 | ```typ 41 | #math.integral, #math.underbrace([a + b], [c]) 42 | ``` 43 | 44 | ## Letters and commands 45 | 46 | Typst aims to have as simple and effective syntax for math as possible. 47 | That means no special symbols, just using commands. 48 | 49 | To make it short, Typst uses several simple rules: 50 | 51 | - All single-letter words _turn into variables_. That includes any _unicode symbols_ too! 52 | - All multi-letter words _turn into commands_. They may be built-in commands (available with math.something outside of math environment). 53 | Or they **may be user-defined variables/functions**. If the command **isn't defined**, there will be **compilation error**. 54 | 55 |
56 | If you use kebab-case or snake_case for variables you want to use in math, 57 | you will have to refer to them as #snake-case-variable. 58 |
59 | - To write simple text, use quotes: 60 | ```typ 61 | $a "equals to" 2$ 62 | ``` 63 | 64 |
65 | Spacing matters there! 66 |
67 | 68 | ```typ 69 | $a "is" 2$, $a"is"2$ 70 | ``` 71 | - You can turn it into multi-letter variables using `italic`: 72 | ```typ 73 | $(italic("mass") v^2)/2$ 74 | ``` 75 | 76 | Commands see [there](https://typst.app/docs/reference/math/#definitions) (go to the links to see the commands). 77 | 78 | All symbols see [there](https://typst.app/docs/reference/symbols/sym/). 79 | 80 | ## Multiline equations 81 | 82 | To create multiline _display equation_, use the same symbol as in markup mode: `\\`: 83 | 84 | ```typ 85 | $ 86 | a = b\ 87 | a = c 88 | $ 89 | ``` 90 | 91 | ## Escaping 92 | 93 | Any symbol that is used may be escaped with `\\`, like in markup mode. For example, you can disable fraction: 94 | 95 | ```typ 96 | $ 97 | a / b \ 98 | a \/ b 99 | $ 100 | ``` 101 | 102 | The same way it works with any other syntax. 103 | 104 | ## Wrapping inline math 105 | 106 | Sometimes, when you write large math, it may be too close to text (especially for some long letter tails). 107 | 108 | ```typ 109 | #lorem(17) $display(1)/display(1+x^n)$ #lorem(20) 110 | ``` 111 | 112 | You may easily increase the distance it by wrapping into box: 113 | 114 | ```typ 115 | #lorem(17) #box($display(1)/display(1+x^n)$, inset: 0.2em) #lorem(20) 116 | ``` 117 | -------------------------------------------------------------------------------- /src/basics/tutorial/basic_styling.md: -------------------------------------------------------------------------------- 1 | # Basic styling 2 | ## `Set` rule 3 | ```typ 4 | #set page(width: 15cm, margin: (left: 4cm, right: 4cm)) 5 | 6 | That was great, but using functions everywhere, especially 7 | with many arguments every time is awfully cumbersome. 8 | 9 | That's why Typst has _rules_. No, not for you, for the document. 10 | 11 | #set par(justify: true) 12 | 13 | And the first rule we will consider there is `set` rule. 14 | As you see, I've just used it on `par` (which is short from paragraph) 15 | and now all paragraphs became _justified_. 16 | 17 | It will apply to all paragraphs after the rule, 18 | but will work only in its _scope_ (we will discuss them later). 19 | 20 | #par(justify: false)[ 21 | Of course, you can override a `set` rule. 22 | This rule just sets the _default value_ 23 | of an argument of an element. 24 | ] 25 | 26 | By the way, at first line of this snippet 27 | I've reduced page size to make justifying more visible, 28 | also increasing margins to add blank space on left and right. 29 | ``` 30 | 31 | ## A bit about length units 32 | ```typ 33 | Before we continue with rules, we should talk about length. There are several absolute length units in Typst: 34 | 35 | #set rect(height: 1em) 36 | 37 | #table( 38 | columns: 2, 39 | [Points], rect(width: 72pt), 40 | [Millimeters], rect(width: 25.4mm), 41 | [Centimeters], rect(width: 2.54cm), 42 | [Inches], rect(width: 1in), 43 | [Relative to font size], rect(width: 6.5em) 44 | ) 45 | 46 | `1 em` = current font size. \ 47 | It is a very convenient unit, 48 | so we are going to use it a lot 49 | ``` 50 | 51 | ## Setting something else 52 | 53 | Of course, you can use `set` rule with all built-in functions 54 | and all their named arguments to make some argument "default". 55 | 56 | For example, let's make all quotes in this snippet authored by the book: 57 | 58 | ```typ 59 | #set quote(block: true, attribution: [Typst Examples Book]) 60 | 61 | #quote[ 62 | Typst is great! 63 | ] 64 | 65 | #quote[ 66 | The problem with quotes on the internet is 67 | that it is hard to verify their authenticity. 68 | ] 69 | ``` 70 | 71 | ## Opinionated defaults 72 | 73 | That allows you to set Typst default styling as you want it: 74 | 75 | ```typ 76 | #set par(justify: true) 77 | #set list(indent: 1em) 78 | #set enum(indent: 1em) 79 | #set page(numbering: "1") 80 | 81 | - List item 82 | - List item 83 | 84 | + Enum item 85 | + Enum item 86 | ``` 87 | 88 | Don't complain about bad defaults! `Set` your own. 89 | 90 | ## Numbering 91 | 92 | ```typ 93 | = Numbering 94 | 95 | Some of elements have a property called "numbering". 96 | They accept so-called "numbering patterns" and 97 | are very useful with set rules. Let's see what I mean. 98 | 99 | #set heading(numbering: "I.1:") 100 | 101 | = This is first level 102 | = Another first 103 | == Second 104 | == Another second 105 | === Now third 106 | == And second again 107 | = Now returning to first 108 | = These are actual roman numerals 109 | ``` 110 | 111 | Of course, there are lots of other cool properties 112 | that can be _set_, so feel free to dive into [Official Reference](https://typst.app/docs/reference/) 113 | and explore them! 114 | 115 | And now we are moving into something much more interesting… 116 | -------------------------------------------------------------------------------- /src/basics/scripting/types.md: -------------------------------------------------------------------------------- 1 | # Types, part I 2 | Each value in Typst has a type. You don't have to specify it, but it is important. 3 | 4 | ## Content (`content`) 5 | > [Link to Reference](https://typst.app/docs/reference/foundations/content/). 6 | 7 | We have already seen it. A type that represents what is displayed in document. 8 | ```typ 9 | #let c = [It is _content_!] 10 | 11 | // Check type of c 12 | #(type(c) == content) 13 | 14 | #c 15 | 16 | // repr gives an "inner representation" of value 17 | #repr(c) 18 | ``` 19 | 20 | **Important:** It is very hard to convert _content_ to _plain text_, as _content_ may contain *anything*! So be careful when passing and storing content in variables. 21 | 22 | ## None (`none`) 23 | Nothing. Also known as `null` in other languages. It isn't displayed, converts to empty content. 24 | ```typ 25 | #none 26 | #repr(none) 27 | ``` 28 | 29 | ## String (`str`) 30 | > [Link to Reference](https://typst.app/docs/reference/foundations/str/). 31 | 32 | String contains only plain text and no formatting. Just some chars. That allows us to work with chars: 33 | ```typ 34 | #let s = "Some large string. There could be escape sentences: \n, 35 | line breaks, and even unicode codes: \u{1251}" 36 | #s \ 37 | #type(s) \ 38 | `repr`: #repr(s) 39 | 40 | #let s = "another small string" 41 | #s.replace("a", sym.alpha) \ 42 | #s.split(" ") // split by space 43 | ``` 44 | 45 | You can convert other types to their string representation using this type's constructor (e.g. convert number to string): 46 | 47 | ```typ 48 | #str(5) // string, can be worked with as string 49 | ``` 50 | 51 | ## Boolean (`bool`) 52 | > [Link to Reference](https://typst.app/docs/reference/foundations/bool/). 53 | 54 | true/false. Used in `if` and many others 55 | ```typ 56 | #let b = false 57 | #b \ 58 | #repr(b) \ 59 | #(true and not true or true) = #((true and (not true)) or true) \ 60 | #if (4 > 3) { 61 | "4 is more than 3" 62 | } 63 | ``` 64 | 65 | ## Integer (`int`) 66 | > [Link to Reference](https://typst.app/docs/reference/foundations/int/). 67 | 68 | A whole number. 69 | 70 | The number can also be specified as hexadecimal, octal, or binary by starting it with a zero followed by either x, o, or b. 71 | 72 | ```typ 73 | #let n = 5 74 | #n \ 75 | #(n += 1) \ 76 | #n \ 77 | #calc.pow(2, n) \ 78 | #type(n) \ 79 | #repr(n) 80 | ``` 81 | 82 | ```typ 83 | #(1 + 2) \ 84 | #(2 - 5) \ 85 | #(3 + 4 < 8) 86 | ``` 87 | 88 | ```typ 89 | #0xff \ 90 | #0o10 \ 91 | #0b1001 92 | ``` 93 | 94 | You can convert a value to an integer with this type's constructor (e.g. convert string to int). 95 | 96 | ```typ 97 | #int(false) \ 98 | #int(true) \ 99 | #int(2.7) \ 100 | #(int("27") + int("4")) 101 | ``` 102 | 103 | ## Float (`float`) 104 | > [Link to Reference](https://typst.app/docs/reference/foundations/float/). 105 | 106 | Works the same way as integer, but can store floating point numbers. 107 | However, precision may be lost. 108 | 109 | ```typ 110 | #let n = 5.0 111 | 112 | // You can mix floats and integers, 113 | // they will be implicitly converted 114 | #(n += 1) \ 115 | #calc.pow(2, n) \ 116 | #(0.2 + 0.1) \ 117 | #type(n) 118 | ``` 119 | 120 | ```typ 121 | #3.14 \ 122 | #1e4 \ 123 | #(10 / 4) 124 | ``` 125 | 126 | You can convert a value to a float with this type's constructor (e.g. convert string to float). 127 | 128 | ```typ 129 | #float(40%) \ 130 | #float("2.7") \ 131 | #float("1e5") 132 | ``` 133 | -------------------------------------------------------------------------------- /src/basics/scripting/conditions.md: -------------------------------------------------------------------------------- 1 | # Conditions & loops 2 | 3 | ## Conditions 4 | > See [official documentation](https://typst.app/docs/reference/scripting/#conditionals). 5 | 6 | In Typst, you can use `if-else` statements. 7 | This is especially useful inside function bodies to vary behavior depending on arguments types or many other things. 8 | 9 | ```typ 10 | #if 1 < 2 [ 11 | This is shown 12 | ] else [ 13 | This is not. 14 | ] 15 | ``` 16 | 17 | Of course, `else` is unnecessary: 18 | 19 | ```typ 20 | #let a = 3 21 | 22 | #if a < 4 { 23 | a = 5 24 | } 25 | 26 | #a 27 | ``` 28 | 29 | You can also use `else if` statement (known as `elif` in Python): 30 | 31 | ```typ 32 | #let a = 5 33 | 34 | #if a < 4 { 35 | a = 5 36 | } else if a < 6 { 37 | a = -3 38 | } 39 | 40 | #a 41 | ``` 42 | 43 | ### Booleans 44 | 45 | `if, else if, else` accept _only boolean_ values as a switch. 46 | You can combine booleans as described in [types section](./types.md#boolean-bool): 47 | 48 | ```typ 49 | #let a = 5 50 | 51 | #if (a > 1 and a <= 4) or a == 5 [ 52 | `a` matches the condition 53 | ] 54 | ``` 55 | 56 | ### Set-if 57 | 58 | Typst supports a pretty useful instruction: `set if`, use set rule if condition is applied. This may be very useful for conditional styling, either of the whole document or inside a function: 59 | 60 | ```typ 61 | #let draft = true 62 | 63 | // you can do any condition operation right there 64 | #set page(columns: 2, width: 20em, height: 10em) if not draft 65 | 66 | // and even use it inside show rules 67 | #show "TODO": set text(red, size: 2em) if draft 68 | 69 | TODO: write real text 70 | 71 | #lorem(50) 72 | ``` 73 | 74 | ## Loops 75 | 76 | > See [official documentation](https://typst.app/docs/reference/scripting/#loops). 77 | 78 | There are two kinds of loops: `while` and `for`. While repeats body while the condition is met: 79 | 80 | ```typ 81 | #let a = 3 82 | 83 | #while a < 100 { 84 | a *= 2 85 | str(a) 86 | " " 87 | } 88 | ``` 89 | 90 | `for` iterates over all elements of sequence. The sequence may be an `array`, `string` 91 | or `dictionary` (`for` iterates over its _key-value pairs_). 92 | 93 | ```typ 94 | #for c in "ABC" [ 95 | #c is a letter. 96 | ] 97 | ``` 98 | 99 | To iterate to all numbers from `a` to `b`, use `range(a, b+1)`: 100 | 101 | ```typ 102 | #let s = 0 103 | 104 | #for i in range(3, 6) { 105 | s += i 106 | [Number #i is added to sum. Now sum is #s.] 107 | } 108 | ``` 109 | 110 | Because range is end-exclusive this is equal to 111 | 112 | ```typ 113 | #let s = 0 114 | 115 | #for i in (3, 4, 5) { 116 | s += i 117 | [Number #i is added to sum. Now sum is #s.] 118 | } 119 | ``` 120 | 121 | ```typ 122 | #let people = (Alice: 3, Bob: 5) 123 | 124 | #for (name, value) in people [ 125 | #name has #value apples. 126 | ] 127 | ``` 128 | 129 | ### Break and continue 130 | 131 | Inside loops can be used `break` and `continue` commands. `break` breaks loop, jumping outside. `continue` jumps to next loop iteration. 132 | 133 | See the difference on these examples: 134 | 135 | ```typ 136 | #for letter in "abc nope" { 137 | if letter == " " { 138 | // stop when there is space 139 | break 140 | } 141 | 142 | letter 143 | } 144 | ``` 145 | 146 | ```typ 147 | #for letter in "abc nope" { 148 | if letter == " " { 149 | // skip the space 150 | continue 151 | } 152 | 153 | letter 154 | } 155 | ``` 156 | -------------------------------------------------------------------------------- /src/snippets/numbering.md: -------------------------------------------------------------------------------- 1 | # Numbering 2 | ## Individual heading without numbering 3 | ```typ 4 | #let numless(it) = {set heading(numbering: none); it } 5 | 6 | = Heading 7 | #numless[= No numbering heading] 8 | ``` 9 | 10 | ## "Clean" numbering 11 | ```typ 12 | // original author: tromboneher 13 | 14 | // Number sections according to a number of schemes, omitting previous leading elements. 15 | // For example, where the numbering pattern "A.I.1." would produce: 16 | // 17 | // A. A part of the story 18 | // A.I. A chapter 19 | // A.II. Another chapter 20 | // A.II.1. A section 21 | // A.II.1.a. A subsection 22 | // A.II.1.b. Another subsection 23 | // A.II.2. Another section 24 | // B. Another part of the story 25 | // B.I. A chapter in the second part 26 | // B.II. Another chapter in the second part 27 | // 28 | // clean_numbering("A.", "I.", "1.a.") would produce: 29 | // 30 | // A. A part of the story 31 | // I. A chapter 32 | // II. Another chapter 33 | // 1. A section 34 | // 1.a. A subsection 35 | // 1.b. Another subsection 36 | // 2. Another section 37 | // B. Another part of the story 38 | // I. A chapter in the second part 39 | // II. Another chapter in the second part 40 | // 41 | #let clean_numbering(..schemes) = { 42 | (..nums) => { 43 | let (section, ..subsections) = nums.pos() 44 | let (section_scheme, ..subschemes) = schemes.pos() 45 | 46 | if subsections.len() == 0 { 47 | numbering(section_scheme, section) 48 | } else if subschemes.len() == 0 { 49 | numbering(section_scheme, ..nums.pos()) 50 | } 51 | else { 52 | clean_numbering(..subschemes)(..subsections) 53 | } 54 | } 55 | } 56 | 57 | #set heading(numbering: clean_numbering("A.", "I.", "1.a.")) 58 | 59 | = Part 60 | == Chapter 61 | == Another chapter 62 | === Section 63 | ==== Subsection 64 | ==== Another subsection 65 | = Another part of the story 66 | == A chapter in the second part 67 | == Another chapter in the second part 68 | ``` 69 | 70 | ## Math numbering 71 | See [there](./math/numbering.md). 72 | 73 | ## Numbering each paragraph 74 | 75 |
76 | By the 0.12 version of Typst, this should be replaced with good native solution. 77 |
78 | 79 | ```typ 80 | // original author: roehlichA 81 | // Legal formatting of enumeration 82 | #show enum: it => context { 83 | // Retrieve the last heading so we know what level to step at 84 | let headings = query(selector(heading).before(here())) 85 | let last = headings.at(-1) 86 | 87 | // Combine the output items 88 | let output = () 89 | for item in it.children { 90 | output.push([ 91 | #context{ 92 | counter(heading).step(level: last.level + 1) 93 | } 94 | #context { 95 | counter(heading).display() 96 | } 97 | ]) 98 | output.push([ 99 | #text(item.body) 100 | #parbreak() 101 | ]) 102 | } 103 | 104 | // Display in a grid 105 | grid( 106 | columns: (auto, 1fr), 107 | column-gutter: 1em, 108 | row-gutter: 1em, 109 | ..output 110 | ) 111 | 112 | } 113 | 114 | #set heading(numbering: "1.") 115 | 116 | = Some heading 117 | + Paragraph 118 | = Other 119 | + Paragraphs here are preceded with a number so they can be referenced directly. 120 | + _#lorem(100)_ 121 | + _#lorem(100)_ 122 | 123 | == A subheading 124 | + Paragraphs are also numbered correctly in subheadings. 125 | + _#lorem(50)_ 126 | + _#lorem(50)_ 127 | ``` 128 | -------------------------------------------------------------------------------- /src/basics/scripting/braces.md: -------------------------------------------------------------------------------- 1 | # Braces, brackets and default 2 | ## Square brackets 3 | You may remember that square brackets convert everything inside to *content*. 4 | ```typ 5 | #let v = [Some text, _markup_ and other #strong[functions]] 6 | #v 7 | ``` 8 | 9 | We may use same for functions bodies: 10 | ```typ 11 | #let f(name) = [Hello, #name] 12 | #f[World] // also don't forget we can use it to pass content! 13 | ``` 14 | 15 | **Important:** It is very hard to convert _content_ to _plain text_, as _content_ may contain *anything*! So be careful when passing and storing content in variables. 16 | 17 | ## Braces 18 | 19 | However, we often want to use code inside functions. 20 | That's when we use `{}`: 21 | ```typ 22 | #let f(name) = { 23 | // this is code mode 24 | 25 | // First part of our output 26 | "Hello, " 27 | 28 | // we check if name is empty, and if it is, 29 | // insert placeholder 30 | if name == "" { 31 | "anonym" 32 | } else { 33 | name 34 | } 35 | 36 | // finish sentence 37 | "!" 38 | } 39 | 40 | #f("") 41 | #f("Joe") 42 | #f("world") 43 | ``` 44 | 45 | 46 | ## Default values 47 | What we made just now was inventing "default values". 48 | 49 | They are very common in styling, so there is a special syntax for them: 50 | ```typ 51 | #let f(name: "anonym") = [Hello, #name!] 52 | 53 | #f() 54 | #f(name: "Joe") 55 | #f(name: "world") 56 | ``` 57 | 58 | You may have noticed that the argument became _named_ now. 59 | In Typst, named argument is an argument _that has default value_. 60 | 61 | 62 | ## When to use brackets and braces 63 | 64 | So, as we have seen, we can use both 65 | 66 | ```typ 67 | #let f(name) = [ 68 | Hello, #name 69 | ] 70 | #f("Joe") 71 | ``` 72 | 73 | And 74 | 75 | ```typ 76 | #let f(name) = { 77 | [Hello,] 78 | name 79 | } 80 | #f("Joe") 81 | ``` 82 | 83 | So when to use what? 84 | 85 | Well, the answer is simple: which way the code is cleaner. 86 | 87 | So don't do that: 88 | ```typ 89 | // DON'T DO THAT 90 | // PLEASE 91 | #let f(inner) = [ 92 | #set align(center) 93 | #set box(stroke: red) 94 | #show heading: it => [ 95 | #set text(size: 2em) 96 | #it 97 | ] 98 | #box[#inner] 99 | ] 100 | ``` 101 | 102 | Can you see how it can be simplified when using code mode? 103 | 104 | ## Scopes 105 | **This is a very important thing to remember**. 106 | 107 | _You can't use variables outside of scopes they are defined (unless it is file root, then you can import them)_. _Set and show rules affect things in their scope only._ 108 | ```typ 109 | #{ 110 | let a = 3; 111 | } 112 | // can't use "a" there. 113 | 114 | #[ 115 | #show "true": "false" 116 | 117 | This is true. 118 | ] 119 | 120 | This is true. 121 | ``` 122 | 123 | ## Return 124 | **Important**: by default braces return anything that "returns" into them. For example, 125 | ```typ 126 | #let change_world() = { 127 | // some code there changing everything in the world 128 | str(4e7) 129 | // another code changing the world 130 | } 131 | 132 | #let g() = { 133 | "Hahaha, I will change the world now! " 134 | change_world() 135 | " So here is my long evil monologue..." 136 | } 137 | 138 | #g() 139 | ``` 140 | 141 | To avoid returning everything, return only what you want _explicitly_, otherwise everything will be joined into one object: 142 | 143 | ```typ 144 | #let f() = { 145 | "Some long text" 146 | // Crazy numbers 147 | "2e7" 148 | return none 149 | } 150 | 151 | // Returns nothing 152 | #f() 153 | ``` 154 | -------------------------------------------------------------------------------- /src/basics/math/symbols.md: -------------------------------------------------------------------------------- 1 | # Symbols 2 | 3 | Multiletter words in math refer either to local variables, functions, text operators, spacing or _special symbols_. 4 | The latter are very important for advanced math. 5 | 6 | ```typ 7 | $ 8 | forall v, w in V, alpha in KK: alpha dot (v + w) = alpha v + alpha w 9 | $ 10 | ``` 11 | 12 | You can write the same with unicode: 13 | 14 | ```typ 15 | $ 16 | ∀ v, w ∈ V, α ∈ 𝕂: α ⋅ (v + w) = α v + α w 17 | $ 18 | ``` 19 | 20 | ## Symbols naming 21 | 22 | > See all available symbols list [there](https://typst.app/docs/reference/symbols/sym/). 23 | 24 | ### General idea 25 | 26 | Typst wants to define some "basic" symbols with small easy-to-remember words, and build complex ones using 27 | combinations. For example, 28 | 29 | ```typ 30 | $ 31 | // cont — contour 32 | integral, integral.cont, integral.double, integral.square, sum.integral\ 33 | 34 | // lt — less than, gt — greater than 35 | lt, lt.circle, lt.eq, lt.not, lt.eq.not, lt.tri, lt.tri.eq, lt.tri.eq.not, gt, lt.gt.eq, lt.gt.not 36 | $ 37 | ``` 38 | 39 | I highly recommend using WebApp/Typst LSP when writing math with lots of complex symbols. 40 | That helps you to quickly choose the right symbol within all combinations. 41 | 42 | Sometimes the names are not obvious, for example, sometimes it is used prefix `n-` instead of `not`: 43 | 44 | ```typ 45 | $ 46 | gt.nequiv, gt.napprox, gt.ntilde, gt.tilde.not 47 | $ 48 | ``` 49 | 50 | 51 | ### Common modifiers 52 | 53 | - `.b, .t, .l, .r`: bottom, top, left, right. Change direction of symbol. 54 | ```typ 55 | $arrow.b, triangle.r, angle.l$ 56 | ``` 57 | - `.bl, tr`: bottom-left, top-right and so on. Where diagonal directions are possible. 58 | - `.bar, .circle, .times, ...`: adds corresponding element to symbol 59 | - `.double, .triple, .quad`: combine symbol 2, 3 or 4 times 60 | - `.not` crosses the symbol 61 | - `.cw, .ccw`: clock-wise and counter-clock-wise. For arrows and other things. 62 | - `.big, .small`: 63 | ```typ 64 | $plus.circle.big plus.circle, times.circle.big plus.circle$ 65 | ``` 66 | - `.filled`: fills the symbol 67 | ```typ 68 | $square, square.filled, diamond.filled, arrow.filled$ 69 | ``` 70 | 71 | ### Greek letters 72 | 73 | Lower case letters start with lower case letter, upper case start with upper case. 74 | 75 | For different versions of letters, use `.alt` 76 | 77 | ```typ 78 | $ 79 | alpha, Alpha, beta, Beta, beta.alt, gamma, pi, Pi,\ 80 | pi.alt, phi, phi.alt, Phi, omicron, kappa, kappa.alt, Psi,\ 81 | theta, theta.alt, xi, zeta, rho, rho.alt, kai, Kai, 82 | $ 83 | ``` 84 | 85 | ### Blackboard letters 86 | 87 | Just use double of them. If you want to make some other symbol blackboard, use `bb`: 88 | 89 | ```typ 90 | $bb(A), AA, bb(1)$ 91 | ``` 92 | 93 | ## Fonts issues 94 | 95 | Default font is **New Computer Modern Math**. It is a good font, but there are some inconsistencies. 96 | 97 | Typst maps symbol names to unicode, so if the font has wrong symbols, Typst will display wrong ones. 98 | 99 | ### Empty set 100 | See example: 101 | 102 | ```typ 103 | // nothing in default math font is something bad 104 | $nothing, nothing.rev, diameter$ 105 | 106 | #show math.equation: set text(font: "Fira Math") 107 | 108 | // Fira math is more consistent 109 | $nothing, nothing.rev, diameter$ 110 | ``` 111 | 112 | However, you can fix this with font feature: 113 | 114 | ```typ 115 | #show math.equation: set text(features: ("cv01",)) 116 | 117 | $nothing, nothing.rev, diameter$ 118 | ``` 119 | 120 | Or simply using "show" rule: 121 | 122 | ```typ 123 | #show math.nothing: math.diameter 124 | 125 | $nothing, nothing.rev, diameter$ 126 | ``` -------------------------------------------------------------------------------- /src/packages/physics.md: -------------------------------------------------------------------------------- 1 | # Physics 2 | 3 | ## `physica` 4 | 5 | > Physica (Latin for _natural sciences_) provides utilities that simplify 6 | > otherwise complex and repetitive mathematical expressions in natural sciences. 7 | 8 | > Its [manual](https://github.com/Leedehai/typst-physics/blob/master/physica-manual.pdf) 9 | > provides a full set of demonstrations of how the package could be helpful. 10 | 11 | ### Mathematical physics 12 | 13 | The [packages/math.md](./math.md#common-notations) page has more examples on its 14 | math capabilities. Below is a preview that may be of particular interest in the 15 | domain of physics: 16 | * Calculus: differential, ordinary and partial derivatives 17 | * Optional function name, 18 | * Optional order number or array of order numbers, 19 | * Customizable "d" symbol and product joiner (say, exterior product), 20 | * Overridable total order calculation, 21 | * Vectors and vector fields: div, grad, curl, 22 | * Taylor expansion, 23 | * Dirac braket notations, 24 | * Tensors with abstract index notations, 25 | * Matrix transpose and dagger (conjugate transpose). 26 | * Special matrices: determinant, (anti-)diagonal, identity, zero, Jacobian, 27 | Hessian, etc. 28 | 29 | A partial glimpse: 30 | 31 | ```typ 32 | #import "@preview/physica:0.9.1": * 33 | #show: super-T-as-transpose // put in a #[...] to limit its scope... 34 | #show: super-plus-as-dagger // ...or use scripts() to manually override 35 | 36 | $ dd(x,y,2) quad dv(f,x,d:Delta) quad pdv(,x,y,[2i+1,2+i]) quad 37 | vb(a) va(a) vu(a_i) quad mat(laplacian, div; grad, curl) quad 38 | tensor(T,+a,-b,+c) quad ket(phi) quad A^+ e^scripts(+) A^T integral^T $ 39 | ``` 40 | 41 | ### Isotopes 42 | 43 | ```typ 44 | #import "@preview/physica:0.9.1": isotope 45 | 46 | // a: mass number A 47 | // z: the atomic number Z 48 | $ 49 | isotope(I, a:127), quad isotope("Fe", z:26), quad 50 | isotope("Tl",a:207,z:81) --> isotope("Pb",a:207,z:82) + isotope(e,a:0,z:-1) 51 | $ 52 | ``` 53 | 54 | ### Reduced Planck constant (hbar) 55 | 56 | In the default font, the Typst built-in symbol `planck.reduce` looks a bit off: 57 | on letter "h" there is a slash instead of a horizontal bar, contrary to the 58 | symbol's colloquial name "h-bar". This package offers `hbar` to render the 59 | symbol in the familiar form⁠. Contrast: 60 | 61 | ```typ 62 | #import "@preview/physica:0.9.1": hbar 63 | 64 | $ E = planck.reduce omega => E = hbar omega, wide 65 | frac(planck.reduce^2, 2m) => frac(hbar^2, 2m), wide 66 | (pi G^2) / (planck.reduce c^4) => (pi G^2) / (hbar c^4), wide 67 | e^(frac(i(p x - E t), planck.reduce)) => e^(frac(i(p x - E t), hbar)) $ 68 | ``` 69 | 70 | ## `quill`: quantum diagrams 71 | 72 | > See [documentation](https://github.com/Mc-Zen/quill/tree/main). 73 | 74 | ```typ 75 | #import "@preview/quill:0.2.0": * 76 | #quantum-circuit( 77 | lstick($|0〉$), gate($H$), ctrl(1), rstick($(|00〉+|11〉)/√2$, n: 2), [\ ], 78 | lstick($|0〉$), 1, targ(), 1 79 | ) 80 | ``` 81 | 82 | ```typ 83 | #import "@preview/quill:0.2.0": * 84 | 85 | #let ancillas = (setwire(0), 5, lstick($|0〉$), setwire(1), targ(), 2, [\ ], 86 | setwire(0), 5, lstick($|0〉$), setwire(1), 1, targ(), 1) 87 | 88 | #quantum-circuit( 89 | scale-factor: 80%, 90 | lstick($|ψ〉$), 1, 10pt, ctrl(3), ctrl(6), $H$, 1, 15pt, 91 | ctrl(1), ctrl(2), 1, [\ ], 92 | ..ancillas, [\ ], 93 | lstick($|0〉$), 1, targ(), 1, $H$, 1, ctrl(1), ctrl(2), 94 | 1, [\ ], 95 | ..ancillas, [\ ], 96 | lstick($|0〉$), 2, targ(), $H$, 1, ctrl(1), ctrl(2), 97 | 1, [\ ], 98 | ..ancillas 99 | ) 100 | ``` 101 | 102 | ```typ 103 | #import "@preview/quill:0.2.0": * 104 | 105 | #quantum-circuit( 106 | lstick($|psi〉$), ctrl(1), gate($H$), 1, ctrl(2), meter(), [\ ], 107 | lstick($|beta_00〉$, n: 2), targ(), 1, ctrl(1), 1, meter(), [\ ], 108 | 3, gate($X$), gate($Z$), midstick($|psi〉$) 109 | ) 110 | ``` -------------------------------------------------------------------------------- /src/snippets/layout/shapes.md: -------------------------------------------------------------------------------- 1 | # Shaped boxes with text 2 | 3 | (I guess that will make a package eventually, but let it be a snippet for now) 4 | 5 | ```typ 6 | /// author: JustForFun88 7 | #import "@preview/oxifmt:0.2.1": strfmt 8 | 9 | #let shadow_svg_path = ` 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | `.text 30 | 31 | #let parallelogram(width: 20mm, height: 5mm, angle: 30deg) = { 32 | let δ = height * calc.tan(angle) 33 | ( 34 | ( + δ, 0pt ), 35 | (width + δ * 2, 0pt ), 36 | (width + δ, height), 37 | (0pt, height), 38 | ) 39 | } 40 | 41 | #let hexagon(width: 100pt, height: 30pt, angle: 30deg) = { 42 | let dy = height / 2; 43 | let δ = dy * calc.tan(angle) 44 | ( 45 | (0pt, dy ), 46 | ( + δ, 0pt ), 47 | (width + δ, 0pt ), 48 | (width + δ * 2, dy ), 49 | (width + δ, height), 50 | ( + δ, height), 51 | ) 52 | } 53 | 54 | #let shape_size(vertices) = { 55 | let x_vertices = vertices.map(array.first); 56 | let y_vertices = vertices.map(array.last); 57 | 58 | ( 59 | calc.max(..x_vertices) - calc.min(..x_vertices), 60 | calc.max(..y_vertices) - calc.min(..y_vertices) 61 | ) 62 | } 63 | 64 | #let shadowed_shape(shape: hexagon, fill: none, 65 | stroke: auto, angle: 30deg, shadow_fill: black, alpha: 0.5, 66 | blur: 1.5, blur_margin: 5, dx: 0pt, dy: 0pt, ..args, content 67 | ) = layout(size => context { 68 | let named = args.named() 69 | for key in ("width", "height") { 70 | if key in named and type(named.at(key)) == ratio { 71 | named.insert(key, size.at(key) * named.at(key)) 72 | } 73 | } 74 | 75 | let opts = (blur: blur, flood-color: shadow_fill.to-hex()) 76 | 77 | let content = box(content, ..named) 78 | let size = measure(content) 79 | 80 | let vertices = shape(..size, angle: angle) 81 | let (shape_width, shape_height) = shape_size(vertices) 82 | let margin = opts.blur * blur_margin * 1pt 83 | 84 | opts += ( 85 | canvas-width: shape_width + margin, 86 | canvas-height: shape_height + margin, 87 | flood-opacity: alpha 88 | ) 89 | 90 | opts.viewbox = (0, 0, opts.canvas-width.pt(), opts.canvas-height.pt()).map(str).join(",") 91 | 92 | opts.vertices = ""; 93 | let d = margin / 2; 94 | for (i, p) in vertices.enumerate() { 95 | let prefix = if i == 0 { "M " } else { " L " }; 96 | opts.vertices += prefix + p.map(x => str((x + d).pt())).join(", "); 97 | } 98 | 99 | let svg-shadow = image(bytes(strfmt(shadow_svg_path, ..opts))) 100 | place(dx: dx, dy: dy, svg-shadow) 101 | place(curve(..((curve.move(vertices.at(0)),) + vertices.slice(1).map(curve.line) + (curve.close(),)), fill: fill, stroke: stroke)) 102 | box(h((shape_width - size.width) / 2) + content, width: shape_width) 103 | }) 104 | 105 | #set text(3em); 106 | 107 | #shadowed_shape(shape: hexagon, 108 | inset: 1em, fill: teal, 109 | stroke: 1.5pt + teal.darken(50%), 110 | shadow_fill: red, 111 | dx: 0.5em, dy: 0.35em, blur: 3)[Hello there!] 112 | #shadowed_shape(shape: parallelogram, 113 | inset: 1em, fill: teal, 114 | stroke: 1.5pt + teal.darken(50%), 115 | shadow_fill: red, 116 | dx: 0.5em, dy: 0.35em, blur: 3)[Hello there!] 117 | 118 | ``` -------------------------------------------------------------------------------- /theme/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | /* Open Sans is licensed under the Apache License, Version 2.0. See http://www.apache.org/licenses/LICENSE-2.0 */ 2 | /* Source Code Pro is under the Open Font License. See https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL */ 3 | 4 | /* open-sans-300 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 5 | @font-face { 6 | font-family: 'Open Sans'; 7 | font-style: normal; 8 | font-weight: 300; 9 | src: local('Open Sans Light'), local('OpenSans-Light'), 10 | url('open-sans-v17-all-charsets-300.woff2') format('woff2'); 11 | } 12 | 13 | /* open-sans-300italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 14 | @font-face { 15 | font-family: 'Open Sans'; 16 | font-style: italic; 17 | font-weight: 300; 18 | src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'), 19 | url('open-sans-v17-all-charsets-300italic.woff2') format('woff2'); 20 | } 21 | 22 | /* open-sans-regular - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 23 | @font-face { 24 | font-family: 'Open Sans'; 25 | font-style: normal; 26 | font-weight: 400; 27 | src: local('Open Sans Regular'), local('OpenSans-Regular'), 28 | url('open-sans-v17-all-charsets-regular.woff2') format('woff2'); 29 | } 30 | 31 | /* open-sans-italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 32 | @font-face { 33 | font-family: 'Open Sans'; 34 | font-style: italic; 35 | font-weight: 400; 36 | src: local('Open Sans Italic'), local('OpenSans-Italic'), 37 | url('open-sans-v17-all-charsets-italic.woff2') format('woff2'); 38 | } 39 | 40 | /* open-sans-600 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 41 | @font-face { 42 | font-family: 'Open Sans'; 43 | font-style: normal; 44 | font-weight: 600; 45 | src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'), 46 | url('open-sans-v17-all-charsets-600.woff2') format('woff2'); 47 | } 48 | 49 | /* open-sans-600italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 50 | @font-face { 51 | font-family: 'Open Sans'; 52 | font-style: italic; 53 | font-weight: 600; 54 | src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'), 55 | url('open-sans-v17-all-charsets-600italic.woff2') format('woff2'); 56 | } 57 | 58 | /* open-sans-700 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 59 | @font-face { 60 | font-family: 'Open Sans'; 61 | font-style: normal; 62 | font-weight: 700; 63 | src: local('Open Sans Bold'), local('OpenSans-Bold'), 64 | url('open-sans-v17-all-charsets-700.woff2') format('woff2'); 65 | } 66 | 67 | /* open-sans-700italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 68 | @font-face { 69 | font-family: 'Open Sans'; 70 | font-style: italic; 71 | font-weight: 700; 72 | src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), 73 | url('open-sans-v17-all-charsets-700italic.woff2') format('woff2'); 74 | } 75 | 76 | /* open-sans-800 - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 77 | @font-face { 78 | font-family: 'Open Sans'; 79 | font-style: normal; 80 | font-weight: 800; 81 | src: local('Open Sans ExtraBold'), local('OpenSans-ExtraBold'), 82 | url('open-sans-v17-all-charsets-800.woff2') format('woff2'); 83 | } 84 | 85 | /* open-sans-800italic - latin_vietnamese_latin-ext_greek-ext_greek_cyrillic-ext_cyrillic */ 86 | @font-face { 87 | font-family: 'Open Sans'; 88 | font-style: italic; 89 | font-weight: 800; 90 | src: local('Open Sans ExtraBold Italic'), local('OpenSans-ExtraBoldItalic'), 91 | url('open-sans-v17-all-charsets-800italic.woff2') format('woff2'); 92 | } 93 | 94 | /* source-code-pro-500 - latin_vietnamese_latin-ext_greek_cyrillic-ext_cyrillic */ 95 | @font-face { 96 | font-family: 'Source Code Pro'; 97 | font-style: normal; 98 | font-weight: 500; 99 | src: url('source-code-pro-v11-all-charsets-500.woff2') format('woff2'); 100 | } 101 | -------------------------------------------------------------------------------- /src/typstonomicon/totally-empty.md: -------------------------------------------------------------------------------- 1 | # Empty pages without numbering 2 | 3 | ## Empty pages before chapters starting at odd pages 4 | 5 |
6 | This snippet has been broken on 0.12.0. If someone will help fixing it, this would be cool. 7 |
8 | 9 | `````typ -norender 10 | // author: janekfleper 11 | 12 | #set page(height: 20em) 13 | 14 | #let find-labels(name) = { 15 | return query(name).map(label => label.location().page()) 16 | } 17 | 18 | #let page-header = context { 19 | let empty-pages = find-labels() 20 | let new-chapters = find-labels() 21 | if new-chapters.len() > 0 { 22 | if new-chapters.contains(here().page()) [ 23 | _a new chapter starts on this page_ 24 | #return 25 | ] 26 | 27 | // get the index of the next label 28 | let new-chapter-index = new-chapters.position(page => page > here().page()) 29 | if new-chapter-index != none { 30 | let empty-page = empty-pages.at(new-chapter-index) 31 | if empty-page < here().page() [ 32 | _this is an empty page to make the next chapter start on an odd page_ 33 | #return 34 | ] 35 | } 36 | } 37 | 38 | [and this would be a regular header] 39 | line(length: 100%) 40 | } 41 | 42 | #let page-footer = context { 43 | // since the page breaks in chapter-heading() are inserted after the label, 44 | // the selector has to look "before" the current page to find the relevant label 45 | let empty-page-labels = query(selector().before(here())) 46 | if empty-page-labels.len() > 0 { 47 | let empty-page = empty-page-labels.last().location().page() 48 | // look back at the most recent label 49 | let new-chapter = query(selector().before(here())).last().location().page() 50 | // check that there is no label on the current page 51 | if (new-chapter != here().page()) and (empty-page + 1 == here().page()) [ 52 | _this is an empty page where the page number should be omitted_ 53 | #return 54 | ] 55 | } 56 | 57 | let page-display = counter(page).display(here().page-numbering()) 58 | h(1fr) + page-display + h(1fr) 59 | } 60 | 61 | #show heading.where(level: 1): it => [ 62 | #[] 63 | #pagebreak(to: "even", weak: true) 64 | #[] 65 | #pagebreak(to: "odd", weak: true) 66 | #it.body 67 | #v(2em) 68 | ] 69 | 70 | 71 | #show outline.entry.where(level: 1): it => { 72 | // reverse the results of the label queries to find the last label for the targeted page 73 | // the method array.position() will always return the first one... 74 | let empty-pages = find-labels().rev() 75 | let new-chapters = query().rev() 76 | let empty-page-index = empty-pages.position(page => page == int(it.page.text)) 77 | let new-chapter = new-chapters.at(empty-page-index) 78 | link(new-chapter.location())[#it.body #box(width: 1fr)[#it.fill] #new-chapter.location().page()] 79 | } 80 | 81 | #set page(header: page-header, footer: page-footer, numbering: "1") 82 | 83 | #outline() 84 | 85 | = The explanation 86 | 87 | ``` 88 | These queries reveal where the corresponding tags are found. The actual empty page is always at the location of the label + 1. If an empty page is actually inserted by the pagebreaks, the two labels will cover the page of the heading and one page before that. If no empty page was inserted, both labels will point to the same page which is not an issue either. And even then we can check for the label first to give it a higher priority. 89 | 90 | The first label is always on page 1 and can just be ignored since it points to the (non-existing) empty page before the first chapter. 91 | 92 | pages with the label : #context find-labels() 93 | pages with the label : #context find-labels() 94 | ``` 95 | 96 | = A heading 97 | #lorem(190) 98 | 99 | = Another heading 100 | #lorem(100) 101 | 102 | = The last heading 103 | #lorem(400) 104 | ````` -------------------------------------------------------------------------------- /src/basics/tutorial/functions.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | ## Functions 3 | 4 | ```typ 5 | Okay, let's now move to more complex things. 6 | 7 | First of all, there are *lots of magic* in Typst. 8 | And it major part of it is called "scripting". 9 | 10 | To go to scripting mode, type `#` and *some function name* 11 | after that. We will start with _something dull_: 12 | 13 | #lorem(50) 14 | 15 | _That *function* just generated 50 "Lorem Ipsum" words!_ 16 | ``` 17 | 18 | ## More functions 19 | 20 | ```typ 21 | #underline[functions can do everything!] 22 | 23 | #text(orange)[L]ike #text(size: 0.8em)[Really] #sub[E]verything! 24 | 25 | #figure( 26 | caption: [ 27 | This is a screenshot from one of first theses written in Typst. \ 28 | _All these things are written with #text(blue)[custom functions] too._ 29 | ], 30 | image("../boxes.png", width: 80%) 31 | ) 32 | 33 | In fact, you can #strong[forget] about markup 34 | and #emph[just write] functions everywhere! 35 | 36 | #list[ 37 | All that markup is just a #emph[syntax sugar] over functions! 38 | ] 39 | ``` 40 | 41 | ## How to call functions 42 | 43 | ```typ 44 | First, start with `#`. Then write the name. 45 | Finally, write some parentheses and maybe something inside. 46 | 47 | You can navigate lots of built-in functions 48 | in #link("https://typst.app/docs/reference/")[Official Reference]. 49 | 50 | #quote(block: true, attribution: "Typst Examples Book")[ 51 | That's right, links, quotes and lots of 52 | other document elements are created with functions. 53 | ] 54 | ``` 55 | 56 | ## Function arguments 57 | 58 | ```typ 59 | There are _two types_ of function arguments: 60 | 61 | + *Positional.* Like `50` in `lorem(50)`. 62 | Just write them in parentheses and it will be okay. 63 | If you have many, use commas. 64 | + *Named.* Like in `#quote(attribution: "Whoever")`. 65 | Write the value after a name and a colon. 66 | 67 | If argument is named, it has some _default value_. 68 | To find out what it is, see 69 | #link("https://typst.app/docs/reference/")[Official Typst Reference]. 70 | ``` 71 | 72 | ## Content 73 | 74 | Now we should probably try writing our own functions 75 | 76 | ```typ 77 | The most "universal" type in Typst language is *content*. 78 | Everything you write in the document becomes content. 79 | 80 | #[ 81 | But you can explicitly create it with 82 | _scripting mode_ and *square brackets*. 83 | 84 | There, in square brackets, you can use any markup 85 | functions or whatever you want. 86 | ] 87 | ``` 88 | 89 | ## Markup and code modes 90 | ```typ 91 | When you use `#`, you are "switching" to code mode. 92 | When you use `[]`, you turn back into _markup_ (or content) mode: 93 | 94 | // +-- going from markup (the default mode) to scripting for that function 95 | // | +-- scripting mode: calling `text`, the last argument is markup 96 | // | first arg | 97 | // v vvvvvvvvv vvvv 98 | #rect(width: 5cm, text(red)[hello *world*]) 99 | // ^^^^ ^^^^^^^^^^^^^ just a markup argument for `text` 100 | // | 101 | // +-- calling `rect` in scripting mode, with two arguments: width and other content 102 | ``` 103 | 104 | ## Passing content into functions 105 | ```typ 106 | So what are these square brackets after functions? 107 | 108 | If you *write content right after 109 | function, it will be passed as positional argument there*. 110 | 111 | #quote(block: true)[ 112 | So #text(red)[_that_] allows me to write 113 | _literally anything in things 114 | I pass to #underline[functions]!_ 115 | ] 116 | ``` 117 | 118 | ## Passing content, part II 119 | 120 | `````typ 121 | So, just to make it clear, when I write 122 | 123 | ```typ 124 | - #text(red)[red text] 125 | - #text([red text], red) 126 | - #text("red text", red) 127 | // ^ ^ 128 | // Quotes there mean a plain string, not a content! 129 | // This is just text. 130 | ``` 131 | 132 | It all will result in a #text([red text], red). 133 | ````` 134 | -------------------------------------------------------------------------------- /src/basics/states/states.md: -------------------------------------------------------------------------------- 1 | # States 2 | 3 |
This section may be not very complete and fully updated for last Typst versions. Any contribution is very welcome!.
4 | 5 | Before we start something practical, it is important to understand states in general. 6 | 7 | Here is a good explanation of why do we _need_ them: [Official Reference about states](https://typst.app/docs/reference/introspection/state/). It is highly recommended to read it first. 8 | 9 | So instead of 10 | ```typ -norender 11 | #let x = 0 12 | #let compute(expr) = { 13 | // eval evaluates string as Typst code 14 | // to calculate new x value 15 | x = eval( 16 | expr.replace("x", str(x)) 17 | ) 18 | [New value is #x.] 19 | } 20 | 21 | #compute("10") \ 22 | #compute("x + 3") \ 23 | #compute("x * 2") \ 24 | #compute("x - 5") 25 | ``` 26 | 27 | **THIS DOES NOT COMPILE:** Variables from outside the function are read-only and cannot be modified 28 | 29 | Instead, you should write 30 | 31 | ```typ 32 | #let s = state("x", 0) 33 | #let compute(expr) = [ 34 | // updates x current state with this function 35 | #s.update(x => 36 | eval(expr.replace("x", str(x))) 37 | ) 38 | // and displays it 39 | New value is #context s.get(). 40 | ] 41 | 42 | #compute("10") \ 43 | #compute("x + 3") \ 44 | #compute("x * 2") \ 45 | #compute("x - 5") 46 | 47 | The computations will be made _in order_ they are _located_ in the document. So if you create computations first, but put them in the document later... See yourself: 48 | 49 | #let more = [ 50 | #compute("x * 2") \ 51 | #compute("x - 5") 52 | ] 53 | 54 | #compute("10") \ 55 | #compute("x + 3") \ 56 | #more 57 | ``` 58 | ## Context magic 59 | 60 | So what does this magic `context s.get()` mean? 61 | 62 | > [Context in Reference](https://typst.app/docs/reference/context/) 63 | 64 | In short, it specifies what part of your code (or markup) can _depend on states outside_. This context-expression is packed then as one object, and it is evaluated on layout stage. 65 | 66 | That means it is impossible to look from "normal" code at whatever is inside the `context`. This is a black box that would be known _only after putting it into the document_. 67 | 68 | We will discuss `context` features later. 69 | 70 | ## Operations with states 71 | ### Creating new state 72 | ```typ 73 | #let x = state("state-id") 74 | #let y = state("state-id", 2) 75 | 76 | #x, #y 77 | 78 | State is #context x.get() \ // the same as 79 | #context [State is #y.get()] \ // the same as 80 | #context {"State is" + str(y.get())} 81 | ``` 82 | 83 | ### Update 84 | 85 | Updating is _a content_ that is an instruction. That instruction tells compiler that in this place of document the state _should be updated_. 86 | 87 | ```typ 88 | #let x = state("x", 0) 89 | #context x.get() \ 90 | #let _ = x.update(3) 91 | // nothing happens, we don't put `update` into the document flow 92 | #context x.get() 93 | 94 | #repr(x.update(3)) // this is how that content looks \ 95 | 96 | #context x.update(3) 97 | #context x.get() // Finally! 98 | ``` 99 | 100 | Here we can see one of _important `context` traits_: it "sees" states from outside, but can't see how they change inside it: 101 | 102 | ```typ 103 | #let x = state("x", 0) 104 | 105 | #context { 106 | x.update(3) 107 | str(x.get()) 108 | } 109 | ``` 110 | 111 | ### ID collision 112 | 113 | _TLDR; **Never allow colliding states.**_ 114 | 115 |
116 | States are described by their id-s, if they are the same, the code will break. 117 |
118 | 119 | So, if you write functions or loops that are used several times, _be careful_! 120 | 121 | ```typ 122 | #let f(x) = { 123 | // return new state… 124 | // …but their id-s are the same! 125 | // so it will always be the same state! 126 | let y = state("x", 0) 127 | y.update(y => y + x) 128 | context y.get() 129 | } 130 | 131 | #let a = f(2) 132 | #let b = f(3) 133 | 134 | #a, #b \ 135 | #raw(repr(a) + "\n" + repr(b)) 136 | ``` 137 | 138 | However, this _may seem_ okay: 139 | 140 | ```typ 141 | // locations in code are different! 142 | #let x = state("state-id") 143 | #let y = state("state-id", 2) 144 | 145 | #x, #y 146 | ``` 147 | 148 | But in fact, it _isn't_: 149 | 150 | ```typ 151 | #let x = state("state-id") 152 | #let y = state("state-id", 2) 153 | 154 | #context [#x.get(); #y.get()] 155 | 156 | #x.update(3) 157 | 158 | #context [#x.get(); #y.get()] 159 | ``` 160 | -------------------------------------------------------------------------------- /theme/fonts/SOURCE-CODE-PRO-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /src/packages/boxes.md: -------------------------------------------------------------------------------- 1 | # Custom boxes 2 | 3 | ## Showbox 4 | 5 | ```typ 6 | #import "@preview/showybox:2.0.1": showybox 7 | 8 | #showybox( 9 | [Hello world!] 10 | ) 11 | ``` 12 | 13 | ```typ 14 | #import "@preview/showybox:2.0.1": showybox 15 | 16 | // First showybox 17 | #showybox( 18 | frame: ( 19 | border-color: red.darken(50%), 20 | title-color: red.lighten(60%), 21 | body-color: red.lighten(80%) 22 | ), 23 | title-style: ( 24 | color: black, 25 | weight: "regular", 26 | align: center 27 | ), 28 | shadow: ( 29 | offset: 3pt, 30 | ), 31 | title: "Red-ish showybox with separated sections!", 32 | lorem(20), 33 | lorem(12) 34 | ) 35 | 36 | // Second showybox 37 | #showybox( 38 | frame: ( 39 | dash: "dashed", 40 | border-color: red.darken(40%) 41 | ), 42 | body-style: ( 43 | align: center 44 | ), 45 | sep: ( 46 | dash: "dashed" 47 | ), 48 | shadow: ( 49 | offset: (x: 2pt, y: 3pt), 50 | color: yellow.lighten(70%) 51 | ), 52 | [This is an important message!], 53 | [Be careful outside. There are dangerous bananas!] 54 | ) 55 | ``` 56 | 57 | ```typ 58 | #import "@preview/showybox:2.0.1": showybox 59 | 60 | #showybox( 61 | title: "Stokes' theorem", 62 | frame: ( 63 | border-color: blue, 64 | title-color: blue.lighten(30%), 65 | body-color: blue.lighten(95%), 66 | footer-color: blue.lighten(80%) 67 | ), 68 | footer: "Information extracted from a well-known public encyclopedia" 69 | )[ 70 | Let $Sigma$ be a smooth oriented surface in $RR^3$ with boundary $diff Sigma equiv Gamma$. If a vector field $bold(F)(x,y,z)=(F_x (x,y,z), F_y (x,y,z), F_z (x,y,z))$ is defined and has continuous first order partial derivatives in a region containing $Sigma$, then 71 | 72 | $ integral.double_Sigma (bold(nabla) times bold(F)) dot bold(Sigma) = integral.cont_(diff Sigma) bold(F) dot dif bold(Gamma) $ 73 | ] 74 | ``` 75 | 76 | ```typ 77 | #import "@preview/showybox:2.0.1": showybox 78 | 79 | #showybox( 80 | title-style: ( 81 | weight: 900, 82 | color: red.darken(40%), 83 | sep-thickness: 0pt, 84 | align: center 85 | ), 86 | frame: ( 87 | title-color: red.lighten(80%), 88 | border-color: red.darken(40%), 89 | thickness: (left: 1pt), 90 | radius: 0pt 91 | ), 92 | title: "Carnot cycle's efficiency" 93 | )[ 94 | Inside a Carnot cycle, the efficiency $eta$ is defined to be: 95 | 96 | $ eta = W/Q_H = frac(Q_H + Q_C, Q_H) = 1 - T_C/T_H $ 97 | ] 98 | ``` 99 | 100 | ```typ 101 | #import "@preview/showybox:2.0.1": showybox 102 | 103 | #showybox( 104 | footer-style: ( 105 | sep-thickness: 0pt, 106 | align: right, 107 | color: black 108 | ), 109 | title: "Divergence theorem", 110 | footer: [ 111 | In the case of $n=3$, $V$ represents a volume in three-dimensional space, and $diff V = S$ its surface 112 | ] 113 | )[ 114 | Suppose $V$ is a subset of $RR^n$ which is compact and has a piecewise smooth boundary $S$ (also indicated with $diff V = S$). If $bold(F)$ is a continuously differentiable vector field defined on a neighborhood of $V$, then: 115 | 116 | $ integral.triple_V (bold(nabla) dot bold(F)) dif V = integral.surf_S (bold(F) dot bold(hat(n))) dif S $ 117 | ] 118 | ``` 119 | 120 | ```typ 121 | #import "@preview/showybox:2.0.1": showybox 122 | 123 | #showybox( 124 | frame: ( 125 | border-color: red.darken(30%), 126 | title-color: red.darken(30%), 127 | radius: 0pt, 128 | thickness: 2pt, 129 | body-inset: 2em, 130 | dash: "densely-dash-dotted" 131 | ), 132 | title: "Gauss's Law" 133 | )[ 134 | The net electric flux through any hypothetical closed surface is equal to $1/epsilon_0$ times the net electric charge enclosed within that closed surface. The closed surface is also referred to as Gaussian surface. In its integral form: 135 | 136 | $ Phi_E = integral.surf_S bold(E) dot dif bold(A) = Q/epsilon_0 $ 137 | ] 138 | ``` 139 | 140 | ## Colorful boxes 141 | 142 | ```typ 143 | #import "@preview/colorful-boxes:1.2.0": colorbox, slantedColorbox, outlinebox, stickybox 144 | 145 | #colorbox( 146 | title: lorem(5), 147 | color: "blue", 148 | radius: 2pt, 149 | width: auto 150 | )[ 151 | #lorem(50) 152 | ] 153 | 154 | #slantedColorbox( 155 | title: lorem(5), 156 | color: "red", 157 | radius: 0pt, 158 | width: auto 159 | )[ 160 | #lorem(50) 161 | ] 162 | 163 | #outlinebox( 164 | title: lorem(5), 165 | color: none, 166 | width: auto, 167 | radius: 2pt, 168 | centering: false 169 | )[ 170 | #lorem(50) 171 | ] 172 | 173 | #outlinebox( 174 | title: lorem(5), 175 | color: "green", 176 | width: auto, 177 | radius: 2pt, 178 | centering: true 179 | )[ 180 | #lorem(50) 181 | ] 182 | 183 | #stickybox( 184 | rotation: 3deg, 185 | width: 7cm 186 | )[ 187 | #lorem(20) 188 | ] 189 | ``` 190 | 191 | ## Theorems 192 | 193 | See [math](./math.md) 194 | -------------------------------------------------------------------------------- /src/basics/tutorial/advanced_styling.md: -------------------------------------------------------------------------------- 1 | # Advanced styling 2 | 3 | ## The `show` rule 4 | 5 | ```typ 6 | Advanced styling comes with another rule. The _`show` rule_. 7 | 8 | Now please compare the source code and the output. 9 | 10 | #show "Be careful": strong[Play] 11 | 12 | This is a very powerful thing, sometimes even too powerful. 13 | Be careful with it. 14 | 15 | #show "it is holding me hostage": text(green)[I'm fine] 16 | 17 | Wait, what? I told you "Be careful!", not "Play!". 18 | 19 | Help, it is holding me hostage. 20 | ``` 21 | 22 | ## Now a bit more serious 23 | 24 | ```typ 25 | Show rule is a powerful thing that takes a _selector_ 26 | and what to apply to it. After that it will apply to 27 | all elements it can find. 28 | 29 | It may be extremely useful like that: 30 | 31 | #show emph: set text(blue) 32 | 33 | Now if I want to _emphasize_ something, 34 | it will be both _emphasized_ and _blue_. 35 | Isn't that cool? 36 | ``` 37 | 38 | ## About syntax 39 | 40 | ```typ 41 | Sometimes show rules may be confusing. They may seem very diverse, but in fact they all are quite the same! So 42 | 43 | // actually, this is the same as 44 | // redify = text.with(red) 45 | // `with` creates a new function with that argument already set 46 | #let redify(string) = text(red, string) 47 | 48 | // and this is the same as 49 | // framify = rect.with(stroke: orange) 50 | #let framify(object) = rect(object, stroke: orange) 51 | 52 | // set default color of text blue for all following text 53 | #show: set text(blue) 54 | 55 | Blue text. 56 | 57 | // wrap everything into a frame 58 | #show: framify 59 | 60 | Framed text. 61 | 62 | // it's the same, just creating new function that calls framify 63 | #show: a => framify(a) 64 | 65 | Double-framed. 66 | 67 | // apply function to `the` 68 | #show "the": redify 69 | // set text color for all the headings 70 | #show heading: set text(purple) 71 | 72 | = Conclusion 73 | 74 | All these rules are doing basically the same thing! 75 | ``` 76 | 77 | ## Blocks 78 | 79 | One of the most important usages is that you can set up all spacing using blocks. Like every element with text contains text that can be set up, every _block element_ contains blocks: 80 | 81 | ```typ 82 | Text before 83 | = Heading 84 | Text after 85 | 86 | #show heading: set block(spacing: 0.5em) 87 | 88 | Text before 89 | = Heading 90 | Text after 91 | ``` 92 | 93 | ## Selector 94 | 95 | ```typ 96 | So show rule can accept _selectors_. 97 | 98 | There are lots of different selector types, 99 | for example 100 | 101 | - element functions 102 | - strings 103 | - regular expressions 104 | - field filters 105 | 106 | Let's see example of the latter: 107 | 108 | #show heading.where(level: 1): set align(center) 109 | 110 | = Title 111 | == Small title 112 | 113 | Of course, you can set align by hand, 114 | no need to use show rules 115 | (but they are very handy!): 116 | 117 | #align(center)[== Centered small title] 118 | ``` 119 | 120 | ## Custom formatting 121 | 122 | ```typ 123 | Let's try now writing custom functions. 124 | It is very easy, see yourself: 125 | 126 | // "it" is a heading, we take it and output things in braces 127 | #show heading: it => { 128 | // center it 129 | set align(center) 130 | // set size and weight 131 | set text(12pt, weight: "regular") 132 | // see more about blocks and boxes 133 | // in corresponding chapter 134 | block(smallcaps(it.body)) 135 | } 136 | 137 | = Smallcaps heading 138 | 139 | ``` 140 | 141 | ## Setting spacing 142 | 143 | TODO: explain block spacing for common elements 144 | 145 | ## Formatting to get an "article look" 146 | 147 | ```typ 148 | #set page( 149 | // Header is that small thing on top 150 | header: align( 151 | right + horizon, 152 | [Some header there] 153 | ), 154 | height: 12cm 155 | ) 156 | 157 | #align(center, text(17pt)[ 158 | *Important title* 159 | ]) 160 | 161 | #grid( 162 | columns: (1fr, 1fr), 163 | align(center)[ 164 | Some author \ 165 | Some Institute \ 166 | #link("mailto:some@mail.edu") 167 | ], 168 | align(center)[ 169 | Another author \ 170 | Another Institute \ 171 | #link("mailto:another@mail.edu") 172 | ] 173 | ) 174 | 175 | Now let's split text into two columns: 176 | 177 | #show: rest => columns(2, rest) 178 | 179 | #show heading.where( 180 | level: 1 181 | ): it => block(width: 100%)[ 182 | #set align(center) 183 | #set text(12pt, weight: "regular") 184 | #smallcaps(it.body) 185 | ] 186 | 187 | #show heading.where( 188 | level: 2 189 | ): it => text( 190 | size: 11pt, 191 | weight: "regular", 192 | style: "italic", 193 | it.body + [.], 194 | ) 195 | 196 | // Now let's fill it with words: 197 | 198 | = Heading 199 | == Small heading 200 | #lorem(10) 201 | == Second subchapter 202 | #lorem(10) 203 | = Second heading 204 | #lorem(40) 205 | 206 | == Second subchapter 207 | #lorem(40) 208 | ``` 209 | -------------------------------------------------------------------------------- /src/snippets/demos.md: -------------------------------------------------------------------------------- 1 | # Demos 2 | 3 | ## Resume (using template) 4 | 5 | ```typ 6 | #import "@preview/modern-cv:0.8.0": * 7 | 8 | #show: resume.with( 9 | author: ( 10 | firstname: "John", 11 | lastname: "Smith", 12 | email: "js@example.com", 13 | homepage: "https://example.com", 14 | phone: "(+1) 111-111-1111", 15 | github: "DeveloperPaul123", 16 | twitter: "typstapp", 17 | scholar: "", 18 | orcid: "0000-0000-0000-000X", 19 | birth: "January 1, 1990", 20 | linkedin: "Example", 21 | address: "111 Example St. Example City, EX 11111", 22 | positions: ( 23 | "Software Engineer", 24 | "Software Architect", 25 | "Developer", 26 | ), 27 | ), 28 | profile-picture: none, 29 | date: datetime.today().display(), 30 | language: "en", 31 | colored-headers: true, 32 | show-footer: false, 33 | paper-size: "us-letter", 34 | ) 35 | 36 | = Experience 37 | 38 | #resume-entry( 39 | title: "Senior Software Engineer", 40 | location: "Example City, EX", 41 | date: "2019 - Present", 42 | description: "Example, Inc.", 43 | title-link: "https://github.com/DeveloperPaul123", 44 | ) 45 | 46 | #resume-item[ 47 | - #lorem(20) 48 | - #lorem(15) 49 | - #lorem(25) 50 | ] 51 | 52 | #resume-entry( 53 | title: "Software Engineer", 54 | location: "Example City, EX", 55 | date: "2011 - 2019", 56 | description: "Previous Company, Inc.", 57 | ) 58 | 59 | #resume-item[ 60 | // content doesn't have to be bullet points 61 | #lorem(72) 62 | ] 63 | 64 | #resume-entry( 65 | title: "Intern", 66 | location: "Example City, EX", 67 | ) 68 | 69 | #resume-item[ 70 | - #lorem(20) 71 | - #lorem(15) 72 | - #lorem(25) 73 | ] 74 | 75 | = Projects 76 | 77 | #resume-entry( 78 | title: "Thread Pool C++ Library", 79 | location: [#github-link("DeveloperPaul123/thread-pool")], 80 | date: "May 2021 - Present", 81 | description: "Designer/Developer", 82 | ) 83 | 84 | #resume-item[ 85 | - Designed and implemented a thread pool library in C++ using the latest C++20 and C++23 features. 86 | - Wrote extensive documentation and unit tests for the library and published it on Github. 87 | ] 88 | 89 | #resume-entry( 90 | title: "Event Bus C++ Library", 91 | location: github-link("DeveloperPaul123/eventbus"), 92 | date: "Sep. 2019 - Present", 93 | description: "Designer/Developer", 94 | ) 95 | 96 | #resume-item[ 97 | - Designed and implemented an event bus library using C++17. 98 | - Wrote detailed documentation and unit tests for the library and published it on Github. 99 | ] 100 | 101 | = Skills 102 | 103 | #resume-skill-item( 104 | "Languages", 105 | (strong("C++"), strong("Python"), "Java", "C#", "JavaScript", "TypeScript"), 106 | ) 107 | #resume-skill-item("Spoken Languages", (strong("English"), "Spanish")) 108 | #resume-skill-item( 109 | "Programs", 110 | (strong("Excel"), "Word", "Powerpoint", "Visual Studio"), 111 | ) 112 | 113 | = Education 114 | 115 | #resume-entry( 116 | title: "Example University", 117 | location: "Example City, EX", 118 | date: "August 2014 - May 2019", 119 | description: "B.S. in Computer Science", 120 | ) 121 | 122 | #resume-item[ 123 | - #lorem(20) 124 | - #lorem(15) 125 | - #lorem(25) 126 | ] 127 | ``` 128 | 129 | ## Book cover 130 | ```typ 131 | // author: bamdone 132 | #let accent = rgb("#00A98F") 133 | #let accent1 = rgb("#98FFB3") 134 | #let accent2 = rgb("#D1FF94") 135 | #let accent3 = rgb("#D3D3D3") 136 | #let accent4 = rgb("#ADD8E6") 137 | #let accent5 = rgb("#FFFFCC") 138 | #let accent6 = rgb("#F5F5DC") 139 | 140 | #set page(paper: "a4",margin: 0.0in, fill: accent) 141 | 142 | #set rect(stroke: 4pt) 143 | #move( 144 | dx: -6cm, dy: 1.0cm, 145 | rotate(-45deg, 146 | rect( 147 | width: 100cm, 148 | height: 2cm, 149 | radius: 50%, 150 | stroke: 0pt, 151 | fill:accent1, 152 | ))) 153 | 154 | #set rect(stroke: 4pt) 155 | #move( 156 | dx: -2cm, dy: -1.0cm, 157 | rotate(-45deg, 158 | rect( 159 | width: 100cm, 160 | height: 2cm, 161 | radius: 50%, 162 | stroke: 0pt, 163 | fill:accent2, 164 | ))) 165 | 166 | #set rect(stroke: 4pt) 167 | #move( 168 | dx: 8cm, dy: -10cm, 169 | rotate(-45deg, 170 | rect( 171 | width: 100cm, 172 | height: 1cm, 173 | radius: 50%, 174 | stroke: 0pt, 175 | fill:accent3, 176 | ))) 177 | 178 | #set rect(stroke: 4pt) 179 | #move( 180 | dx: 7cm, dy: -8cm, 181 | rotate(-45deg, 182 | rect( 183 | width: 1000cm, 184 | height: 2cm, 185 | radius: 50%, 186 | stroke: 0pt, 187 | fill:accent4, 188 | ))) 189 | 190 | #set rect(stroke: 4pt) 191 | #move( 192 | dx: 0cm, dy: -0cm, 193 | rotate(-45deg, 194 | rect( 195 | width: 1000cm, 196 | height: 2cm, 197 | radius: 50%, 198 | stroke: 0pt, 199 | fill:accent1, 200 | ))) 201 | 202 | #set rect(stroke: 4pt) 203 | #move( 204 | dx: 9cm, dy: -7cm, 205 | rotate(-45deg, 206 | rect( 207 | width: 1000cm, 208 | height: 1.5cm, 209 | radius: 50%, 210 | stroke: 0pt, 211 | fill:accent6, 212 | ))) 213 | 214 | #set rect(stroke: 4pt) 215 | #move( 216 | dx: 16cm, dy: -13cm, 217 | rotate(-45deg, 218 | rect( 219 | width: 1000cm, 220 | height: 1cm, 221 | radius: 50%, 222 | stroke: 0pt, 223 | fill:accent2, 224 | ))) 225 | 226 | #align(center)[ 227 | #rect(width: 30%, 228 | fill: accent4, 229 | stroke:none, 230 | [#align(center)[ 231 | #text(size: 60pt,[Title]) 232 | ] 233 | ]) 234 | ] 235 | 236 | #align(center)[ 237 | #rect(width: 30%, 238 | fill: accent4, 239 | stroke:none, 240 | [#align(center)[ 241 | #text(size: 20pt,[author]) 242 | ] 243 | ]) 244 | ] 245 | ``` -------------------------------------------------------------------------------- /src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | - [About](./about.md) 3 | - [Getting Started with Typst](./getting_started.md) 4 | 5 | # The Book 6 | - [Typst Basics](./basics/index.md) 7 | - [Tutorial by Examples](./basics/tutorial/index.md) 8 | - [Markup language](./basics/tutorial/markup.md) 9 | - [Functions](./basics/tutorial/functions.md) 10 | - [Cheatsheet](./basics/tutorial/cheatsheet.md) 11 | - [Basic styling](./basics/tutorial/basic_styling.md) 12 | - [Advanced styling](./basics/tutorial/advanced_styling.md) 13 | - [Templates](./basics/tutorial/templates.md) 14 | - [Must-know](./basics/must_know/index.md) 15 | - [Boxing & Blocking](./basics/must_know/box_block.md) 16 | - [Spacing](./basics/must_know/spacing.md) 17 | - [Placing, Moving, Scale & Hide](./basics/must_know/place.md) 18 | - [Align & Padding]() 19 | - [Tables & Grids](./basics/must_know/tables.md) 20 | - [Project structure](./basics/must_know/project_struct.md) 21 | - [Scripting](./basics/scripting/index.md) 22 | - [Basics](./basics/scripting/basics.md) 23 | - [Braces, brackets and default](./basics/scripting/braces.md) 24 | - [Types, part I](./basics/scripting/types.md) 25 | - [Types, part II](./basics/scripting/types_2.md) 26 | - [Conditions & loops](./basics/scripting/conditions.md) 27 | - [Advanced arguments](./basics/scripting/arguments.md) 28 | - [Tips](./basics/scripting/tips.md) 29 | - [States, Query, Context Dependence](./basics/states/index.md) 30 | - [States](./basics/states/states.md) 31 | - [Counters](./basics/states/counters.md) 32 | - [Context](./basics/states/context.md) 33 | - [Measure, Layout](./basics/states/measure.md) 34 | - [Query](./basics/states/query.md) 35 | - [Metadata](./basics/states/metadata.md) 36 | - [Math](./basics/math/index.md) 37 | - [Symbols](./basics/math/symbols.md) 38 | - [Grouping](./basics/math/grouping.md) 39 | - [Alignment](./basics/math/alignment.md) 40 | - [Limits](./basics/math/limits.md) 41 | - [Operators](./basics/math/operators.md) 42 | - [Location and sizes](./basics/math/sizes.md) 43 | - [Vectors, Matrices, Semicolon syntax](./basics/math/vec.md) 44 | - [Classes](./basics/math/classes.md) 45 | - [Special symbols](./basics/special_symbols.md) 46 | - [Extra](./basics/extra.md) 47 | - [Typst Snippets](./snippets/index.md) 48 | - [Demos](./snippets/demos.md) 49 | - [Logos & Figures](./snippets/logos.md) 50 | - [Labels](./snippets/labels.md) 51 | - [Chapters]() 52 | - [Headings]() 53 | - [Page numbering](./snippets/chapters/page-numbering.md) 54 | - [Outlines](./snippets/chapters/outlines.md) 55 | - [Bibliography]() 56 | - [General layout]() 57 | - [Page setup](./snippets/layout/page_setup.md) 58 | - [Hiding](./snippets/layout/hiding.md) 59 | - [Multiline detection](./snippets/layout/multiline_detect.md) 60 | - [Duplicate content](./snippets/layout/duplicate.md) 61 | - [Lines between list items](./snippets/layout/insert_lines.md) 62 | - [Shadowed shape](./snippets/layout/shapes.md) 63 | - [Code formatting](./snippets/code.md) 64 | - [Tables & grids](./snippets/grids.md) 65 | - [Hyphenation]() 66 | - [Scripting](./snippets/scripting/index.md) 67 | - [Data loading]() 68 | - [Json](./snippets/dataload/json.md) 69 | - [Numbering](./snippets/numbering.md) 70 | - [Math]() 71 | - [Numbering](./snippets/math/numbering.md) 72 | - [Operations](./snippets/math/operations.md) 73 | - [Scripts](./snippets/math/scripts.md) 74 | - [Vectors & Matrices](./snippets/math/vecs.md) 75 | - [Fonts](./snippets/math/fonts.md) 76 | - [Text & Content]() 77 | - [Calligraphic letters](./snippets/math/calligraphic.md) 78 | - [Color & Gradients](./snippets/gradients.md) 79 | - [Pretty things](./snippets/pretty.md) 80 | - [Text]() 81 | - [First line indent](./snippets/text/line_indent.md) 82 | - [Individual language fonts](./snippets/text/individual_lang_fonts.md) 83 | - [Fake italic & Text shadows](./snippets/text/text_shadows.md) 84 | - [Special documents](./snippets/special/index.md) 85 | - [Use with external tools](./snippets/external.md) 86 | 87 | - [Typst Packages](./packages/index.md) 88 | - [Overview]() 89 | - [Drawing](./packages/drawing.md) 90 | - [Graphs](./packages/graphs.md) 91 | 92 | - [Math](./packages/math.md) 93 | - [Physics](./packages/physics.md) 94 | - [Tables](./packages/tables.md) 95 | - [Code](./packages/code.md) 96 | 97 | - [Themes]() 98 | - [Layout](./packages/layout.md) 99 | - [Wrapping figures](./packages/wrapping.md) 100 | - [Scripting]() 101 | - [Misc](./packages/misc.md) 102 | - [Headers](./packages/headers.md) 103 | - [Glossary](./packages/glossary.md) 104 | - [Counting words](./packages/word_count.md) 105 | - [External](./packages/external.md) 106 | 107 | - [Typstonomicon, or The Code You Should Not Write](./typstonomicon/index.md) 108 | - [Word count](./typstonomicon/word_count.md) 109 | - [Try & Catch](./typstonomicon/try_catch.md) 110 | - [Breakpoints on broken blocks](./typstonomicon/block_break.md) 111 | - [Extracting plain text](./typstonomicon/extract_plain_text.md) 112 | - [Inline with](./typstonomicon/inline_with.md) 113 | - [Create zero-level chapters](./typstonomicon/chapters.md) 114 | - [Make all math display](./typstonomicon/math_display.md) 115 | - [Empty pages without numbering](./typstonomicon/totally-empty.md) 116 | - [Multiple show rules](./typstonomicon/multiple-show.md) 117 | - [Removing indent of nested lists](./typstonomicon/remove-indent-nested.md) 118 | -------------------------------------------------------------------------------- /src/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | Typst is an open-source project that can be built into a pretty small binary, that is very easy to install or even use in Web. Typst is managed and built by a company, a company, the main product of which is Typst editing Web App. 4 | 5 | So there are two possibilities for working with Typst: use online Web App or install Typst locally and work with it from your favorite editor. I will briefly cover these two ways with their pros and cons in this chapter. 6 | 7 | ## WebApp 8 | 9 | Starting is pretty simple: sign on [typst.app](https://typst.app) and create a new document. Then... Just start typing, and the document with your text will appear in the preview Panel. 10 | 11 | I highly recommend starting from scratch at first to try things. When you get some better understanding on Typst, you can continue with _templates_, instructions to style your document ready-to-use. But even then, sometimes it is just easier to make all you need exactly as you need from scratch. Typst makes it easy. 12 | 13 | **Pros**: 14 | 15 | - Very easy to start 16 | - Perfect for collaboration. 17 | - _Features:_ Typst Team has put lots of effort into the app, so it has a lot of pretty good features (like smart dictionary check or Vim keybindings for pros). 18 | - _Working Offline_: Once the page is loaded, you can go offline. Compiling document is done on your computer, so you don't need internet connection to make it. And all changes will be saved locally. 19 | - Easy to work with same projects across devices. 20 | - Comes with even more cool features at their paid plan, Typst Pro: like comments for collaboration and Github sync. 21 | It's also a pretty good opportunity to support the project (though there are other ways to support them, like Github Sponsors, contributing and spreading the word about Typst `:)`). 22 | 23 | **Cons**: 24 | 25 | - Still requires internet 26 | - Your data is stored online, your development (however, you can make backups and the app crashes very rarely) 27 | - The App lacks some features that are present in local editors and Tinymist LSP. 28 | - With local compiler, you can do pretty wild automations, like making automatic report generators. 29 | 30 | 31 | ## Local development 32 | 33 | ### Tinymist 34 | 35 | > Don't use Typst LSP, that's a very outdated thing. 36 | 37 | Tinymist is a community-developed LSP [^1] that probably has even more features than Web App (well, that may change in some time, and I'm not known for keeping this book very up-to-date). These include things like going-to-defenition, refactoring, formatting,, opening packages the errors are comming from and many-many others. It's not "official", but it doesn't make it any worse. It is definitely worth trying. 38 | 39 | Works with pretty much any editor supporting LSP. For VS Cod(e,ium), Neovim, Emacs, Sublime Text, Helix and Zed there are also useful frontends available. 40 | 41 | So, to use Typst locally, it's probably enough to open your favourite editor, install Tinymist extension and get a full Typst experience with live preview and many other nice things. 42 | 43 | > Tinymist uses Typst as a library, so it comes with it's own inner Typst version. Sometimes, for example, if your VS Code version is too old, it can't install newer version, and you end up with old Typst version without knowing it. 44 | 45 | > Oh, yep, Tinymist can export documents in any needed format, by the way. You can also set up it to do it automatically on save, too. 46 | 47 | > And it's actually possible to just use `tinymist preview document.typ` from terminal, if it's a properly installed tool (that would open a browser preview). 48 | 49 | **Pros:** 50 | 51 | - _Features:_ probably _the largest set_ available for Typst. 52 | - Best for programmers or experienced users. 53 | - It's just a LSP, all other things you need come from your editor, system and so on. It's easy to work with Github, easy to integrate it in whatever you want. 54 | 55 | **Cons:** 56 | 57 | - It's probably a bit harder than just launching WebApp. 58 | - Collaborating that way is much harder. It requires using Github or setting up your editor. 59 | - Worse portability (you have to sync your files). 60 | - There are tiny chances that the development will be dropped in future. 61 | 62 | ### CLI 63 | 64 | Typst also comes with it's own CLI (command-line-tool). This way, it is enough to install on your system and then launch from terminal `typst c your_file.typ` (or `compile` instead of `c`) to get a PDF, compiled from your `your_file.typ` document. 65 | 66 | > Installation notes: 67 | > - Windows users: just download the exe from Github Releases and unpack it somewhere in your PATH 68 | > - Unix users: https://github.com/typst/typst?tab=readme-ov-file#installation. 69 | > Note: Typst version sometimes significantly lags at package managers (and it's not Typst' fault). 70 | 71 | This way, you can open your favorite text editor, like Notepad (or Vim without any plugins), write Typst document there, then compiling it and looking at the result. 72 | 73 | CLI also supports _watching_ file: `typst w your_file.typ` (or `watch` instead of `w`). That way, Typst will recompile it each time it is changed (and saved). 74 | 75 | That way, however, I recommend having a _live preview PDF viewer_, that would update the viewed PDF as it is changed with need for reload. 76 | 77 | These include: 78 | 79 | - SumatraPDF (works on Windows) 80 | - Zathura and Sioyek (Linux) 81 | - Okular (cross-platform) 82 | - MuPDF (must be combined with `entr` on Unix) 83 | - (some others I've forgotten, feel free to make an Issue / PR) 84 | 85 | (note that it is not perfect, there probably would be some blinking, but it's much better than having to reload) 86 | 87 | **Pros:** 88 | - Perfect for "I need to quickly compile this file". You can use it along with Tinymist, using Tinymist for preview and editing, and CLI for the fast and precise exporting. 89 | - Perfect for complex automations and using it from other apps. 90 | - Can self-update for required version with one command (if installed not from package manager) 91 | 92 | **Cons:** 93 | - Harder to use 94 | - Doesn't provide editor features 95 | 96 | ## Let's go 97 | 98 | I hope you have managed to get something working, so let's go diving into Typst! 99 | 100 | [^1]: A language-server protocol, a thing that provides cool things like autocompletion or refactoring features for most editors. --------------------------------------------------------------------------------