painted

painted

One library. Print to TUI. One dependency.

show() producing styled output in TTY, plain text in pipe, JSON with --json flag
from painted import show
show({"cpu": 67, "mem": 82, "disk": 45})

TTY gets a styled chart. Pipe gets plain text. --json gets JSON.

Print styled output

Replace print() one call at a time. Auto-detects TTY.

from painted import Block, Style, print_block

block = Block.text("deploy OK", Style(fg="green", bold=True))
print_block(block)
print_block rendering styled green bold text in the terminal

Compose

Blocks are immutable rectangles. Compose them with functions.

from painted import border, join_vertical, ROUNDED

header = Block.text(" api-gateway ", Style(bold=True, reverse=True))
status = join_vertical(
    Block.text("  replicas: 2/3 ready", Style(fg="yellow")),
    Block.text("  /health:  200  12ms", Style(fg="green")),
)
card = border(join_vertical(header, status), chars=ROUNDED)
print_block(card)
Composing blocks with border, join_vertical, and ROUNDED border chars into a status card

CLI harness

One render function, three output modes.

from painted import run_cli, CliContext, Block

def render(ctx: CliContext, data: dict) -> Block:
    ...  # your render logic

def fetch() -> dict:
    return {"status": "ok", "replicas": 3}

run_cli(sys.argv[1:], render=render, fetch=fetch)
myapp           # auto-detect
myapp -q        # quiet
myapp -v        # verbose
myapp -i        # interactive TUI
myapp --json    # JSON output
myapp | grep ok # plain text, no ANSI
run_cli producing different output at each zoom level: quiet, summary, verbose, and interactive TUI

Full TUI

Alt screen, keyboard input, diff-flush render loop.

import asyncio
from painted import Block, Style, border
from painted.tui import Surface

class MyApp(Surface):
    def render(self):
        block = Block.text("Hello!", Style(fg="green"))
        border(block, title="Demo").paint(self._buf)

    def on_key(self, key: str):
        if key == "q":
            self.quit()

asyncio.run(MyApp().run())
Full TUI application running in alt screen with keyboard input and live rendering
$ pip install painted

One dependency: wcwidth