Touying Documentation

repository·main·Indexed 25 days ago

https://github.com/touying-typ/touying

A package for creating presentation slides in Typst featuring built-in themes and rich animations. It supports incremental reveal via #pause and #meanwhile, advanced reveal with #uncover and #only, and integration with CeTZ and Fletcher for animated diagrams. The ecosystem includes the touying-exporter for converting Typst files to HTML (via impress.js), PPTX, PDF, and pdfpc formats, as well as support for speaker notes via pdfpc and Pympress.

Tokens
41K
Snippets
150
Records
181
Agent score
81%

What's inside Touying

  1. Use `frozen-counters` to prevent counter jumps in animations

    main

    When using packages that maintain internal counters (like Theorion's theorem-counter), Touying's subslide rendering can cause these counters to increment on every subslide, leading to incorrect numbering.

    To fix this, use config-common(frozen-counters: (...)) to tell Touying to capture the counter value at the start of a slide and restore it for every subslide. This ensures theorem or figure numbers remain consistent across animation steps.

  2. Use Waypoints to manage animation timelines

    main

    Waypoints allow you to name specific positions in a slide's animation timeline using labels. Instead of hard-coding subslide numbers (e.g., 1, 2, 3), you can reference these labels in functions like #uncover or #only. This makes animations easier to maintain because inserting new elements or pauses automatically shifts the subsequent waypoints without requiring manual re-counting of subslides.

    By default, an advancing waypoint creates a new subslide. You can use the #waypoint(<label>) syntax to mark a position and then reference that label in your animation calls.

    #slide[
      Base content.
      #waypoint(<step-a>)
      #uncover(<step-a>)[Uncovered from step-a.]
      #waypoint(<step-b>)
      #only(<step-b>)[Only during step-b.]
    ]
  3. Use only, uncover, and alternatives in CeTZ and Fletcher

    main

    You can use only, uncover, and alternatives within CeTZ and Fletcher diagrams. Because these packages are generally position-based, the visual result is often the same, but the underlying mechanism differs:

    • only: Drops the draw command entirely for non-matching slides.
    • uncover: Covers the element (hides it) until the specified slide.

    Note: Commands like effect and item-by-item might not work as expected within these bindings.

    Syntax Examples:

    • CeTZ: (uncover(3, { ... }),) or (only(3, line(...)),)
    • Fletcher: uncover("1-2", edge(...)) or only(3, node(...))
  4. Understand the `cover` function in Touying

    main
    The cover function is a core mechanism used by uncover and #pause to conceal content that is not currently visible in a presentation. By default, Touying uses the Typst hide function, which makes content invisible without affecting the layout (the space occupied by the content remains preserved).
  5. Create a custom theme function

    main

    A custom theme is typically implemented as a function (e.g., bamboo-theme) that wraps touying-slides.with(). This allows you to set global styles (like font size) and pass configurations to Touying.

    To handle initialization logic that requires access to the self object (the theme state), use config-methods(init: (self: none, body) => { ... }).

    #import "@preview/touying:0.7.4": *
    
    #let bamboo-theme(
      aspect-ratio: "16-9",
      ..args,
      body,
    ) = {
      set text(size: 20pt)
    
      show: touying-slides.with(
        config-page(paper: "presentation-" + aspect-ratio),
        config-common(
          slide-fn: slide,
        ),
        ..args,
      )
    
      body
    }
  6. Animations in Touying

    main

    Touying provides several ways to create dynamic presentations:

    • Incremental Reveal: Use #pause to delay content or #meanwhile to display content synchronously with other elements.
    • Advanced Reveal: Use #uncover("start-") to reserve space for content that appears later, #only("start-") to show content without reserving space, and #alternatives[...] to choose between different content options.
    • Math Animations: Use #pause or #meanwhile inside math blocks to animate equation steps.
    • Graphics Animations: Touying integrates with CeTZ and Fletcher to allow incremental drawing of diagrams using pause or meanwhile within their respective canvas/diagram blocks.
    • Callback Style: For complex logic, use the #slide(repeat: n, self => [...]) syntax to access the current subslide index via self.subslide and use utility methods provided by the slide context.
  7. Structure sections and subsections using headings

    main

    Touying uses Typst headings to define the structure of your presentation. The mapping of heading levels to slides depends on the theme or your configuration:

    • Multi-level structure (e.g., dewdrop theme): Level 1 headings (=) are sections, Level 2 (==) are subsections, and Level 3 (===) are subsubsections.
    • Simplified structure (e.g., university theme): Level 1 (=) are sections and Level 2 (==) are titles/slides.

    You can control how many heading levels trigger new slides by using the slide-level parameter in the config-common function. The value represents the nesting complexity starting from 0.

    • slide-level: 2: Levels 1 and 2 create new slides.
    • slide-level: 3: Levels 1, 2, and 3 create new slides.
    #import "@preview/touying:0.7.4": *
    #import themes.dewdrop: *
    
    #show: dewdrop-theme.with(aspect-ratio: "16-9")
    
    = Section
    
    == Subsection
    
    === Title
    
    Hello, Touying!
  8. Animate content with pause and meanwhile

    main

    Touying provides several ways to control content visibility during a presentation:

    • #pause: Delays the display of subsequent content until the next subslide.
    • #meanwhile: Allows displaying content synchronously with other elements (often used to show parts of an expression or diagram step-by-step).
    • #uncover("range"): Reserves space for content but keeps it invisible until the specified subslide range.
    • #only("range"): Shows content only during the specified subslide range without reserving space.
    • #alternatives[option1][option2]: Allows choosing one of several alternatives for a specific subslide.
    #pause
    
    #meanwhile
    
    #uncover("2-")[`#uncover` function]
    
    #only("2-")[`#only` function]
    
    #alternatives[call `#only` multiple times ✗][use `#alternatives` function ✓]
  9. Hide or exclude headings from outlines and bookmarks

    main

    You can control how headings affect the PDF structure and slide generation using labels:

    • <touying:hidden>: Makes the heading invisible, unnumbered, unoutlined, and unbookmarked. It also skips the automatic section/subsection slide that the heading would otherwise trigger. The content under the heading remains visible in the PDF.
    • <touying:unoutlined>: The slide is visible in the presentation but is excluded from the outline/bookmarks.

    Use <touying:hidden> for elements like an outline slide that should appear in the PDF but not in the navigation bookmarks.

    #import "@preview/touying:0.7.4": *
    #import themes.simple: *
    #show: simple-theme
    == Outline <touying:hidden>
    
    #components.adaptive-columns(outline(title: none, indent: 1em))
    
    = Section
    
    == Normal Slide
    
    Appears in the outline.
    
    == Interstitial Slide <touying:unoutlined>
    
    This slide shows but is not listed in the outline.
  10. Quick Start with Touying

    main

    To use Touying, ensure you have a Typst environment installed (such as the Web App or Tinymist LSP). Include the Touying package and a theme in your document, then apply the theme using a #show rule.

    Basic workflow:

    1. Import the package: #import "@preview/touying:0.7.4": *
    2. Import a theme: #import themes.simple: *
    3. Apply the theme: #show: simple-theme.with(aspect-ratio: "16-9")

    Slides are created using standard Typst headings (= Title, == Slide Title).

    #import "@preview/touying:0.7.4": *
    #import themes.simple: *
    
    #show: simple-theme.with(aspect-ratio: "16-9")
    
    = Title
    
    == First Slide
    
    Hello, Touying!
    
    #pause
    
    Hello, Typst!
  11. Get started with Touying

    main

    Touying is a presentation package for Typst that allows you to create slides using Typst's modern syntax. It follows a 'content and style separation' philosophy where you write plain text and markup, and themes handle the visual design.

    To use Touying, you do not need to perform a separate installation. It is automatically downloaded from the Typst package registry when you use one of the following environments:

    1. Typst Web App: Open typst.app, create a new project, and start writing. This provides real-time preview and collaboration.
    2. Tinymist LSP: Use a Typst language server (like the Tinymist LSP) in an editor like VS Code. This provides syntax highlighting, autocomplete, error diagnostics, and slide preview.

    Terminology used in Touying:

    • slides: The entire slideshow.
    • slide: A single page.
    • subslide: A sub-page produced by an animation step (e.g., using #pause).
  12. Use Callback-Style Functions for Complex Animations

    main

    To avoid layout limitations and errors in context expressions, use the callback-style pattern. Instead of passing a content block to #slide, pass a function that accepts a self parameter. You can then extract the animation methods using utils.methods(self).

    Important: When using this method, you must manually specify the repeat parameter in #slide (e.g., repeat: 3) because Touying cannot automatically infer the number of subslides when using these bound methods.

    #import "@preview/touying:0.7.4": *
    #import themes.simple: *
    #show: simple-theme
    
    #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 ✗][use `#alternatives` function ✓].
    ])