Quick Start

Installation

Install ManimPango from PyPI:

pip install manimpango

The Windows and macOS wheels bundle their native dependencies, so installing them from PyPI does not require Pango or Cairo to be installed separately. Linux has no binary wheels at present, so installation there builds from source and requires a C compiler, pkg-config, and the Pango development headers.

To build from source on macOS, install Pango and Cairo first, for example with Homebrew:

brew install pango cairo

Source builds on Windows need Pango 1.56 or newer to register private font files at runtime.

Rendering Plain Text

Use render() for plain text. It returns a RenderedText object containing SVG and layout metadata.

import manimpango

result = manimpango.render("Hello, world!", size=24.0)
svg = result.svg
result.save("hello.svg")

save() writes to an existing parent directory; it does not create missing directories.

Understanding RenderedText

Both rendering functions return a RenderedText object rather than writing a temporary file. It keeps the SVG document and the layout result together, so callers can choose whether to keep the SVG in memory, save it, or inspect its geometry.

The basic result contract is executable and independent of the host’s font metrics:

>>> import manimpango
>>> result = manimpango.render("Hello, world!", size=24.0)
>>> isinstance(result, manimpango.RenderedText)
True
>>> result.line_count
1
>>> isinstance(result.svg, str) and result.width > 0 and result.height > 0
True

For example, one macOS/Pango installation produces the following selected values. The exact numbers vary with the selected font and native backend; the relationships and SVG user-space units do not.

>>> result
RenderedText(width=130.0, height=24.0, baseline=18.0, line_count=1)
>>> round(result.width, 1), round(result.height, 1), round(result.baseline, 1)
(130.0, 24.0, 18.0)
>>> result.ink_bounds
Bounds(x=0.38671875, y=1.546875, width=127.33203125, height=19.875)
>>> result.logical_bounds
Bounds(x=0.0, y=0.0, width=130.0, height=24.0)

width and height are the rendered SVG viewport dimensions, and baseline is the first line’s baseline position. ink_bounds is tight to glyph drawing, so it excludes the side bearings and whitespace visible in logical_bounds. All of these values, as well as font size and an optional layout width, are float values in SVG user-space units—not raw Pango units or device pixels. An SVG consumer may subsequently scale the document.

The complete SVG is available without another render operation, and may be written only when a file is needed:

svg = result.svg
result.save("hello.svg")

RenderedText is immutable and result.lines is a tuple. Its lines describe the parsed text, code-point ranges, bounds, and baselines for individual lines. The following section shows how to inspect them.

Rendering Markup

Pango markup has its own entry point. Do not pass markup to render().

result = manimpango.render_markup(
    "<span foreground='red' weight='bold'>Important</span>",
    font="Helvetica",
    size=24.0,
)

Styling Plain Text with Spans

Use TextSpan for styled ranges in plain text. Span offsets are Python code-point offsets and are half-open, just like string slices. Spans and markup are deliberately separate APIs.

text = "Hello, world!"
result = manimpango.render(
    text,
    spans=(
        manimpango.TextSpan(0, 5, weight=manimpango.Weight.BOLD),
        manimpango.TextSpan(7, 12, foreground="#3366cc"),
    ),
)

Inspecting Layout Metadata

All geometry exposed by ManimPango is a float in SVG user-space units. Bounds records an x, y, width, and height in that same coordinate system. LineInfo contains the rendered line text, its half-open code-point range, bounds, and baseline.

result = manimpango.render("Line 1\nLine 2", width=200.0)

print(result.width, result.height, result.baseline)
print(result.ink_bounds, result.logical_bounds)
for line in result.lines:
    print(line.text, line.start, line.end, line.bounds, line.baseline)

Variable Fonts

weight accepts a Weight member or an integer from 1 through 1000. Use variations for OpenType axes; axis tags contain exactly four ASCII characters. ManimPango forwards these settings to Pango, but a visible effect depends on the selected font, axis, and renderer backend. For example, the bundled test font’s wght axis changes output on the current Linux, macOS, and Windows test backends, while its CNTR axis does not change output through the current macOS Pango/CoreText/Cairo stack. This is a fixture-and-renderer compatibility observation, not a general CoreText limitation. Test variation-dependent output on every platform you support.

result = manimpango.render(
    "Smooth weight",
    font="Inter",
    weight=450,
    variations={"wght": 650, "wdth": 90},
)

Custom Fonts

register_font() returns a FontRegistration handle. Use it as a context manager so the registration closes predictably. Multiple handles for a path are reference-safe; closing one does not release the font while another remains open.

with manimpango.register_font("path/to/MyFont.ttf") as registration:
    assert not registration.closed
    result = manimpango.render("Custom font", font="My Font")

assert registration.closed