Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support typst with manim #3339

Open
pavelzw opened this issue Aug 21, 2023 · 20 comments
Open

Support typst with manim #3339

pavelzw opened this issue Aug 21, 2023 · 20 comments
Labels
new feature Enhancement specifically adding a new feature (feature request should be used for issues instead)
Milestone

Comments

@pavelzw
Copy link
Contributor

pavelzw commented Aug 21, 2023

Description of proposed feature

It would be nice to have support for the typst typesetting language next to LaTeX.
https://github.com/typst/typst

How can the new feature be used?

from manim import *

complex_typst_example = \
"""$ frac(a^2, 2) $
$ vec(1, 2, delim: "[") $
$ mat(1, 2; 3, 4) $
$ lim_x =
    op("lim", limits: #true)_x $
"""

class Formula(Scene):
    def construct(self):
        s = Typst(f"This is normal text rendered with typst.")
        t = MathTypst("A = pi r^2")
        u = Typst(complex_typst_example)

        self.add(s)
        self.add(t)
        self.add(u)

See https://typst.app/docs/reference/math/ for the typst math introduction.

@pavelzw pavelzw added the new feature Enhancement specifically adding a new feature (feature request should be used for issues instead) label Aug 21, 2023
@github-project-automation github-project-automation bot moved this to 🆕 New in Dev Board Aug 21, 2023
@uwezi
Copy link
Contributor

uwezi commented Aug 21, 2023

I would guess the problem is not so much for Manim to be able to accept typst-formatted input, since it is only a string. But is there any similar interface for external rendering of typst-formatted text which results in a graphical representation as there is for LaTeX?

To give you the basics on how LaTeX in Manim works: you enter your string in a Tex() or MathTex() object, which is then sent to the LaTeX-interpreter installed on your computer. This interpreter then creates an output file, usually a .dvi-file, which then by yet another external program is converted into an SVG-image. It is this image which is then re-imported into Manim and included into your scene.

As far as I can see, typst only exists as an online cloud-service with a web-interface, without any standalone, downloadable version or even web-api...

Ok, I was mistaken, since I see that there actually seems to be a standalone application in the github repo which you linked...

@vaclavblazej
Copy link
Contributor

@uwezi The linked source code https://github.com/typst/typst has some installation instructions and terminal compilation to pdf.

@uwezi
Copy link
Contributor

uwezi commented Aug 22, 2023

@uwezi The linked source code https://github.com/typst/typst has some installation instructions and terminal compilation to pdf.

As I pointed out at the end I finally figured it out. And the PDF can be converted to SVG (or even PNG) using pdftocairo which comes with MikTex on my computer... In order to get a "standalone"-like behavior you need to define the page #set page(width:auto,height:auto,margin:0cm) however, with a 0 cm margin typst cuts off parts of the text extending below the baseline...

(I will not argue here that I don't see why typst should be easier or simpler than LaTeX in the context of use with Manim)

#set page(width:auto,height:auto,margin:0cm)
= Introduction
In this report, we will explore the
various factors that influence _fluid
dynamics_ in glaciers and how they
contribute to the formation and
behavior of these natural structures.

$ frac(a^2, 2) $
$ vec(1, 2, delim: "[") $
$ mat(1, 2; 3, 4) $
$ lim_x =
    op("lim", limits: #true)_x $

test.pdf
test
test

@pavelzw
Copy link
Contributor Author

pavelzw commented Aug 22, 2023

I will not argue here that I don't see why typst should be easier or simpler than LaTeX in the context of use with Manim

I personally find LaTeX to be quite annoying to install. Having a light-weight alternative to LaTeX that succeeds to do most things that LaTeX can also do is why I really like the typst project.

Having typst support in manim would make it easier for people who don't have a properly configured LaTeX setup on their machine to use mathematical expressions and also make automated CI setup for manim way easier since installing LaTeX also takes quite some time in CI.

Another reason could be performance; but I'm not sure how much LaTeX rendering actually contributes to manim compilation times.

@pavelzw
Copy link
Contributor Author

pavelzw commented Aug 22, 2023

And the PDF can be converted to SVG (or even PNG) using pdftocairo which comes with MikTex on my computer...

typst actually has native support for png output and svg output (svg since typst/typst#1729, not released yet) so you don't even need third-party tools to do this.

This is my output with your typst file:

$ typst compile manim.typ
$ typst compile --ppi 600 manim.typ manim.png
$ typst compile manim.typ manim.svg

manim.pdf
manim.png
manim.svg

@pavelzw
Copy link
Contributor Author

pavelzw commented Aug 22, 2023

There also seem to be python bindings for typst:
https://github.com/messense/typst-py

@uwezi
Copy link
Contributor

uwezi commented Aug 22, 2023

I don't think that python bindings would be necessary. Running the command line tool on a temporary file just like in the LaTeX case should work perfectly fine. Typst then creates a PDF output which can be read and converted into an SVG stream using pymupdf .
(Sadly) the SVG stream then needs to be written into another temporary file in order to be re-imported into Manim using the SVGMobject. Using my typst code up there and the PDF created by typst I succeeded with the following code:

from manim import *
import fitz

class test(Scene):
    def construct(self):      
        doc = fitz.open(r"bilder/test.pdf")

        page = doc.load_page(0)
        svg = page.get_svg_image()
        
        file = open(r"media/20230822_test.svg", "w")
        file.write(svg)
        file.close()

        svgmobj = SVGMobject(r"media/20230822_test.svg").set_color(WHITE).scale_to_fit_width(14)
        self.add(svgmobj)
        self.add(index_labels(svgmobj).set_color(RED).shift(UR))

to get this output:
bild

The index labels indicate that there is nothing special going on with the conversion of the glyphs, so that later animations should be straightforward.

It feels a bit weird that the SVG data has to be written and then read back - but currently there is no Manim object which interprets SVG data which already is in memory and I did not succeed to fake a file input using io.StringIO, the network of methods inside the SVGMobject is too much to comprehend for me right now.

@uwezi
Copy link
Contributor

uwezi commented Aug 22, 2023

native support for png output and svg output

well, I didn't know that - it would make the whole process even simpler and not much of an implementation would be needed. All the pre-processing of LaTeX strings for splitting which does not work reliably could be skipped in my opinion...

@pavelzw
Copy link
Contributor Author

pavelzw commented Aug 23, 2023

I don't think that python bindings would be necessary.

When the Python bindings support direct compilation from a string instead of a file (messense/typst-py#4) I think the Manim implementation could be a bit nicer without the need to write the typst code directly to disk and compiling it afterwards but doing everything in memory.
Also, you wouldn't even need typst installed but can do everything within the python bindings.

@MrDiver
Copy link
Collaborator

MrDiver commented Dec 2, 2023

🤔 so it's probably possible to do that. One thing i would ask for this is how would you decide on which one to use, because by default we expect Latex to be present on the system for things like the Tex object, so should it just be a general Typst object then ? Like the Tex object ? Or what would be the idea on that ?

@MrDiver MrDiver added this to the v0.18.1 milestone Dec 2, 2023
@pavelzw
Copy link
Contributor Author

pavelzw commented Dec 2, 2023

I think something like a Typst(content: str) object for regular typst stuff and a MathTypst(content: str, display_mode: Literal["inline", "display"]) object for inline math ($x = sum_(i=1)^n i$) and display mode math ($ x = sum_(i=1)^n i $) would make sense.

I would make it somewhat similar to the Tex object with the exception that Typst doesn't need to be preinstalled but comes as an optional dependency with typst-py.

@BreakingLead
Copy link

This idea is great. LaTeX is just a bit too complicated and annoying for amateur math lovers...

@JasonGrace2282
Copy link
Member

Maybe we should consider this, especially since #3523 showed up independently.

@behackl behackl modified the milestones: v0.18.1, v0.19.0 Apr 23, 2024
@NicoWeio
Copy link
Contributor

NicoWeio commented Apr 25, 2024

One aspect I didn't see mentioned before is that Typst is easier to (automatically) parse and interface with. With a sufficiently deep integration, this could help (as an example) with those cases where you want to animate a part of a formula, which with TeX requires juggling with substrings and is generally a cumbersome thing to build upon.
Consider the following basic examples:

  1. Having a formula ABCD and first animating AB and then BC
  2. Animating the x in e^x (yes, this is possible with the TeX integration as well)
  3. Feel free to add more; I haven't used Manim for a while, so I cannot think of more on the spot.

@behackl
Copy link
Member

behackl commented Apr 25, 2024

Are you thinking of some particular Typst functionality that allows this sort of grouping? Working on this is somewhat high on my list of prioirities, and I'd really like to have a robust and well-working implementation for substring mapping.

My current intention is to mimic (more or less) the functionality implemented here, which would mean that individual parts of a Typst string would be identified by wrapping them with Typst functions that set different fill colors, then importing the compiled SVG back to Manim and using the fill-colors to group together the parsed objects.

I am not sure yet whether we should go the Tex/MathTex way of splitting strings in the sense that inputs of the form Tex("Hello ", "world!") are allowed, or whether subgroups have to be constructed using some sort of special syntax (e.g., Typst("Hello {{world}}!"). Any thoughts on that?

@NicoWeio
Copy link
Contributor

NicoWeio commented Apr 25, 2024

Unfortunately, I can't confidently say more about that, having little knowledge of Typst's internals.
But in case you didn't know, Typst has an active Discord community and the founders (especially @laurmaedje) are very responsive, too. I'm sure that they can help you with such considerations.

@laurmaedje
Copy link

There is a thread on the Discord server related to this. There hasn't been a lot of discussion there yet, but the idea of exposing some primitives to more easily identify particular groups of the SVG output has been floated.

@behackl
Copy link
Member

behackl commented Apr 29, 2024

Thanks, @laurmaedje! I'm following the post; we'll do our homework and come up with a more concrete design for the interface of Typst-rendererd objects on our end. In case we stumble over something that would be useful to have in SVGs generated by Typst I'll chime in there (I don't really see anything like that apart from grouped elements though).

((I've been using Typst somewhat excessively this semester in teaching and I enjoy it quite a bit -- so I'm definitely motivated to implement a nice interface for it within for Manim as well. 😄))

@JasonGrace2282 JasonGrace2282 modified the milestones: v0.19.0, v0.20.0 Jul 23, 2024
@Beiri22
Copy link

Beiri22 commented Jan 23, 2025

Typst integration would be a really nice add-on; as I am moving away from tex towards typst; and currently, using manim would reintroduce tex...

@DenisLohvynov
Copy link

DenisLohvynov commented Jan 30, 2025

I've been playing around and managed to write a prototype, if you will, of Typst class. The code is rather ugly, but the idea of how I made the "groups"(can be nested) is that I hid (via #hide in Typst) the desired part and then subtracted it from the whole scene. Here's an example:

class Test(Scene):
    def construct(self):
        frame_ = _Typst(r"""
                        #{title}[== Introduction]
                        $ {int}(integral)_0^({u}(1)) x d x = lr(x^2/2|)_0^1 $
                        """)
        frame_['title'].set_color(RED)

        frame_['int'].set_color(YELLOW)
        
        frame_['u'].set_color(GREEN)

        self.add(frame_)

Image

I'm new here, and I'm not sure how good this design is and if it is how to proceed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Enhancement specifically adding a new feature (feature request should be used for issues instead)
Projects
Status: 🆕 New
Development

No branches or pull requests