manim/pyproject.toml
Benjamin Hackl d999d422c9
Introduce first-class support for rendering text and markup via Typst (optional dependency) (#4681)
* feat: add TypstMobject and TypstMathMobject for first-class Typst support

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.

* feat(typst): add sub-expression selection via {{ }} groups and .select()

- 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 unneeded assert line

* Generalize some more critical hard-coded LaTeX assumptions

* Fix syntax error

* Support Typst labels in existing APIs

* Add ManimTextLabel typing alias

* Preserve Typst SVG stroke widths by default

* Calibrate Typst font sizing against TeX

* Add Typst mobject documentation

* Track Typst baseline frames

* Document Typst baseline frame tracking

* Add Typst section to text guide

* Polish Typst docs and label handling

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Improve Typst stroke scaling and docs examples

* Tune Typst SVG stroke scaling

* Restore Typst math example wording

* Fix pre-commit issues for Typst branch

* Fix number line runtime typing import

* Exclude Typst autogenerated .rst files

* Use Manim directive in docstrings and fix wrong key in Typst.select() docstring

* Fix GroupedMath comments

---------

Co-authored-by: Toon Verstraelen <Toon.Verstraelen@UGent.be>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Francisco Manríquez Novoa <49853152+chopan050@users.noreply.github.com>
Co-authored-by: Francisco Manríquez Novoa <francisco.manriquezn@usm.cl>
2026-06-11 03:54:21 +00:00

224 lines
4.7 KiB
TOML

[project]
name = "manim"
version = "0.20.1"
description = "Animation engine for explanatory math videos."
authors = [
{name = "The Manim Community Developers", email = "contact@manim.community"},
{name = "Grant '3Blue1Brown' Sanderson", email = "grant@3blue1brown.com"},
]
license = "MIT"
readme = "README.md"
classifiers = [
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
"Topic :: Scientific/Engineering",
"Topic :: Multimedia :: Video",
"Topic :: Multimedia :: Graphics",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Natural Language :: English",
]
requires-python = ">=3.11"
dependencies = [
"audioop-lts>=0.2.1 ; python_full_version >= '3.13'",
"av>=15.0",
"beautifulsoup4>=4.12",
"click>=8.0",
"cloup>=2.0.0",
"decorator>=4.3.2",
"isosurfaces>=0.1.1",
"manimpango>=0.6.1,<1.0.0",
"mapbox-earcut>=1.0.0",
"moderngl-window>=2.0.0",
"moderngl>=5.7.0,<6.0.0",
"networkx>=2.6",
"numpy>=2.1",
"pillow>=11.0",
"pycairo>=1.14,<2.0.0",
"pydub>=0.22.0",
"pygments>=2.17",
"rich>=12.0.0",
"scipy>=1.13.0",
"scipy>=1.15.0 ; python_full_version >= '3.13'",
"screeninfo>=0.7.0",
"skia-pathops>=0.9.0",
"srt>=3.0.0",
"svgelements>=1.9.0",
"tqdm>=4.21.0",
"typing-extensions>=4.12.0",
"watchdog>=2.0.0",
]
[project.scripts]
"manim" = "manim.__main__:main"
"manimce" = "manim.__main__:main"
[project.urls]
repository = "https://github.com/manimcommunity/manim"
documentation = "https://docs.manim.community/"
homepage = "https://www.manim.community/"
"Bug Tracker" = "https://github.com/ManimCommunity/manim/issues"
"Changelog" = "https://docs.manim.community/en/stable/changelog.html"
"X / Twitter" = "https://x.com/manimcommunity"
"Bluesky" = "https://bsky.app/profile/manim.community"
"Discord" = "https://www.manim.community/discord/"
[project.optional-dependencies]
gui = [
"dearpygui>=1.0.0",
]
jupyterlab = [
"jupyterlab>=4.3.4",
"notebook>=7.3.2",
]
typst = [
"typst>=0.14",
]
[dependency-groups]
dev = [
"furo>=2024.8.6",
"matplotlib>=3.9.4",
"myst-parser>=3.0.1",
"pre-commit>=4.1.0",
"pytest>=8.3.4",
"pytest-cov>=6.0.0",
"pytest-xdist>=2.2,<3.0",
"ruff>=0.14.7",
"sphinx>=7.4.7",
"sphinx-copybutton>=0.5.2",
"sphinx-design>=0.6.1",
"sphinx-reredirects>=0.1.5",
"sphinxcontrib-programoutput>=0.18",
"sphinxext-opengraph>=0.9.1",
"types-decorator>=5.1.8.20250121",
"types-pillow>=10.2.0.20240822",
"types-pygments>=2.19.0.20250107",
"psutil>=6.1.1",
"requests>=2.32.3",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build]
include = [
"/manim"
]
exclude = [
"/docker",
"/logo",
"/scripts",
]
[tool.pytest.ini_options]
markers = "slow: Mark the test as slow. Can be skipped with --skip_slow"
addopts = "--no-cov-on-fail --cov=manim --cov-report xml --cov-report term -n auto --dist=loadfile --durations=0"
[tool.isort]
profile = "black"
[tool.coverage.run]
omit = ["*tests*"]
[tool.coverage.report]
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
[tool.ruff]
line-length = 88
target-version = "py311"
extend-exclude = [
".github",
".hg",
".env",
"env",
"build",
"buck-out",
"media",
]
fix = true
[tool.ruff.lint]
select = [
"A",
"B",
"C4",
"D",
"E",
"F",
"I",
"NPY",
"PERF",
"PGH",
"PT",
"SIM",
"UP",
"W",
]
ignore = [
# (sub)module shadows standard library module
"A005",
# mutable argument defaults (too many changes)
"B006",
# No function calls in defaults
# ignored because np.array() and straight_path()
"B008",
# docstring ignores - mostly stylistic
"D1",
"D203",
"D205",
"D212",
"D4",
"E111",
"E114",
"E117",
"E501",
# due to the import * used in manim
"F403",
"F405",
"PERF203", # try-except-in-loop
# Exception too broad (this would require lots of changes + re.escape) for little benefit
"PT011",
# as recommended by https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
"D206",
"D300",
]
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
[tool.ruff.lint.per-file-ignores]
"tests/*" = [
# flake8-builtins
"A",
# unused expression
"B018",
# unused variable
"F841",
# from __future__ import annotations
"I002",
]
"example_scenes/*" = [
"I002",
]
"__init__.py" = [
"F401",
"F403",
]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false
[tool.ruff.lint.pydocstyle]
convention = "numpy"
[tool.ruff.format]
docstring-code-format = true