takumi-py
takumi-py provides Python 3.10+ bindings for the Takumi Rust renderer.
[!IMPORTANT]
takumi-pyis currently in a testing stage. APIs, wheel build targets, release automation, and exception types may still change while the Takumi core binding surface is completed; do not treat it as a stable production dependency yet.
The binding focuses on exposing practical Takumi core capabilities instead of copying the WASM/JS convenience layer. It currently supports:
- Node Tree, HTML string, and Jinja template rendering into image bytes.
RenderOptions, including auto viewport, DPR, debug border, dithering, andtime_ms.- Custom fonts, per-render image resources, font fallback families, language hints, and SVG output.
- Rust-backed HTML parsing with configurable presets, Tailwind attribute mapping, and depth limits.
- Layout measurement with a typed measured node tree result.
- CSS and structured keyframe animation time sampling, sequence animation, and WebP/APNG/GIF animated encoders.
- PEP 561 typing, with
_core.pyicovering the public native binding surface.
It intentionally does not include Playwright fallback, remote fetch, abort signal support, data URL convenience APIs, a Node.js sidecar, or Takumi internal layout/cache/glyph types.
Development
uv sync --all-groups --all-extras
uv run maturin develop
make check
make check checks Ruff formatting and linting, ty, pytest with coverage,
and the Rust formatting/build checks.
Install From Source
uv sync --all-groups --all-extras
uv run maturin develop
Node Tree
from pathlib import Path
from takumi_py import Renderer
renderer = Renderer()
png = renderer.render_node(
{"type": "text", "text": "Hello from Python"},
stylesheets=["span { font-size: 72px; color: black; }"],
width=1200,
height=630,
)
Path("out.png").write_bytes(png)
Render Options
from takumi_py import RenderOptions, Renderer
raw = Renderer().render_node(
{
"type": "container",
"style": {
"width": "240px",
"height": "120px",
"backgroundColor": "white",
},
},
options=RenderOptions(
width=None,
height=None,
format="raw",
device_pixel_ratio=2.0,
dithering="ordered-bayer",
),
)
HTML
from takumi_py import Renderer
html = """
<div class="card">
<h1>Hello</h1>
</div>
"""
stylesheets = ["""
.card {
width: 1200px;
height: 630px;
display: flex;
align-items: center;
justify-content: center;
color: white;
background: #111827;
}
"""]
png = Renderer().render_html(
html,
stylesheets=stylesheets,
width=1200,
height=630,
)
HTML parsing is performed by Takumi's Rust parser. Use HtmlOptions when you
need to disable Chromium presets, read Tailwind classes from a custom attribute,
or cap parse depth:
from takumi_py import HtmlOptions, Renderer
png = Renderer().render_html(
'<div class="w-[1200px] h-[630px]"></div>',
html_options=HtmlOptions(
presets="none",
tailwind_property="class",
max_depth=64,
),
width=None,
height=None,
)
Compiled nodes expose Takumi's image URL discovery API:
compiled = Renderer().compile_node(
{"type": "image", "src": "https://example.com/logo.png"}
)
print(compiled.resource_urls())
resource_urls() follows Takumi's native image URL discovery semantics and
reports HTTP(S) image references from image nodes and styles. It does not fetch
those resources and does not report already-provided memory:// resources or
byte buffers.
Measure
from takumi_py import Renderer
measured = Renderer().measure_node(
{
"type": "container",
"style": {"width": "240px", "height": "120px"},
"children": [{"type": "text", "text": "Hello"}],
},
width=240,
height=120,
)
print(measured.width, measured.height)
Resources
from pathlib import Path
from takumi_py import FontResource, ImageResource, Renderer
renderer = Renderer(load_default_fonts=False)
families = renderer.register_font(
FontResource(
Path("Inter-Regular.woff2").read_bytes(),
name="Inter",
weight=400,
style="normal",
generic_family="sans-serif",
)
)
png = renderer.render_node(
{"type": "image", "src": "memory://logo", "width": 128, "height": 128},
width=128,
height=128,
images=[
ImageResource(
"memory://logo",
Path("logo.svg").read_bytes(),
cache="none",
)
],
font_families=families,
lang="en",
)
fetched_resources, load_font, load_fonts, persistent_images,
put_persistent_image, and clear_image_store remain available as deprecated
compatibility shims for the v0.2 line. New code should pass images per render
and use register_font / register_fonts.
register_font returns the family names registered by Takumi. Pass that list as
font_families when you want a render call to use those families as its
fallback stack. lang accepts a BCP-47 language tag and is forwarded to
Takumi's locale-aware text shaping and line-breaking.
The render-level lang option is not injected as a node attribute, so it does
not make CSS :lang() selectors match. Takumi's selector matcher follows the
HTML language-determination model and walks actual node metadata or HTML
attributes. If CSS needs :lang(...), set lang on the HTML element or node
that should establish the language:
renderer.render_html(
'<section lang="zh-Hant"><div class="headline">你好</div></section>',
stylesheets=[
'.headline:lang(zh-Hant) { font-family: "Noto Sans TC"; }',
],
)
renderer.render_node(
{
"type": "container",
"lang": "ja",
"children": [{"type": "text", "text": "こんにちは"}],
},
stylesheets=[':lang(ja) { font-family: "Noto Sans JP"; }'],
)
ImageResource.cache accepts "auto" or "none" and is forwarded to Takumi's
native image cache. Tuple resources like ("memory://logo", data) remain
accepted and default to "auto".
FontResource accepts Takumi v2 descriptor fields:
FontResource(
font_bytes,
name="Inter",
weight=700,
style="italic",
subset_of="Brand Sans",
generic_family="sans-serif",
)
style uses CSS font-style syntax such as "normal", "italic", or
"oblique 12deg". Invalid style values raise FontError during registration.
SVG
from takumi_py import Renderer
svg = Renderer().render_svg_html(
"""
<div class="card">Hello</div>
""",
stylesheets=[".card { width: 1200px; height: 630px; color: black; }"],
width=1200,
height=630,
)
Animation
from takumi_py import AnimationScene, RenderOptions, Renderer
renderer = Renderer()
frame = renderer.render_html(
"""
<div class="box"></div>
""",
stylesheets=["""
@keyframes fade {
from { opacity: 0; }
to { opacity: 1; }
}
.box {
width: 64px;
height: 64px;
background: black;
animation: fade 1000ms both;
}
"""],
width=64,
height=64,
time_ms=500,
)
structured_frame = renderer.render_node(
{
"type": "container",
"className": "box",
},
stylesheets=[
".box { width: 64px; height: 64px; animation: fade 1000ms both; }"
],
keyframes={
"fade": {
"from": {"opacity": 0},
"to": {"opacity": 1},
}
},
width=64,
height=64,
time_ms=500,
)
options_frame = renderer.render_node(
{"type": "container", "className": "box"},
stylesheets=[
".box { width: 64px; height: 64px; animation: fade 1000ms both; }"
],
options=RenderOptions(
width=64,
height=64,
time_ms=500,
keyframes={
"fade": {
"from": {"opacity": 0},
"to": {"opacity": 1},
}
},
),
)
webp = renderer.render_animation(
[
AnimationScene(
{
"type": "container",
"style": {
"width": "100%",
"height": "100%",
"backgroundColor": "black",
},
},
duration_ms=100,
),
AnimationScene(
{
"type": "container",
"style": {
"width": "100%",
"height": "100%",
"backgroundColor": "white",
},
},
duration_ms=100,
),
],
width=64,
height=64,
fps=20,
)
Takumi v2 Migration
takumi-py now targets Takumi v2. The main resource model changed from a
renderer-level global context to explicit per-render resources:
- Use
images=[ImageResource(...)]instead offetched_resources. - Use
register_font/register_fontsinstead ofload_font/load_fonts. - Pass
font_familiesandlangon render calls when you need deterministic font fallback or locale-aware shaping. - Use HTML or node
langattributes, not the render-levellangoption, when CSS selectors depend on:lang(...). ImageResource.cacheis forwarded to the native image cache for per-render, constructor, and deprecated persistent-image resources.FontResourceaccepts Takumi v2 descriptor fields:name,weight,style,subset_of, andgeneric_family.- The built-in fallback font follows Takumi v2: a Latin Geist subset marked as last resort, so caller-registered fonts win ordinary fallback selection.
HtmlOptionsexposes Takumi's Rustfrom_htmlparser options.CompiledNode.resource_urls()wraps Takumi's image URL discovery and reports HTTP(S) image/style references for callers that want to prepare resources before rendering.- Pass
keyframes=...orRenderOptions(keyframes=...)to use Takumi's structured keyframe input without embedding@keyframesCSS text. - WebP defaults to lossless when neither
qualitynorlosslessis specified. Passing bothqualityandlossless=Trueis rejected. - SVG output is available through
render_svg_node,render_svg_html,render_svg_template, andrender_svg_compiled. - HTML parsing is handled by Takumi's Rust parser. Inline
styleattributes are parsed with the HTML payload; pass document-level CSS explicitly throughstylesheets=[...]on HTML render, measure, SVG, or template calls.
Takumi v2 also changes several CSS defaults to be closer to the Web platform.
If an old image shifts, check for implicit defaults such as position,
border/outline width, transform-origin, object-position, and SVG
currentColor inheritance before treating it as a binding regression.
Jinja
from takumi_py import TemplateRenderer
renderer = TemplateRenderer("examples/templates")
stylesheets = ["""
.card {
width: 1200px;
height: 630px;
display: flex;
flex-direction: column;
justify-content: center;
padding: 64px;
background: #111827;
color: white;
}
"""]
png = renderer.render(
"card.html.jinja",
{
"title": "takumi-py",
"subtitle": "HTML / Jinja to image",
},
stylesheets=stylesheets,
width=1200,
height=630,
)
Release
Releases are handled by GitHub Actions. After the release commit is on main,
tag that commit with v plus the project.version value from
pyproject.toml, then push the tag to build wheels/sdist, publish to PyPI, and
create a GitHub Release.
git tag v0.2.0 <commit-on-main>
git push origin main v0.2.0
The tag must match project.version in pyproject.toml; for example, version
0.2.0 must be released as v0.2.0.
Before publishing, the workflow generates GitHub build provenance attestations for every wheel and source distribution. The PyPI publication is recorded as a GitHub Deployment and links to the released version on PyPI.
Test Coverage
The Python test suite covers static rendering, the HTML adapter, templates, core fixtures, options, measurement, resources, animation, typing artifacts, and generated HTML fixtures from the upstream Takumi core test suite.
License
takumi-py is licensed under GPL-3.0-or-later. See LICENSE.
This repository includes takumi as a git submodule. takumi is licensed
separately under MIT OR Apache-2.0; see
THIRD_PARTY_NOTICES.md.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file takumi_py-0.2.0.tar.gz.
File metadata
- Download URL: takumi_py-0.2.0.tar.gz
- Upload date:
- Size: 8.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
096a98e5f200a28b58c83759c623705a7c715a4bcc102be9aaeb6d24fbe073bd
|
|
| MD5 |
e3d38ddb6f42527d185350ff412034c3
|
|
| BLAKE2b-256 |
59fc85c77ff016617eb3f3a2093a89288374bc8310d82c7162c61290ef789fc1
|
Provenance
The following attestation bundles were made for takumi_py-0.2.0.tar.gz:
Publisher:
publish.yml on BalconyJH/takumi-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takumi_py-0.2.0.tar.gz -
Subject digest:
096a98e5f200a28b58c83759c623705a7c715a4bcc102be9aaeb6d24fbe073bd - Sigstore transparency entry: 2137081342
- Sigstore integration time:
-
Permalink:
BalconyJH/takumi-py@1838921483a6af3fac9587425715f77e12b35f3d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/BalconyJH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1838921483a6af3fac9587425715f77e12b35f3d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file takumi_py-0.2.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: takumi_py-0.2.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 4.3 MB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d1340965f8dd56a4e4b25bfda1f4b12282cd13d252b521bd5e77a2e91623ea8
|
|
| MD5 |
aa493dcb23f5e52d23a55b85fc0c74a5
|
|
| BLAKE2b-256 |
e4e2e73da347dc3f33b4918e4fbe921dd944cd32100af18c1c93281999b61a37
|
Provenance
The following attestation bundles were made for takumi_py-0.2.0-cp310-abi3-win_amd64.whl:
Publisher:
publish.yml on BalconyJH/takumi-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takumi_py-0.2.0-cp310-abi3-win_amd64.whl -
Subject digest:
9d1340965f8dd56a4e4b25bfda1f4b12282cd13d252b521bd5e77a2e91623ea8 - Sigstore transparency entry: 2137081463
- Sigstore integration time:
-
Permalink:
BalconyJH/takumi-py@1838921483a6af3fac9587425715f77e12b35f3d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/BalconyJH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1838921483a6af3fac9587425715f77e12b35f3d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file takumi_py-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: takumi_py-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.9 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3536ed28e94022fc750a7d31939a3941c0069b4c6d4a9f93eba80f457aab6a2
|
|
| MD5 |
df1ce637351dcee9b537cca6de294193
|
|
| BLAKE2b-256 |
c6c1e6f2768438ac949db0b724ef7e171065ec16e70d5b052cf3f03f64b372ac
|
Provenance
The following attestation bundles were made for takumi_py-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish.yml on BalconyJH/takumi-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takumi_py-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
f3536ed28e94022fc750a7d31939a3941c0069b4c6d4a9f93eba80f457aab6a2 - Sigstore transparency entry: 2137081395
- Sigstore integration time:
-
Permalink:
BalconyJH/takumi-py@1838921483a6af3fac9587425715f77e12b35f3d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/BalconyJH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1838921483a6af3fac9587425715f77e12b35f3d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file takumi_py-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: takumi_py-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 4.9 MB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d56482cf09b25db82c251be200b766f9ecc19a3ea32155567649868a99d2f41
|
|
| MD5 |
30eaa50638d0442a315789370a04e537
|
|
| BLAKE2b-256 |
60408024180776c16bc414dad112ed858eb7b4f3eadf8a59d0c80fd258e1036e
|
Provenance
The following attestation bundles were made for takumi_py-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish.yml on BalconyJH/takumi-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takumi_py-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
6d56482cf09b25db82c251be200b766f9ecc19a3ea32155567649868a99d2f41 - Sigstore transparency entry: 2137081433
- Sigstore integration time:
-
Permalink:
BalconyJH/takumi-py@1838921483a6af3fac9587425715f77e12b35f3d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/BalconyJH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1838921483a6af3fac9587425715f77e12b35f3d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file takumi_py-0.2.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: takumi_py-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 4.4 MB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29e11242af625395e26489dd74b0c4d7d460180a36770cafd11e9fee11f8e182
|
|
| MD5 |
815d02538e438fc0e4cd0ca39331d50d
|
|
| BLAKE2b-256 |
0ba5b005a244440abf0efc3505cff5b468660a94caabf59aa9df0ad835fe4cb2
|
Provenance
The following attestation bundles were made for takumi_py-0.2.0-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
publish.yml on BalconyJH/takumi-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
takumi_py-0.2.0-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
29e11242af625395e26489dd74b0c4d7d460180a36770cafd11e9fee11f8e182 - Sigstore transparency entry: 2137081369
- Sigstore integration time:
-
Permalink:
BalconyJH/takumi-py@1838921483a6af3fac9587425715f77e12b35f3d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/BalconyJH
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1838921483a6af3fac9587425715f77e12b35f3d -
Trigger Event:
workflow_dispatch
-
Statement type: