Back to Projects
TUIX v0.3Beta

Last Updated: 2026-05-20

Canvas Widget

A free-draw surface with pixel-level control. Supports individual pixel setting, geometric primitives (line, rectangle, circle), text drawing, and sprite operations with caching.

Creating a Canvas

from tuix.core import builders, objects, buffers

uid = objects.create_object(
    builders.CANVAS, b"main",
    1.0, 1.0,    # full terminal width and height
    0.0, 0.0     # no margin (top-left corner)
)

# Operational object handle
buf = buffers.get_buffer_by_uid(uid)
obj = buf.contents.obj.contents

# Read-only inspection (lock-safe snapshots)
buffer_info = buffers.get_buffer_snapshot_by_uid(uid)
object_info = objects.get_object_snapshot_by_uid(uid)
Snapshot-First Inspectionv0.3 examples use lock-safe snapshots for inspection and diagnostics. Use object/buffer handles for drawing operations and snapshot APIs for read-only state reads.

Pixel Operations

tuix_canvas_set_pixel(obj, x, y, sym, fgr, fgg, fgb, bgr, bgg, bgb)

Sets a single pixel at (x, y) to the given symbol and colors.

ParameterTypeDescription
objTuixObjectObject pointer
x, yintPixel coordinates (0-based)
symint/charCharacter value (single byte)
fgr, fgg, fgbint (0–255)Foreground RGB color
bgr, bgg, bgbint (0–255)Background RGB color
# Draw a red 'X' on black background at position (10, 5)
objects.tuix_canvas_set_pixel(obj, 10, 5, ord(b'X'), 255, 0, 0, 0, 0, 0)

tuix_canvas_insert_buffer(obj, pixels_ptr, size)

Replaces the canvas pixel buffer with a pre-built pixel array. Used for bulk pixel operations.

ParameterTypeDescription
objTuixObjectObject pointer
pixels_ptrctypes pointerPointer to TuixPixel array
sizeintNumber of pixels in the array

Drawing Primitives

tuix_canvas_draw_line(obj, x0, y0, x1, y1, sym, fgr, fgg, fgb, bgr, bgg, bgb)

Draws a line from (x0, y0) to (x1, y1) using the Bresenham algorithm.

ParameterTypeDescription
x0, y0intStart coordinates
x1, y1intEnd coordinates
symint/charCharacter to draw with
fgr, fgg, fgbint (0–255)Foreground RGB
bgr, bgg, bgbint (0–255)Background RGB
# Draw a green line from (0,0) to (20,10)
objects.tuix_canvas_draw_line(obj, 0, 0, 20, 10, ord(b'*'), 0, 255, 0, 0, 0, 0)

tuix_canvas_draw_rect(obj, x, y, w, h, sym, filled, fgr, fgg, fgb, bgr, bgg, bgb)

Draws a rectangle. Set filled=1 for a solid rectangle, filled=0 for an outline.

ParameterTypeDescription
x, yintTop-left corner
w, hintWidth and height
symint/charCharacter to draw with
filledint1 for solid, 0 for outline only
fgr, fgg, fgbint (0–255)Foreground RGB
bgr, bgg, bgbint (0–255)Background RGB
# Draw a blue filled rectangle
objects.tuix_canvas_draw_rect(obj, 5, 2, 15, 8, ord(b'#'), 1, 0, 100, 255, 0, 0, 0)

# Draw a red outline rectangle
objects.tuix_canvas_draw_rect(obj, 5, 2, 15, 8, ord(b'+'), 0, 255, 0, 0, 0, 0, 0)

tuix_canvas_draw_circle(obj, cx, cy, radius, sym, filled, fgr, fgg, fgb, bgr, bgg, bgb)

Draws a circle centered at (cx, cy) with the given radius.

ParameterTypeDescription
cx, cyintCenter coordinates
radiusintCircle radius
symint/charCharacter to draw with
filledint1 for solid, 0 for outline only
fgr, fgg, fgbint (0–255)Foreground RGB
bgr, bgg, bgbint (0–255)Background RGB
# Draw a yellow filled circle
objects.tuix_canvas_draw_circle(obj, 20, 10, 5, ord(b'O'), 1, 255, 255, 0, 0, 0, 0)

Text Drawing

tuix_canvas_draw_text(obj, x, y, text, fgr, fgg, fgb, bgr, bgg, bgb)

Draws a text string starting at (x, y). Supports newline characters (\n) for multi-line text.

ParameterTypeDescription
x, yintStarting position
textbytesText to draw (e.g. b"Hello\nWorld")
fgr, fgg, fgbint (0–255)Foreground RGB
bgr, bgg, bgbint (0–255)Background RGB
objects.tuix_canvas_draw_text(obj, 5, 2, b"Hello World!", 255, 255, 255, 0, 0, 0)

Sprite Operations

tuix_canvas_draw_sprite(obj, dst_x, dst_y, sprite_w, sprite_h, sprite_ptr)

Draws a sprite (pre-built TuixPixel array) at the given position.

ParameterTypeDescription
dst_x, dst_yintDestination position on canvas
sprite_w, sprite_hintSprite dimensions
sprite_ptrctypes pointerPointer to TuixPixel array

Sprite Caching

For sprites drawn multiple times, use the caching API to avoid repeated data transfer:

# Cache a sprite (upload to C-side memory)
sprite_id = objects.tuix_canvas_cache_sprite(obj, sprite_w, sprite_h, sprite_ptr)

# Draw cached sprite at multiple positions (fast — no data transfer)
objects.tuix_canvas_draw_cached_sprite(obj, sprite_id, 10, 5)
objects.tuix_canvas_draw_cached_sprite(obj, sprite_id, 30, 5)
objects.tuix_canvas_draw_cached_sprite(obj, sprite_id, 50, 5)

# Free cached sprite when no longer needed
objects.tuix_canvas_free_cached_sprite(obj, sprite_id)
FunctionReturnsDescription
tuix_canvas_cache_sprite(obj, w, h, ptr)intNon-negative cache ID, or -1 on error
tuix_canvas_draw_cached_sprite(obj, id, x, y)int0 on success
tuix_canvas_free_cached_sprite(obj, id)NoneFrees the cached sprite

Complete Example: Bouncing Ball

from tuix.core import engine, builders, scenes, registry, objects, buffers, input
import time, math

engine.init()
builders.register_standard()
scenes.init_scene(b"main")
registry.registry.current_scene_name = b"main"
input.listen()

uid = objects.create_object(builders.CANVAS, b"main", 1.0, 1.0, 0.0, 0.0)
buf = buffers.get_buffer_by_uid(uid)
obj = buf.contents.obj.contents

# Run main_loop once to resolve geometry
engine.main_loop()
w = buf.contents.width
h = buf.contents.height

# Ball state
bx, by = w // 2, h // 2
vx, vy = 1, 1
hue = 0

for frame in range(600):
    # Clear with background
    objects.tuix_canvas_draw_rect(obj, 0, 0, w, h, ord(b' '), 1, 0, 0, 0, 20, 20, 30)
    
    # Draw border
    objects.tuix_canvas_draw_rect(obj, 0, 0, w, h, ord(b'.'), 0, 60, 60, 60, 20, 20, 30)
    
    # Move ball
    bx += vx
    by += vy
    if bx <= 1 or bx >= w - 2:
        vx = -vx
    if by <= 1 or by >= h - 2:
        vy = -vy
    
    # HSL color cycling
    r = int(127 + 127 * math.sin(hue))
    g = int(127 + 127 * math.sin(hue + 2.094))
    b_color = int(127 + 127 * math.sin(hue + 4.189))
    hue += 0.05
    
    # Draw ball
    objects.tuix_canvas_draw_circle(obj, bx, by, 2, ord(b'O'), 1, r, g, b_color, 20, 20, 30)
    
    engine.main_loop()
    time.sleep(0.016)

buffers.free_buffer(b"main", uid)
input.stop()
engine.shutdown()