ManimCommunity / manim

A community-maintained Python framework for creating mathematical animations.
https://www.manim.community
MIT License
19.95k stars 1.48k forks source link

Support typst with manim #3339

Open pavelzw opened 10 months ago

pavelzw commented 10 months ago

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.

uwezi commented 10 months ago

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 commented 10 months ago

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

uwezi commented 10 months ago

@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 commented 10 months ago

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 commented 10 months ago

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 https://github.com/typst/typst/pull/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 commented 10 months ago

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

uwezi commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

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

When the Python bindings support direct compilation from a string instead of a file (https://github.com/messense/typst-py/issues/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 commented 7 months ago

🤔 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 ?

pavelzw commented 7 months ago

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 commented 6 months ago

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

JasonGrace2282 commented 6 months ago

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

NicoWeio commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

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 commented 2 months ago

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. 😄))