A cross-platform package to replace curses (mouse/keyboard input & text colours/positioning) and create ASCII animations
npx @tessl/cli install tessl/pypi-asciimatics@1.15.0A comprehensive cross-platform Python library that provides full-screen text UI capabilities and ASCII animation functionality. Asciimatics serves as a modern replacement for curses libraries, offering coloured/styled text rendering with 256-color terminal support and unicode characters (including CJK languages), precise cursor positioning, non-blocking keyboard input with unicode support, mouse input handling, console resize detection, and screen scraping capabilities.
pip install asciimaticsimport asciimatics
from asciimatics.screen import Screen, ManagedScreen
from asciimatics.scene import SceneCommon patterns for animations:
from asciimatics.effects import Print, Stars, Matrix
from asciimatics.renderers import FigletText, Fire
from asciimatics.screen import ManagedScreenFor text-based UIs:
from asciimatics.widgets import Frame, Layout, Button, Text, Label
from asciimatics.scene import Scene
from asciimatics.screen import ManagedScreenfrom asciimatics.screen import ManagedScreen
from asciimatics.scene import Scene
from asciimatics.effects import Print
from asciimatics.renderers import FigletText
from asciimatics.exceptions import ResizeScreenError
import sys
def demo(screen):
effects = [
Print(screen,
FigletText("ASCIIMATICS", font='big'),
screen.height // 2 - 3)
]
screen.play([Scene(effects, 500)])
if __name__ == "__main__":
try:
ManagedScreen(demo).run()
except ResizeScreenError:
passfrom asciimatics.widgets import Frame, Layout, Button, Label
from asciimatics.scene import Scene
from asciimatics.screen import ManagedScreen
from asciimatics.exceptions import StopApplication
class DemoFrame(Frame):
def __init__(self, screen):
super(DemoFrame, self).__init__(screen,
screen.height * 2 // 3,
screen.width * 2 // 3,
hover_focus=True,
title="Contact Details")
layout = Layout([100], fill_frame=True)
self.add_layout(layout)
layout.add_widget(Label("Welcome to Asciimatics!"))
layout.add_widget(Button("OK", self._ok))
self.fix()
def _ok(self):
raise StopApplication("User pressed OK")
def demo(screen):
screen.play([Scene([DemoFrame(screen)], -1)], stop_on_resize=True)
ManagedScreen(demo).run()Asciimatics uses a layered architecture based on the Artist pattern:
This design enables creation of both simple animations and complex interactive applications while maintaining cross-platform compatibility across Windows, macOS, Linux, and even Android.
Core terminal control functionality including screen management, cursor positioning, color handling, keyboard/mouse input, and cross-platform terminal operations.
class Screen:
def print_at(self, text, x, y, colour=COLOUR_WHITE, attr=A_NORMAL, bg=COLOUR_BLACK): ...
def get_from(self, x, y, length): ...
def clear_buffer(self, fg, attr, bg): ...
def refresh(): ...
def get_event(): ...
class ManagedScreen:
def __init__(self, function, arguments=None, catch_interrupt=True): ...
def run(self): ...Comprehensive animation system with built-in effects like banners, stars, matrix rain, snow, fire, and custom sprite animations. Includes timing control, scene management, and transition effects.
class Effect:
def __init__(self, screen, start_frame=0, stop_frame=0): ...
def reset(self): ...
def update(self, frame_no): ...
class Print(Effect):
def __init__(self, screen, renderer, y, x=None, colour=COLOUR_WHITE, attr=A_NORMAL, bg=COLOUR_BLACK, transparent=True, speed=1, clear=False): ...
class Stars(Effect):
def __init__(self, screen, count, stop_frame=0): ...
class Matrix(Effect):
def __init__(self, screen, stop_frame=0): ...Complete widget toolkit for building text-based user interfaces with buttons, text inputs, lists, forms, dialogs, and layout management. Supports validation, focus handling, and event processing.
class Frame(Effect):
def __init__(self, screen, height, width, has_border=True, hover_focus=False, title=None, reduce_cpu=False): ...
def add_layout(self, layout): ...
def fix(self): ...
class Layout:
def __init__(self, columns, fill_frame=False): ...
def add_widget(self, widget, column=0): ...
class Button(Widget):
def __init__(self, text, on_click, disabled=False, add_box=False): ...
class Text(Widget):
def __init__(self, label=None, name=None, on_change=None, validator=None, disabled=False): ...Content generation system for creating complex visual elements including ASCII art text, images, charts, patterns, and media playback. Supports both static and dynamic content generation.
class Renderer:
def render(self, frame): ...
class FigletText(StaticRenderer):
def __init__(self, text, font='3x5', width=80, colour=COLOUR_WHITE): ...
class Fire(DynamicRenderer):
def __init__(self, height, width, emitter, colour, bg, start_frame=0): ...
class ImageFile(StaticRenderer):
def __init__(self, file_name, height=None, colours=8, bg=COLOUR_BLACK, fill_background=False, unicode_char=" "): ...Advanced particle system for creating fireworks, explosions, rain, and other dynamic effects. Includes sprite animation support for character-based animations and custom drawable objects.
class ParticleEffect(Effect):
def __init__(self, screen, x, y, life_time, start_frame=0, stop_frame=0): ...
class StarFirework(ParticleEffect):
def __init__(self, screen, x, y, life_time, firework_colour=COLOUR_WHITE, trail_colour=None, start_frame=0): ...
class Sprite(Effect):
def __init__(self, screen, renderer_dict, path, colour=COLOUR_WHITE, attr=A_NORMAL, bg=COLOUR_BLACK, clear=True, start_frame=0, stop_frame=0): ...
class Sam(Sprite):
def __init__(self, screen, path, start_frame=0, stop_frame=0): ...A_BOLD = 1
A_NORMAL = 2
A_REVERSE = 3
A_UNDERLINE = 4COLOUR_DEFAULT = -1
COLOUR_BLACK = 0
COLOUR_RED = 1
COLOUR_GREEN = 2
COLOUR_YELLOW = 3
COLOUR_BLUE = 4
COLOUR_MAGENTA = 5
COLOUR_CYAN = 6
COLOUR_WHITE = 7ASCII_LINE = 0
SINGLE_LINE = 1
DOUBLE_LINE = 2class ResizeScreenError(Exception):
"""Terminal resize error during scene playback"""
def __init__(self, message, scene=None): ...
@property
def scene(self): ...
class StopApplication(Exception):
"""Signal to stop the application"""
def __init__(self, message): ...
class NextScene(Exception):
"""Signal to move to next scene"""
def __init__(self, name=None): ...
@property
def name(self): ...
class InvalidFields(Exception):
"""Form validation errors"""
def __init__(self, fields): ...
@property
def fields(self): ...class Event:
"""Base event class"""
pass
class KeyboardEvent(Event):
"""Keyboard input event"""
def __init__(self, key_code): ...
@property
def key_code(self): ...
class MouseEvent(Event):
"""Mouse input event"""
def __init__(self, x, y, buttons): ...
@property
def x(self): ...
@property
def y(self): ...
@property
def buttons(self): ...class ColouredText:
"""Text with embedded color codes"""
def __init__(self, raw_text, parser, colour=COLOUR_WHITE, attr=A_NORMAL, bg=COLOUR_BLACK): ...
@property
def text(self): ...
@property
def colour_map(self): ...class Parser:
"""Abstract text parser base class"""
def parse(self, text): ...
# Parser Command Constants
DISPLAY_TEXT = 0
CHANGE_COLOURS = 1
MOVE_ABSOLUTE = 2
MOVE_RELATIVE = 3def readable_mem(mem):
"""Convert bytes to human-readable format"""
pass
def readable_timestamp(stamp):
"""Convert POSIX timestamp to readable format"""
pass
class BoxTool:
"""Box drawing utility for creating bordered regions"""
def __init__(self, unicode_aware, style=SINGLE_LINE): ...
def box(self, width, height): ...
def box_top(self, width): ...
def box_bottom(self, width): ...
def box_line(self, width): ...class Path:
"""Static animation path for sprite movement"""
def __init__(self, screen, x, y, path): ...
def next_pos(self): ...
def is_finished(self, frame): ...
class DynamicPath:
"""Abstract base class for dynamic animation paths"""
def __init__(self, screen, x, y): ...
def process_event(self, event): ...
def next_pos(self): ...