
Features • Showcase • Getting Startet • Module Reference • Core Concepts • Advanced Features • Example Games • Roadmap • Contributing
A lightweight, dependency-free engine for creating terminal-based games in Python. Perfect for building text-based adventures, roguelikes, and retro-style games.
# Quick start
git clone https://github.com/yourusername/tengine.git
cd tengine
python3 snake.py # Run the example game
- Cross-platform - Works on Windows, Linux, and macOS
- ANSI color support - Full 16-color support with formatting options
- Input handling - Real-time keyboard input without blocking
- Scene management - Easy scene transitions and organization
- Lightweight - No external dependencies
- Simple API - Intuitive object-oriented design
This is an example of what tengine is capable of:
Note
Still all running in the terminal. Even the flappybird clone. :)
from tengine.core import Game, Scene
from tengine.core.geometry import Point
from tengine.core.color import Color
game = Game(width=20, height=10, border=True)
class Hello(Scene):
def __init__(self):
super().__init__()
def update(self):
self.render_queue.draw_text(f"{Color.fg.green}Hello, tengine!{Color.reset}", Point(2, 1))
if __name__ == "__main__":
game.add_scene("hello", Hello())
game.set_scene("hello")
game.run()
Run it with python3 hello.py
. You just rendered your first colored string!
Class / Method | Signature | Description | |
---|---|---|---|
Game | Game(width:int, height:int, border:bool=True) |
Initialise a terminal “canvas”. | |
.add_scene(name:str, scene:Scene) |
Register a scene object. | ||
.set_scene(name:str) |
Switch active scene (triggers Scene.setup ). |
||
.run() |
Enter the mainloop (blocks). | ||
.quit(status:int|None=None) |
Gracefully restore terminal and exit. | ||
Scene | Scene(tickdelay:float=0.08, bg_symbol:str=' ', bg_symbol_frmt:str='') |
Base class | |
.setup() |
Called once whenever the scene becomes active. | ||
.update() |
Called every tick; implement game logic here. | ||
.render_queue |
Frame buffer for this scene. | ||
.input_manager |
Keyboard handling for this scene. |
Class / Function | Brief description |
---|---|
RenderQueue | Off‑screen buffer. Key methods: draw_char() , draw_text() , draw_line() , draw_circle() , draw_rectangle() , draw_triangle() , clear() |
RenderManager | Handles border, displaying the RenderQueue buffer and cursor reset. Internal to Game , rarely used directly. |
Item | Description |
---|---|
InputManager | Handles user input. Key functions: add_binding() , block_key() , allow_key() |
Color
: nestedfg
/bg
classes with 16 standard colours plusrgb(r,g,b)
helpers.- Formatting flags:
Color.bold
,Color.underline
,Color.reverse
,Color.reset
, … len_no_ansi(text:str) -> int
– correct length of coloured strings.split_and_group_ansi(text:str) -> list[str]
– internal helper; exposed for advanced use.
Name | Purpose |
---|---|
Point(x:int=0, y:int=0) | Immutable 2‑D point with math (+ , - , comparisons) and .copy() . |
line(start,end) |
Bresenham line points. |
circle(center,r, aspect_ratio=0.5) / filled_circle(...) |
Points approximating a circle in terminal cells. |
rectangle(top_left,w,h) / filled_rectangle(...) |
Points approximating a rectangle in terminal cells. |
triangle(a,b,c) / filled_triangle(...) |
Points approximating a triangle in terminal cells. |
Concept | What it does | Where to import |
---|---|---|
Game | Top‑level controller: window size, active scene, main loop | tengine.core.Game |
Scene | Encapsulates a game state; override setup() & update() |
tengine.core.Scene |
RenderQueue | Off‑screen buffer you draw into each frame | tengine.core.rendering.RenderQueue |
RenderManager | Flushes a queue to the terminal each tick | tengine.core.rendering.RenderManager |
InputManager | Non‑blocking keyboard bindings | tengine.core.input.InputManager |
Color | ANSI helpers (Color.fg.red , Color.bg.blue , Color.bold , …) |
tengine.core.color.Color |
Geometry | 2‑D math plus ready‑made shapes | tengine.core.geometry |
The main controller for your game:
game = Game(
width=60, # Grid width in characters
hight=30, # Grid height in characters
border=True # Display border around play area
)
Represents different game states (menus, levels, etc.):
class CustomScene(Scene):
def __init__(self):
"""Initial scene Initialization"""
super().__init__(
tickdelay=0.1, # Tick update interval in seconds
bg_symbol=' ', # Background character
bg_symbol_frmt=Color.bg.red # ANSI Formating for bg_symbol
)
def setup(self):
"""Initialize scene resources (called each time the game switches to this scene using Game.set_scene)"""
def update(self):
"""Called every tick for game logic"""
Add content to the display:
# Add single character at position
Scene.render_queue.draw_char(Point(3, 4), "#")
# Add multi-line string of characters starting from origin point
Scene.render_queue.draw_text("[----------]", Point(10, 5))
# Format text using Color class
Scene.render_queue.draw_stext(f"{Color.bold}{Color.fg.Red}[ SCORE: 100 ] {Color.reset}", Point(0, 0))
# Draw a line from point a to point b
Scene.render_queue.draw_line(Point(0, 0), Point(5, 5), '#')
Each Scene instance has its own render queue which can be accessed via: self.render_queue
. You can also manipulate a scenes render queue from outside the instance like so: scene.render_queue
.
Handle keyboard input:
class GameScene(Scene):
def __init__(self):
super().__init__()
# Bind keys to handler function
self.input_manager.add_binding('a', self.key_handler_a)
self.input_manager.add_binding('b', self.key_handler_b)
self.input_manager.add_binding('c', self.key_handler_c)
def key_handler_a(self):
# Handle key press
def key_handler_b(self):
# Handle key press
def key_handler_c(self,):
# Handle key press
def setup(self):
# Initialize var when scene is loaded
self.last_key = "..." # Var to hold last key that was pressed
def update(self):
# Display last key that was pressed on screen
self.render_queue.add_string(f"Last Key Pressed: {self.last_key}", Point(1, 1))
Use ANSI colors for rich visuals:
from tengine.color import Color
# Basic usage
f"{Color.fg.red}Warning! {Color.fg.green}Safe zone{Color.reset}"
# Combine styles
f"{Color.bold}{Color.underline}Important!{Color.reset}"
# Background colors
f"{Color.bg.blue}Water area{Color.reset}"
# Style text with rgb colors
f"{Color.fg.rgb(255, 0, 255)}{Color.bg.rgb(0, 255, 0)}RGB Text!{Color.reset}"
from tengine.color import len_no_ansi
text = f"{Color.fg.red}Hello{Color.reset}"
print(len(text)) # Resulting number will be much larger then the text displayed because the ansi codes are also counted as characters.
print(len_no_ansi(text)) # Using len_no_ansi will strip the text of ansi codes before counting the length, which results in the correct number.
The Point
class simplifies position math:
p1 = Point(3, 4)
p2 = Point(1, 1)
print(p1 + p2) # → Point(4, 5)
print(p1 > p2) # → True
The repository includes a complete Snake game:
cp tengine examples/snake
cd examples/snake
python3 snake.py
The game gives a simple usage example for tengine. This includes:
- The coloring system
- Saving game states
- Input management
- Multiple scenes
- Dynamic object rendering
Take a look at snake.py to lern more about how the game works.
The repository also includes a complete Flappybord clone:
cp tengine examples/flappybird
cd examples/flappybird
python3 flappybird.py
The game gives a advanced usage example for tengine. This includes:
- The rgb coloring system
- Saving game states
- Input management
- Multiple scenes
- Dynamic .ppm sprite rendering.
- Collison detection using collider boxes.
Take a look at flappybird.py to lern more about how the game works.
Planned features:
- More example games (Slots, Flappybird)
- Improved documentation
- Entity component system (ECS)
Contributions are welcome! Thx 💜
tengine
is distributed under the MIT License (see LICENSE
).