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
PreviewWidgetthat 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
Fallback video: media/raw_render.mov
Textual component embedding
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 dor arrow keys: rotate+/-: zoomspace: toggle auto spinr: reset cameraqoresc: quit
Demo controls
The packaged Textual demo uses these controls:
- arrow keys: orbit
=: zoom in-: zoom outspace: toggle auto spinr: reset cameraq: 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
lowormediumquality 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 bindingspyproject.tomlPython packaging metadata for the mixed Rust/Python projectpython/termrender/Python package code layered over the PyO3 modulepython/termrender/examples/versioned demo appsmedia/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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| termrenderer-0.0.1.tar.gz | 22.9 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.