Skip to main content

A pygame-powered ANSI terminal emulator framework for building text-based games and apps.

Project description

PixTerm

A pygame-powered ANSI terminal emulator framework for building text-based games and TUI applications.

PixTerm renders a fixed-size character grid (120 × 40 by default) using bitmap BDF fonts and a fully parsed ANSI escape code pipeline — giving you the look of a classic terminal with the full power of Python and pygame underneath.


Features

  • ANSI escape code rendering — foreground/background colours (16-colour palette), bold, cursor movement
  • Bitmap BDF fonts — bundled Terminus fonts in sizes 12–24 px (normal, bold, variable-width variants)
  • Screen manager — stack-based screen system with on_entry / render / update / handle_event / on_exit lifecycle
  • Theme system — swap colour palettes at runtime; ships with basic_black, basic_white, and more
  • Preferences — persistent JSON preferences stored in ~/.pixterm/preferences.json
  • Hot-reloader — optional watchdog-based module reloader for rapid development

Installation

pip install pixterm

Requires Python 3.10+ and pygame 2.6+.


Quick Start

import pygame
from pixterm import Game, Screen, Preferences

class HelloScreen(Screen):
    _text: str

    def on_init(self):
        pass

    def on_entry(self, *args, **kwargs):
        self._text = "Hello, PixTerm!"

    def on_exit(self):
        pass

    def on_deinit(self):
        pass

    def render(self):
        self.cli.write(f"\x1b[2;2H\x1b[93m{self._text}\x1b[0m")

    def update(self, dt: float):
        pass

    def handle_event(self, event: pygame.event.Event):
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            self.game.stop()

game = Game(title="Hello World", target_fps=60)

prefs = Preferences.load()
prefs.apply_theme(game.cli)           # apply saved colour theme

game.add_screen("hello", HelloScreen)
game.switch_screen("hello") # can also use game.current_screen = "hello"
# switch_screen accepts additional args/kwargs which are passed to the screen's on_entry method
game.run()

Core Concepts

Game

The main entry point. Creates the pygame window, owns the CLI, ScreenManager, and main loop.

game = Game(title="My Game", target_fps=60)
game.run()

CLI

The character-grid terminal emulator. Write ANSI-escaped strings to any position:

# Absolute cursor position then coloured text
cli.write("\x1b[5;10H\x1b[32mGreen text\x1b[0m")

# Allows for writing text at specific grid coordinates:
cli.write("\x1b[31mRed text at (15, 20)\x1b[0m", 15, 20) # x=15, y=20

The grid is 120 columns × 40 rows (STANDARD_WIDTH × STANDARD_HEIGHT), you can also use game.width and game.height to get the current dimensions in characters (which may differ if you change the font size).

Screen

Base class for all application views. Override the lifecycle methods, it's recommended not to override the constructor due to .cli and .game references not being set until initialisation, use on_entry instead for setup.

from pixterm import Screen

class GameScreen(Screen):
    def on_init(self):
        """Called once when the screen is first registered with the ScreenManager."""

    def on_entry(self, *args, **kwargs):
        """Called once when this screen becomes active."""

    def render(self):
        """Called every frame — redraw everything here."""

    def update(self, dt: float):
        """Called every frame with elapsed seconds since last frame."""

    def handle_event(self, event):
        """Receives every pygame event while this screen is active."""

    def on_exit(self):
        """Called once when leaving this screen."""

    def on_deinit(self):
        """Called once when the screen is unregistered or the game exits."""

BDFFont

Bitmap font loader. Terminus fonts (12–24 px) are bundled and loaded automatically:

from pixterm import BDFFont

font = BDFFont.get_font(16)          # 16 px normal weight
font_bold = BDFFont.get_font(16, bold=True)

Preferences

Singleton for persistent user settings (theme, etc.):

from pixterm import Preferences

prefs = Preferences.load()           # load from ~/.pixterm/preferences.json
prefs.theme_name = "basic_white"
prefs.save()
prefs.apply_theme(game.cli)

Themes

Built-in colour themes:

Name Description
basic_black Default dark terminal (standard ANSI colours)
basic_white Light background variant
catppuccin_mocha Based on the popular Catppuccin Mocha palette
catppuccin_latte Based on the popular Catppuccin Latte palette
solarized_dark Based on the classic Solarized Dark palette
solarized_light Based on the classic Solarized Light palette
gruvbox_dark Based on the popular Gruvbox Dark palette
dracula Based on the popular Dracula palette
pastel_pink Custom pastel pink palette
orange_sunset Custom orange sunset palette
from pixterm import get_theme_names, get_theme

print(get_theme_names())             # ['basic_black', 'basic_white', ...]
theme = get_theme("basic_black")

Font Sizes

Bundled Terminus BDF fonts:

Size (px) Normal Bold Variable
12
14
16
18
20
22
24

Project Layout

pixterm/
├── __init__.py        # Public API
├── cli.py             # ANSI terminal emulator + TerminalCell grid
├── font_renderer.py   # BDF font loader and glyph renderer
├── game.py            # Main game loop + pygame initialisation
├── screen.py          # Screen base class
├── screen_manager.py  # Screen registration + switching
├── preferences.py     # Persistent user preferences (singleton)
├── themes.py          # Colour theme definitions
├── hotreloader.py     # Optional watchdog-based hot-reloader
└── fonts/             # Bundled Terminus BDF bitmap fonts
    └── ter-u*.bdf

Licence

MIT — see LICENSE.

Author's Notes on Artificial Intelligence

This project was developed with the assistance of AI. The AI was used to generate code snippets, suggest improvements, and help with debugging. The AI's contributions were reviewed and edited by the author to ensure they fit the project's requirements and coding style.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pixterm-0.2.3.tar.gz (292.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pixterm-0.2.3-py3-none-any.whl (311.6 kB view details)

Uploaded Python 3

File details

Details for the file pixterm-0.2.3.tar.gz.

File metadata

  • Download URL: pixterm-0.2.3.tar.gz
  • Upload date:
  • Size: 292.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for pixterm-0.2.3.tar.gz
Algorithm Hash digest
SHA256 81b4cdafc5d2786306472073add5b3852af251f166d4a1961defde06368ec02b
MD5 eb05a36d750490a40396a353e77ef45a
BLAKE2b-256 e4dd968fadb624d79b71f97db8c9768992882dce0ef73359349301594fc00376

See more details on using hashes here.

File details

Details for the file pixterm-0.2.3-py3-none-any.whl.

File metadata

  • Download URL: pixterm-0.2.3-py3-none-any.whl
  • Upload date:
  • Size: 311.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for pixterm-0.2.3-py3-none-any.whl
Algorithm Hash digest
SHA256 817785be4576b42b2174cd1addb6217fd5a5a0854ae00e54cbe12112f1529cc7
MD5 2f7c910933e10c70665beeb29a9acd8a
BLAKE2b-256 1d5946a8d92e0bfb02051d9540caff7bf2dc2167e3b4c32041ea7f29a41ba0ca

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page