Touying is a powerful package for creating presentation slides in Typst.
See the codeTouying (投影 in Chinese, /tóuyǐng/, meaning projection) is a user-friendly, powerful, and efficient package for creating presentation slides in Typst.
If you like it, consider giving a star ⭐ on GitHub. Touying is a community-driven project — feel free to suggest ideas and contribute!
#pause, #meanwhile, math equation animations, CeTZ & Fletcher supportA big release, and the first that requires Typst 0.15.
The main new feature is article mode: the same source file compiles either to slides or to a flowing prose document, with animations collapsed to their final state and images optionally floated to the side.
Two new animation entry points come with it.
touying-render renders a piece of content at chosen animation stages, andanimate combines visibility and styling on one piece of contentOther improvements:
frac or mat.touying-recall was extended from whole slides to any labelled elementtouying-fn-wrapper-raw now parses and nests its body, so #alert[.. #pause ..] works, and much more besidesparbreak.pdfpc files can be written directly as bundle assets instead of through a separate typst query stepmeasure function that overrides typst's own one. Supports measuring animated content.touying-reducer making integration of other packages more straight-forwardalpha-changing-cover and color-changing-cover have been overhauled and are perfect cover functions now.Internally, src/core.typ (6288 lines) was split into modules and the content handling was unified and several functions (mainly out of utils) moved places.
Things to watch when upgrading:
#pause after uncover/only/alternatives no longer skips the subslides they reserve (they wrongfully did so in v0.7.x),semi-transparent-cover is deprecated in favor of alpha-changing-cover and color-changing-cover, andMost documentation pages were rewritten or corrected.
For more information, a migration guide, and a separate one for theme authors, see the detailed changelog.
Choose the workflow that fits how you want to work with Touying:
Then create a .typ file with the following content:
#import "@preview/touying:0.8.0": *
#import themes.simple: *
#show: simple-theme.with(aspect-ratio: "16-9")
= Title
== First Slide
Hello, Touying!
#pause
Hello, Typst!
Congratulations on creating your first Touying slide! 🎉
Touying supports incremental reveal with #pause and #meanwhile, math equation animations, and integrations with CeTZ and Fletcher:
| Math equations | CeTZ & Fletcher |
|---|---|
For the full feature set — cover mode, callback-style animations, #uncover, #only, #alternatives — see the documentation.
For a comprehensive example showcasing university theme, theorems, CeTZ/Fletcher animations, speaker notes, and more. You can also use the #slide[..] format to access more powerful features provided by Touying.
#import "@preview/touying:0.8.0": *
#import themes.university: *
#import "@preview/cetz:0.5.2"
#import "@preview/fletcher:0.5.8" as fletcher: node, edge
#import "@preview/numbly:0.1.0": numbly
#import "@preview/theorion:0.6.0": *
#import cosmos.clouds: *
#show: show-theorion
// cetz and fletcher bindings for touying
#let cetz-canvas = touying-reduce.with(cetz)
#let fletcher-diagram = touying-reduce.with(fletcher)
#show: university-theme.with(
aspect-ratio: "16-9",
// align: horizon,
// config-common(handout: true),
config-common(frozen-counters: (theorem-counter,)), // freeze theorem counter for animation
config-info(
title: [Title],
subtitle: [Subtitle],
author: [Authors],
date: datetime.today(),
institution: [Institution],
logo: emoji.school,
),
)
#set heading(numbering: numbly("{1}.", default: "1.1"))
#title-slide()
== Outline <touying:hidden>
#components.adaptive-columns(outline(title: none, indent: 1em))
= Animation
== Simple Animation
We can use `#pause` to #pause display something later.
#pause
Just like this.
#meanwhile
Meanwhile, #pause we can also use `#meanwhile` to #pause display other content synchronously.
#speaker-note[
+ This is a speaker note.
+ You won't see it unless you use `config-common(show-notes-on-second-screen: right)`
]
== Complex Animation
At subslide #touying-get-config("subslide"), we can
use #uncover("2-")[`#uncover` function] for reserving space,
use #only("2-")[`#only` function] for not reserving space,
#alternatives[call `#only` multiple times \u{2717}][use `#alternatives` function #sym.checkmark] for choosing one of the alternatives.
== Callback Style Animation
#slide(
repeat: 3,
self => [
#let (uncover, only, alternatives) = utils.methods(self)
At subslide #self.subslide, we can
use #uncover("2-")[`#uncover` function] for reserving space,
use #only("2-")[`#only` function] for not reserving space,
#alternatives[call `#only` multiple times \u{2717}][use `#alternatives` function #sym.checkmark] for choosing one of the alternatives.
],
)
== Math Equation Animation
Equation with `pause`:
$
f(x) &= pause x^2 + 2x + 1 \
&= pause (x + 1)^2 \
$
#meanwhile
Here, #pause we have the expression of $f(x)$.
#pause
By factorizing, we can obtain this result.
== CeTZ Animation
CeTZ Animation in Touying:
#cetz-canvas({
import cetz.draw: *
rect((0, 0), (5, 5))
(pause,)
rect((0, 0), (1, 1))
rect((1, 1), (2, 2))
rect((2, 2), (3, 3))
(pause,)
line((0, 0), (2.5, 2.5), name: "line")
})
== Fletcher Animation
Fletcher Animation in Touying:
#fletcher-diagram(
node-stroke: .1em,
node-fill: gradient.radial(blue.lighten(80%), blue, center: (30%, 20%), radius: 80%),
spacing: 4em,
edge((-1, 0), "r", "-|>", `open(path)`, label-pos: 0, label-side: center),
node((0, 0), `reading`, radius: 2em),
edge((0, 0), (0, 0), `read()`, "--|>", bend: 130deg),
pause,
edge(`read()`, "-|>"),
node((1, 0), `eof`, radius: 2em),
pause,
edge(`close()`, "-|>"),
node((2, 0), `closed`, radius: 2em, extrude: (-2.5, 0)),
edge((0, 0), (2, 0), `close()`, "-|>", bend: -40deg),
)
= Theorems
== Prime numbers
#definition[
A natural number is called a #highlight[_prime number_] if it is greater
than 1 and cannot be written as the product of two smaller natural numbers.
]
#example[
The numbers $2$, $3$, and $17$ are prime.
@cor_largest_prime shows that this list is not exhaustive!
]
#theorem(title: "Euclid")[
There are infinitely many primes.
]
#pagebreak(weak: true)
#proof[
Suppose to the contrary that $p_1, p_2, dots, p_n$ is a finite enumeration
of all primes. Set $P = p_1 p_2 dots p_n$. Since $P + 1$ is not in our list,
it cannot be prime. Thus, some prime factor $p_j$ divides $P + 1$. Since
$p_j$ also divides $P$, it must divide the difference $(P + 1) - P = 1$, a
contradiction.
]
#corollary[
There is no largest prime number.
] <cor_largest_prime>
#corollary[
There are infinitely many composite numbers.
]
#theorem[
There are arbitrarily long stretches of composite numbers.
]
#proof[
For any $n > 2$, consider $
n! + 2, quad n! + 3, quad ..., quad n! + n
$
]
= Others
== Multiple columns
#cols[
First column.
][
Second column.
]
== Multiple columns with equal height blocks
#cols(columns: (1fr, 1fr), gutter: 1em, lazy-layout: true)[
#emph-block[
First column with equal height: #lorem(10)
#lazy-v(1fr)
]
][
#emph-block[
Second column with equal height: : #lorem(15)
#lazy-v(1fr)
]
]
== Multiple Pages
#lorem(200)
#show: appendix
= Appendix
== Appendix
Please pay attention to the current slide number.
Touying provides the presentation engine and keeps the result in readable, portable Typst source. These companion projects add higher-level generation and editing workflows without replacing that source-first foundation.
SeaSlides Skill is an AI-native presentation-generation skill and toolchain built around Touying. Give it a topic, document, URL, or Markdown file and it can plan the narrative, select or create a theme, author editable Typst/Touying source, add speaker notes, compile the deck, run quality checks, and export PDF, PNG, or PPTX. Quick Mode produces a fast first draft; Full Mode adds research, asset generation, a separate design specification, and deeper visual review.
Tylina is our recommended AI-native, document-first, WYSIWYG Typst
editor and presenter, available in the browser and as a desktop app. The typeset page
is the editor—not merely a preview: edit it directly, or open Source Lens or Split for source-level
control. Its document-aware agents can edit, compile, and check the same canonical .typ workspace
while every change remains reviewable. Tylina also manages slides and speaker notes, reorders pages,
and presents the deck.
Open the Touying example in Tylina Web · Download the desktop app
Tylina has two PowerPoint export modes, both preserving speaker notes:
See the Tylina integration guide for details.

Generate with the SeaSlides Skill, then inspect, edit, reorder, and present in Tylina.

Start from a curated presentation design or browse the wider Typst Universe without leaving Tylina.
Thanks to...
polylux packagemetropolis themeuniversity themeaqua themestargazer themefit-to-height, fit-to-width and cover-with-rect(top 24 of 76)
221 followers · starred Nov 2025
325 followers · starred Apr 2026
82 followers · starred Jun 2025
8,472 followers · starred Jun 2024
Touying is a powerful package for creating presentation slides in Typst.
See the codeTouying (投影 in Chinese, /tóuyǐng/, meaning projection) is a user-friendly, powerful, and efficient package for creating presentation slides in Typst.
If you like it, consider giving a star ⭐ on GitHub. Touying is a community-driven project — feel free to suggest ideas and contribute!
#pause, #meanwhile, math equation animations, CeTZ & Fletcher supportA big release, and the first that requires Typst 0.15.
The main new feature is article mode: the same source file compiles either to slides or to a flowing prose document, with animations collapsed to their final state and images optionally floated to the side.
Two new animation entry points come with it.
touying-render renders a piece of content at chosen animation stages, andanimate combines visibility and styling on one piece of contentOther improvements:
frac or mat.touying-recall was extended from whole slides to any labelled elementtouying-fn-wrapper-raw now parses and nests its body, so #alert[.. #pause ..] works, and much more besidesparbreak.pdfpc files can be written directly as bundle assets instead of through a separate typst query stepmeasure function that overrides typst's own one. Supports measuring animated content.touying-reducer making integration of other packages more straight-forwardalpha-changing-cover and color-changing-cover have been overhauled and are perfect cover functions now.Internally, src/core.typ (6288 lines) was split into modules and the content handling was unified and several functions (mainly out of utils) moved places.
Things to watch when upgrading:
#pause after uncover/only/alternatives no longer skips the subslides they reserve (they wrongfully did so in v0.7.x),semi-transparent-cover is deprecated in favor of alpha-changing-cover and color-changing-cover, andMost documentation pages were rewritten or corrected.
For more information, a migration guide, and a separate one for theme authors, see the detailed changelog.
Choose the workflow that fits how you want to work with Touying:
Then create a .typ file with the following content:
#import "@preview/touying:0.8.0": *
#import themes.simple: *
#show: simple-theme.with(aspect-ratio: "16-9")
= Title
== First Slide
Hello, Touying!
#pause
Hello, Typst!
Congratulations on creating your first Touying slide! 🎉
Touying supports incremental reveal with #pause and #meanwhile, math equation animations, and integrations with CeTZ and Fletcher:
| Math equations | CeTZ & Fletcher |
|---|---|
For the full feature set — cover mode, callback-style animations, #uncover, #only, #alternatives — see the documentation.
For a comprehensive example showcasing university theme, theorems, CeTZ/Fletcher animations, speaker notes, and more. You can also use the #slide[..] format to access more powerful features provided by Touying.
#import "@preview/touying:0.8.0": *
#import themes.university: *
#import "@preview/cetz:0.5.2"
#import "@preview/fletcher:0.5.8" as fletcher: node, edge
#import "@preview/numbly:0.1.0": numbly
#import "@preview/theorion:0.6.0": *
#import cosmos.clouds: *
#show: show-theorion
// cetz and fletcher bindings for touying
#let cetz-canvas = touying-reduce.with(cetz)
#let fletcher-diagram = touying-reduce.with(fletcher)
#show: university-theme.with(
aspect-ratio: "16-9",
// align: horizon,
// config-common(handout: true),
config-common(frozen-counters: (theorem-counter,)), // freeze theorem counter for animation
config-info(
title: [Title],
subtitle: [Subtitle],
author: [Authors],
date: datetime.today(),
institution: [Institution],
logo: emoji.school,
),
)
#set heading(numbering: numbly("{1}.", default: "1.1"))
#title-slide()
== Outline <touying:hidden>
#components.adaptive-columns(outline(title: none, indent: 1em))
= Animation
== Simple Animation
We can use `#pause` to #pause display something later.
#pause
Just like this.
#meanwhile
Meanwhile, #pause we can also use `#meanwhile` to #pause display other content synchronously.
#speaker-note[
+ This is a speaker note.
+ You won't see it unless you use `config-common(show-notes-on-second-screen: right)`
]
== Complex Animation
At subslide #touying-get-config("subslide"), we can
use #uncover("2-")[`#uncover` function] for reserving space,
use #only("2-")[`#only` function] for not reserving space,
#alternatives[call `#only` multiple times \u{2717}][use `#alternatives` function #sym.checkmark] for choosing one of the alternatives.
== Callback Style Animation
#slide(
repeat: 3,
self => [
#let (uncover, only, alternatives) = utils.methods(self)
At subslide #self.subslide, we can
use #uncover("2-")[`#uncover` function] for reserving space,
use #only("2-")[`#only` function] for not reserving space,
#alternatives[call `#only` multiple times \u{2717}][use `#alternatives` function #sym.checkmark] for choosing one of the alternatives.
],
)
== Math Equation Animation
Equation with `pause`:
$
f(x) &= pause x^2 + 2x + 1 \
&= pause (x + 1)^2 \
$
#meanwhile
Here, #pause we have the expression of $f(x)$.
#pause
By factorizing, we can obtain this result.
== CeTZ Animation
CeTZ Animation in Touying:
#cetz-canvas({
import cetz.draw: *
rect((0, 0), (5, 5))
(pause,)
rect((0, 0), (1, 1))
rect((1, 1), (2, 2))
rect((2, 2), (3, 3))
(pause,)
line((0, 0), (2.5, 2.5), name: "line")
})
== Fletcher Animation
Fletcher Animation in Touying:
#fletcher-diagram(
node-stroke: .1em,
node-fill: gradient.radial(blue.lighten(80%), blue, center: (30%, 20%), radius: 80%),
spacing: 4em,
edge((-1, 0), "r", "-|>", `open(path)`, label-pos: 0, label-side: center),
node((0, 0), `reading`, radius: 2em),
edge((0, 0), (0, 0), `read()`, "--|>", bend: 130deg),
pause,
edge(`read()`, "-|>"),
node((1, 0), `eof`, radius: 2em),
pause,
edge(`close()`, "-|>"),
node((2, 0), `closed`, radius: 2em, extrude: (-2.5, 0)),
edge((0, 0), (2, 0), `close()`, "-|>", bend: -40deg),
)
= Theorems
== Prime numbers
#definition[
A natural number is called a #highlight[_prime number_] if it is greater
than 1 and cannot be written as the product of two smaller natural numbers.
]
#example[
The numbers $2$, $3$, and $17$ are prime.
@cor_largest_prime shows that this list is not exhaustive!
]
#theorem(title: "Euclid")[
There are infinitely many primes.
]
#pagebreak(weak: true)
#proof[
Suppose to the contrary that $p_1, p_2, dots, p_n$ is a finite enumeration
of all primes. Set $P = p_1 p_2 dots p_n$. Since $P + 1$ is not in our list,
it cannot be prime. Thus, some prime factor $p_j$ divides $P + 1$. Since
$p_j$ also divides $P$, it must divide the difference $(P + 1) - P = 1$, a
contradiction.
]
#corollary[
There is no largest prime number.
] <cor_largest_prime>
#corollary[
There are infinitely many composite numbers.
]
#theorem[
There are arbitrarily long stretches of composite numbers.
]
#proof[
For any $n > 2$, consider $
n! + 2, quad n! + 3, quad ..., quad n! + n
$
]
= Others
== Multiple columns
#cols[
First column.
][
Second column.
]
== Multiple columns with equal height blocks
#cols(columns: (1fr, 1fr), gutter: 1em, lazy-layout: true)[
#emph-block[
First column with equal height: #lorem(10)
#lazy-v(1fr)
]
][
#emph-block[
Second column with equal height: : #lorem(15)
#lazy-v(1fr)
]
]
== Multiple Pages
#lorem(200)
#show: appendix
= Appendix
== Appendix
Please pay attention to the current slide number.
Touying provides the presentation engine and keeps the result in readable, portable Typst source. These companion projects add higher-level generation and editing workflows without replacing that source-first foundation.
SeaSlides Skill is an AI-native presentation-generation skill and toolchain built around Touying. Give it a topic, document, URL, or Markdown file and it can plan the narrative, select or create a theme, author editable Typst/Touying source, add speaker notes, compile the deck, run quality checks, and export PDF, PNG, or PPTX. Quick Mode produces a fast first draft; Full Mode adds research, asset generation, a separate design specification, and deeper visual review.
Tylina is our recommended AI-native, document-first, WYSIWYG Typst
editor and presenter, available in the browser and as a desktop app. The typeset page
is the editor—not merely a preview: edit it directly, or open Source Lens or Split for source-level
control. Its document-aware agents can edit, compile, and check the same canonical .typ workspace
while every change remains reviewable. Tylina also manages slides and speaker notes, reorders pages,
and presents the deck.
Open the Touying example in Tylina Web · Download the desktop app
Tylina has two PowerPoint export modes, both preserving speaker notes:
See the Tylina integration guide for details.

Generate with the SeaSlides Skill, then inspect, edit, reorder, and present in Tylina.

Start from a curated presentation design or browse the wider Typst Universe without leaving Tylina.
Thanks to...
polylux packagemetropolis themeuniversity themeaqua themestargazer themefit-to-height, fit-to-width and cover-with-rect(top 24 of 76)
221 followers · starred Nov 2025
325 followers · starred Apr 2026
82 followers · starred Jun 2025
8,472 followers · starred Jun 2024