Skip to content

Introduce first-class support for rendering text and markup via Typst (optional dependency)#4681

Open
behackl wants to merge 23 commits intoManimCommunity:mainfrom
behackl:feat-typst
Open

Introduce first-class support for rendering text and markup via Typst (optional dependency)#4681
behackl wants to merge 23 commits intoManimCommunity:mainfrom
behackl:feat-typst

Conversation

@behackl
Copy link
Copy Markdown
Member

@behackl behackl commented Apr 9, 2026

This PR adds first-class Typst support to Manim via new Typst and TypstMath mobjects. Typst source is compiled directly to SVG through the Python typst package, so users can render both general Typst markup and math without relying on a TeX installation. The branch also integrates Typst with existing label-oriented APIs and adds user-facing documentation and examples.

In addition to the core Typst mobjects, this PR includes a few polish and compatibility improvements: subexpression selection via Typst labels and {{ ... }} groups (incl. a named version), optional baseline-frame tracking for debugging/alignment, and updates to the docs build so Typst examples render in the documentation.

Documentation:

In short:

  • add Typst and TypstMath
  • support Typst label-based subgroup selection via select(...)
  • support {{ ... }} grouping in TypstMath
  • integrate Typst into existing label-related APIs (new type alias ManimTextLabel)
  • preserve SVG stroke widths by default
  • calibrate Typst sizing against Tex / MathTex
  • add optional baseline-frame tracking
  • add reference docs and guide updates, including rendered examples
  • typst (the 3rd party Python interface + packaged compiler) is a new optional dependency; if users want to work with Typst and TypstMath, they'd have to either pip install typst separately, or install manim via pip install 'manim[typst]'

Closes #3339.

behackl and others added 17 commits March 5, 2026 09:26
…port

Implement the initial TypstMobject proposal (see agents/typst.md):

- TypstMobject: renders arbitrary Typst markup to SVG via the 'typst'
  Python package (self-contained Rust binary, no system install needed),
  then imports through SVGMobject.
- TypstMathMobject: convenience subclass that wraps input in Typst math
  delimiters ($ ... $).

Pipeline: user string → wrap in minimal Typst document (auto-sized page,
transparent background) → write .typ file → compile to SVG via
typst.compile() → import via SVGMobject → scale/center/recolor.

Key details:
- Compilation helper in manim/utils/typst_file_writing.py with SHA-256
  content-hash caching (same scheme as the LaTeX pipeline).
- font_size property mirrors SingleStringMathTex: compile at fixed 11pt,
  scale after import using initial_height / SCALE_FACTOR_PER_FONT_POINT.
- init_colors() recolors black submobjects to self.color (Typst default
  fill is black), preserving any explicit Typst colors.
- path_string_config enables curve subdivision for smooth animation.
- 'typst' added as optional dependency group in pyproject.toml.
- 10 tests covering creation, font_size, caching, preamble, and repr.
- Override modify_xml_tree in Typst to convert data-typst-label
  attributes to id attributes before svgelements parsing (avoids
  attribute inheritance issue with data-* attributes)
- Add Typst.select(key) method accepting str labels or int indices
  to retrieve VGroup sub-expressions from id_to_vgroup_dict
- Implement {{ }} double-brace preprocessor on TypstMath:
  - {{ content }} → manimgrp("_grp-N", content) (auto-numbered)
  - {{ content : label }} → manimgrp("label", content) (named)
  - Skips {{ }} inside string literals and [...] content blocks
  - Uses math-mode call convention (no # prefix) to keep args in
    math mode
- Auto-inject manimgrp preamble when groups are detected
- Add 12 new tests covering label mapping, nesting, select(),
  error handling, and preprocessor edge cases
Remove some LaTeX assumptions to allow for Typst objects
@behackl behackl added new feature Enhancement specifically adding a new feature (feature request should be used for issues instead) needs discussion Things which needs to be discussed before implemented. labels Apr 9, 2026
@behackl behackl marked this pull request as draft April 9, 2026 01:01
@behackl
Copy link
Copy Markdown
Member Author

behackl commented Apr 9, 2026

Tests pass and the general state of things is quite good I think, but specifically looking at the rendered examples at https://manimce--4681.org.readthedocs.build/en/4681/reference/manim.mobject.text.typst_mobject.html did reveal that some things still need a bit of polish. Changed this PR to a draft for now.

@behackl behackl marked this pull request as ready for review April 11, 2026 10:16
@behackl
Copy link
Copy Markdown
Member Author

behackl commented Apr 11, 2026

implementation and docs are more or less clean, ready to be looked at!

@tovrstra
Copy link
Copy Markdown

I've re-rendered a presentation (in which I tested an earlier commit in this PR), this time using the latest version of this PR. Everything still worked!

There is one general issue I had to work around with either commit, which is probably beyond the scope of this PR, but still worth mentioning. Manim does not scale stroke widths, which conflicts with some Typst features that use strokes such as underlines, overlines and horizontal lines in fractions. (There are many other relevant cases, but these tree are the most obvious ones.)

For example, take the following equation:

TypstMath(
    'log_10(overline(||Delta vec(r)||^2) thick \\/ "Å"^2)',
    font_size=32,
),

Renders as follows (using Fira Math):

stroke_wrong

The reason for the too think overline is that the width at 11pt is not scaled to match the font size of 32pt.

To get the correct overline width, one can let Typst perform the font scaling:

Typst(
    '#set text(size: 32pt)\n $ log_10(overline(||Delta vec(r)||^2) thick \\/ "Å"^2) $',
    font_size=11,
),

This produces:

 stroke_right

Ideally, both should produce the same result.

It seems that stroke scaling of SVG images is not supported by Manim? (It seems reasonable to me to apply stroke scaling by default to all SVGs.) I noticed some pull requests related to stroke scaling, which may be related:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs discussion Things which needs to be discussed before implemented. new feature Enhancement specifically adding a new feature (feature request should be used for issues instead)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support typst with manim

2 participants