Metadata-Version: 2.4
Name: termrenderer
Version: 0.0.1
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Rust
Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
Classifier: Topic :: Terminals
Requires-Dist: textual>=8.2.0,<9.0.0
License-File: LICENSE
Summary: Realtime terminal 3D STL renderer for kitty/ghostty and Textual
Keywords: terminal,textual,stl,3d,kitty,ghostty
Author: Jingzhe Ni's OpenCode
License-Expression: MIT
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Homepage, https://github.com/NiJingzhe/TermRenderer
Project-URL: Issues, https://github.com/NiJingzhe/TermRenderer/issues
Project-URL: Repository, https://github.com/NiJingzhe/TermRenderer

# 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`.

<details open>
<summary>Raw terminal renderer</summary>

<video src="https://github.com/NiJingzhe/TermRenderer/raw/main/media/raw_render.mov" controls muted loop playsinline></video>

Fallback link: `media/raw_render.mov`

</details>

<details open>
<summary>Textual component embedding</summary>

<video src="https://github.com/NiJingzhe/TermRenderer/raw/main/media/textual_components.mov" controls muted loop playsinline></video>

Fallback link: `media/textual_components.mov`

</details>

## 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:

```bash
pip install termrenderer
```

For local development from this repository:

```bash
python3 -m pip install maturin
maturin develop
```

Build a wheel:

```bash
maturin build
```

## Python API

Import surface-level and viewport-level APIs:

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

Render into an explicit viewport:

```python
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`.

```python
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:

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

If you want a managed Textual demo environment during development:

```bash
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:

```bash
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:

```bash
cargo test
cargo build
cargo build --features python-module
```

Python verification:

```bash
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

