Widget reference
Tetra widgets describe what appears on the display and how each element is arranged. Import the render module before creating a widget tree:
load("render.star", "render")
Every rendered app returns a render.Root. Nest layout, text, image, shape,
chart, and animation widgets below it to build the final 64 × 32 frame.
Shared behavior
Colors accept CSS-style hexadecimal values: #rgb, #rrggbb, #rgba, and
#rrggbbaa.
Widgets expose two useful methods:
size()returns the rendered width and height. It is especially useful for widgets whose dimensions depend on their content, such asText.frame_count()returns the number of frames produced by an animated widget, such asMarquee.
Animation
Animation turns its child list into frames. Frame 0 uses the first child,
frame 1 uses the second, and so on.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
children | [Widget] | No | Widgets to render as consecutive frames. |
render.Animation(
children=[
render.Circle(diameter=8, color="#4f46e5"),
render.Circle(diameter=12, color="#7c3aed"),
render.Circle(diameter=16, color="#a855f7"),
],
)

Box
Box creates a rectangular region. Without color, its background is
transparent. It uses all available space unless you set width or height,
and centers its child within the resulting area.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
child | Widget | No | Widget centered inside the box. |
width | int | No | Maximum box width in pixels. |
height | int | No | Maximum box height in pixels. |
padding | int | No | Space between the child and the box edges. |
color | color | No | Background fill. |
render.Box(
width=64,
height=32,
color="#111827",
child=render.Text("Hello", color="#f9fafb"),
)

Circle
Circle draws a filled circle. An optional child is centered inside it.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
color | color | Yes | Circle fill. |
diameter | int | Yes | Diameter in pixels. |
child | Widget | No | Widget centered in the circle. |
render.Circle(
diameter=30,
color="#312e81",
child=render.Circle(diameter=10, color="#22d3ee"),
)

Column
Column places children from top to bottom. Its natural height is the combined
height of its children, and its width matches the widest child. Set expanded
to occupy all available vertical space.
main_align controls vertical distribution:
"start","center", or"end""space_between","space_evenly", or"space_around"
cross_align controls horizontal placement with "start", "center", or
"end".
| Parameter | Type | Required | Purpose |
|---|---|---|---|
children | [Widget] | Yes | Widgets arranged vertically. |
main_align | str | No | Distribution along the vertical axis. |
cross_align | str | No | Alignment along the horizontal axis. |
expanded | bool | No | Fill the available height. |
render.Column(
children=[
render.Box(width=12, height=5, color="#22d3ee"),
render.Box(width=22, height=7, color="#fbbf24"),
render.Box(width=32, height=4, color="#a855f7"),
],
)

With expanded=True, the same children can use the available height and
space_around distribution:
render.Column(
expanded=True,
main_align="space_around",
cross_align="center",
children=[
render.Box(width=12, height=5, color="#22d3ee"),
render.Box(width=22, height=7, color="#fbbf24"),
render.Box(width=32, height=4, color="#a855f7"),
],
)

Image
Image decodes binary PNG, JPEG, GIF, or SVG data supplied through src.
Tetra preserves the source dimensions unless width or height is provided;
resizing uses nearest-neighbor interpolation. Animated GIFs retain their
frames, and their frame delay is available through the read-only delay
attribute.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
src | str | Yes | Binary image data or SVG markup. |
width | int | No | Output width in pixels. |
height | int | No | Output height in pixels. |
delay | int | No | Read-only GIF frame delay in milliseconds. |
This example uses the same PNG with its unnecessary color-profile metadata removed, reducing the encoded value from more than 4,000 characters to about 350 without changing the image:
load("encoding/base64.star", "base64")
ICON = base64.decode(
"iVBORw0KGgoAAAANSUhEUgAAABkAAAAYCAMAAAA4a6b0AAAAJ1BMVEUAAABBJBb+0wvT" +
"min//vr71QQEBAT///cMCQQBCwD6zwT/0BL31g9Dk4qKAAAAAXRSTlMAQObYZgAAAItJ" +
"REFUKM99ktkSgCAIRQW1bPn/7w1kycg6T8TpojOYkgJGegKASn466hdCVIYxYG2mupIA" +
"DujELhDn5kU/a/miGzrGG6WsagDpS2oa4zWN+zNt00FYd61a64b/lMixe6lmdm8ymY" +
"vg622iYuPKcGHmHblVZkZBJqZ8eRAGjgvX2Bm3LTFj8nrCq7oAcPEFwi8JX50AAAAAS" +
"UVORK5CYII="
)
render.Image(src=ICON)

Marquee
Marquee scrolls content that does not fit its viewport. Horizontal scrolling
moves right to left and requires width. Vertical scrolling moves bottom to
top and requires height. Content that already fits remains still.
Use offset_start and offset_end to adjust where the motion begins and ends.
When no scrolling is required, align accepts "start", "center", or
"end".
| Parameter | Type | Required | Purpose |
|---|---|---|---|
child | Widget | Yes | Widget to scroll when it exceeds the viewport. |
width | int | No | Horizontal viewport width. |
height | int | No | Vertical viewport height. |
offset_start | int | No | Starting position adjustment. |
offset_end | int | No | Ending position adjustment. |
scroll_direction | str | No | "horizontal" (default) or "vertical". |
align | str | No | Placement when the child fits; defaults to "start". |
delay | int | No | Frames to wait before scrolling; defaults to 0. |
render.Marquee(
width=64,
child=render.Text("Welcome to SolidPixels", color="#fbbf24"),
offset_start=4,
offset_end=8,
)

Padding
Padding adds space around one child. Pass one integer to apply the same value
on every side, or a (left, top, right, bottom) tuple for individual sides.
With expanded=True, the widget fills the bounds supplied by its parent.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
child | Widget | Yes | Widget surrounded by padding. |
pad | int or (int, int, int, int) | No | Insets around the child. |
expanded | bool | No | Fill the available bounds. |
color | color | No | Background fill behind the padded area. |
render.Padding(
pad=(4, 2, 4, 2),
color="#172554",
child=render.Text("Live", color="#ffffff"),
)

PieChart
PieChart displays proportional values as colored sectors. colors and
weights are parallel lists, so each weight uses the color at the same index.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
colors | [color] | Yes | Sector colors. |
weights | [float] | Yes | Relative sector sizes. |
diameter | int | Yes | Chart diameter in pixels. |
render.PieChart(
colors=["#22c55e", "#eab308", "#ef4444"],
weights=[55, 30, 15],
diameter=30,
)

Plot
Plot draws a line or scatter series from (x, y) coordinates. It can style
positive and negative values independently and optionally fill the region
between the series and the x-axis.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
data | [(float, float)] | Yes | Ordered (x, y) points. |
width | int | Yes | Chart width in pixels. |
height | int | Yes | Chart height in pixels. |
color | color | No | Color for values at or above zero; defaults to #fff. |
color_inverted | color | No | Color for values below zero. |
x_lim | (float, float) | No | Visible x-axis range. |
y_lim | (float, float) | No | Visible y-axis range. |
fill | bool | No | Fill between the series and x-axis. |
chart_type | str | No | "line" (default) or "scatter". |
fill_color | color | No | Fill color above zero. |
fill_color_inverted | color | No | Fill color below zero. |
render.Plot(
data=[(0, 2), (1, 5), (2, 3), (3, -1), (4, 4)],
width=64,
height=32,
color="#22d3ee",
color_inverted="#c084fc",
y_lim=(-2, 6),
fill=True,
fill_color="#164e63",
fill_color_inverted="#581c87",
)

Root
Root is the top-level widget returned by an app. Its descendants render onto
the display canvas, beginning at the upper-left corner. For animated trees,
delay sets the time between frames.
Set max_age when old output should expire rather than remain visible after a
data source stops updating. show_full_animation asks the device to finish the
animation even when it lasts longer than the normal app cycle.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
child | Widget | Yes | Widget tree to render. |
delay | int | No | Milliseconds between animation frames. |
max_age | int | No | Seconds before the rendered result expires. |
show_full_animation | bool | No | Play the complete animation during each cycle. |
def main(config):
return render.Root(
delay=100,
child=render.Text("Ready", color="#22d3ee"),
)

Return an empty list ([]) instead when an app should be omitted from the
rotation because it has nothing to display.
Row
Row places children from left to right. Its natural width is the combined
width of its children, and its height matches the tallest child. Set expanded
to occupy all available horizontal space.
main_align controls horizontal distribution:
"start","center", or"end""space_between","space_evenly", or"space_around"
cross_align controls vertical placement with "start", "center", or
"end".
| Parameter | Type | Required | Purpose |
|---|---|---|---|
children | [Widget] | Yes | Widgets arranged horizontally. |
main_align | str | No | Distribution along the horizontal axis. |
cross_align | str | No | Alignment along the vertical axis. |
expanded | bool | No | Fill the available width. |
render.Row(
children=[
render.Box(width=10, height=8, color="#22d3ee"),
render.Box(width=14, height=12, color="#fbbf24"),
render.Box(width=20, height=16, color="#a855f7"),
],
)

With expanded=True, the same children can use the available width and
space_between distribution:
render.Row(
expanded=True,
main_align="space_between",
cross_align="end",
children=[
render.Box(width=10, height=8, color="#22d3ee"),
render.Box(width=14, height=12, color="#fbbf24"),
render.Box(width=20, height=16, color="#a855f7"),
],
)

Sequence
Sequence plays animated children one after another. Each child remains active
for its own frame count before Tetra advances to the next child.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
children | [Widget] | Yes | Animated widgets played in order. |
render.Sequence(
children=[
render.Marquee(width=64, child=render.Text("First message")),
render.Marquee(width=64, child=render.Text("Second message")),
],
)

Stack
Stack paints children on top of one another in list order. Its dimensions are
large enough to contain every child, making it useful for backgrounds,
overlays, and simple compositing.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
children | [Widget] | Yes | Widgets layered in order. |
render.Stack(
children=[
render.Box(width=64, height=32, color="#111827"),
render.Text("LIVE", color="#ef4444"),
],
)

Text
Text renders one line. The default font is tb-8; use font to select a
different bundled face. height constrains its drawing area, while offset
moves the glyphs vertically for baseline adjustments.
| Parameter | Type | Required | Purpose |
|---|---|---|---|
content | str | Yes | Text to draw. |
font | str | No | Font face name. |
height | int | No | Drawing-area height. |
offset | int | No | Vertical glyph offset. |
color | color | No | Text color. |
render.Text(
content="SolidPixels",
font="6x13",
color="#22d3ee",
)

WrappedText
WrappedText lays text across multiple lines. Set width and height to
bound the drawing area; omitted dimensions expand to fit the content. align
accepts "left", "center", or "right".
| Parameter | Type | Required | Purpose |
|---|---|---|---|
content | str | Yes | Text to draw. |
font | str | No | Font face name. |
height | int | No | Maximum drawing height. |
width | int | No | Maximum drawing width. |
linespacing | int | No | Space between lines. |
color | color | No | Text color. |
align | str | No | "left", "center", or "right". |
render.WrappedText(
content="Updates at a glance",
width=58,
align="center",
color="#f9fafb",
)
