Skip to main content

TermRenderer

Realtime STL rendering for kitty-graphics-compatible terminals.

TermRenderer rasterizes binary or ASCII STL meshes into RGBA frames in Rust, then streams them through the kitty graphics protocol so Ghostty and kitty can display actual pixels instead of character art.

It ships with two Python-facing integration styles:

  • a viewport-level API for direct rendering into any terminal rectangle
  • a reusable Textual PreviewWidget that renders inside its own widget region

Demo

GitHub can render .mov attachments in repository views, but inline playback reliability depends on the browser and GitHub surface. The repository includes two recordings in media/raw_render.mov and media/textual_components.mov.

Raw terminal renderer

Raw terminal renderer demo

Fallback video: media/raw_render.mov

Textual component embedding

Textual component embedding demo

Fallback video: media/textual_components.mov

Features

  • binary and ASCII STL loading
  • CPU software rasterizer with flat shading, backface culling, projection, and z-buffering
  • kitty graphics protocol presenter with tile-based dirty updates and per-tile double buffering
  • viewport abstraction for rendering into bounded terminal regions
  • direct Rust CLI for quick local viewing
  • Python bindings via PyO3
  • official Textual integration through a reusable PreviewWidget

Python package

  • PyPI package name: termrenderer
  • import package name: termrender

Install from PyPI:

pip install termrenderer

For local development from this repository:

python3 -m pip install maturin
maturin develop

Build a wheel:

maturin build

Python API

Import surface-level and viewport-level APIs:

from termrender import Camera, Mesh, Surface, TerminalRenderer, Viewport

Render into an explicit viewport:

from termrender import Camera, Mesh, TerminalRenderer, Viewport

mesh = Mesh.from_stl("model.stl")
camera = Camera.default()
renderer = TerminalRenderer("medium")
viewport = Viewport(10, 4, 80, 24)

renderer.render_viewport(mesh, camera, viewport)

Textual integration

The package exposes a reusable widget that renders into its own content_region.

from termrender import Mesh, PreviewWidget
from textual.app import App, ComposeResult


class Demo(App):
    CSS = """
    Screen { background: #020617; }
    PreviewWidget { width: 1fr; height: 1fr; }
    """

    def compose(self) -> ComposeResult:
        yield PreviewWidget(Mesh.demo(), quality="medium")

The widget provides host-control methods such as:

  • set_mesh(...)
  • set_camera(...)
  • set_quality(...)
  • adjust_pitch(...)
  • adjust_yaw(...)
  • adjust_zoom(...)
  • toggle_spin()
  • reset_camera()
  • clear_surface()

It also emits a PreviewWidget.FrameRendered message with FPS, framebuffer size, viewport size, and camera state.

The widget ships its own default component styling through PreviewWidget.DEFAULT_CSS; the host app only needs to decide layout and sizing.

The demo Textual app is included as a versioned example module:

maturin develop
termrender-preview path/to/model.stl --quality low

If you want a managed Textual demo environment during development:

python3 -m venv .venv
source .venv/bin/activate
pip install -U pip maturin textual==8.2.0
maturin develop
python -m termrender.examples.textual_preview path/to/model.stl --quality low

CLI

Run the Rust viewer directly:

cargo run --
cargo run -- path/to/model.stl
cargo run -- path/to/model.stl --quality high

Controls:

  • w a s d or arrow keys: rotate
  • + / -: zoom
  • space: toggle auto spin
  • r: reset camera
  • q or esc: quit

Demo controls

The packaged Textual demo uses these controls:

  • arrow keys: orbit
  • =: zoom in
  • -: zoom out
  • space: toggle auto spin
  • r: reset camera
  • q: quit

Terminal support

This project currently targets terminals that support the kitty graphics protocol, especially Ghostty and kitty.

Notes:

  • the renderer uploads compressed RGBA tiles through kitty APC graphics commands
  • the presenter only re-uploads changed tiles when possible
  • framebuffer dimensions stay aligned to terminal cell geometry
  • performance is best with low or medium quality on larger terminal windows

Development

Rust verification:

cargo test
cargo build
cargo build --features python-module

Python verification:

python3 -m compileall python
python3 -m py_compile termrender/examples/textual_preview.py

Repository layout

  • src/ Rust renderer, presenter, viewport, CLI, and bindings
  • pyproject.toml Python packaging metadata for the mixed Rust/Python project
  • python/termrender/ Python package code layered over the PyO3 module
  • python/termrender/examples/ versioned demo apps
  • media/ demo recordings used by the README

License

MIT

Metadata

Release files for termrenderer 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for termrenderer 0.0.1
File Size Uploaded Provenance
termrenderer-0.0.1.tar.gz 22.9 MB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for termrenderer 0.0.1
File Interpreter ABI Platform
termrenderer-0.0.1-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details

Total release size: 23.2 MB

Release files / termrenderer-0.0.1.tar.gz

Download URL termrenderer-0.0.1.tar.gz
Size 22.9 MB
Tags Source
SHA-256 checksum
How to use checksums
232c2eef51957291ce5eabdce916d014daa244c53648c64423b9dccc613b170c
BLAKE2b-256 checksum
How to use checksums
1acb5b4edbed7eb9c6ad74b057e327031d50207bb2880e699917caf0ad143b47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0

Release files / termrenderer-0.0.1-cp39-abi3-macosx_11_0_arm64.whl

Download URL termrenderer-0.0.1-cp39-abi3-macosx_11_0_arm64.whl
Size 339.1 kB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9022ad4609c8071187d851b1e9861fffe6902551c9499f01d802210292ff55f5
BLAKE2b-256 checksum
How to use checksums
3dd513962bdda180bb149be8aa2881c9bb7155a1061c83c316987895bf396f7a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.3.2 CPython/3.14.3 Darwin/25.3.0

Security for termrenderer 0.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page