Schema reference
Schemas define the settings shown when someone configures an app. Export
get_schema() and return a schema.Schema. SolidPixels saves each field under
its id, then passes those values to main(config) when the app renders.
Quick start
This complete app lets someone change the greeting and select a smaller font:
load("render.star", "render")
load("schema.star", "schema")
DEFAULT_WHO = "World"
def main(config):
message = "Hello, %s!" % config.str("who", DEFAULT_WHO)
if config.bool("small", False):
text = render.Text(message, font = "CG-pixel-3x5-mono")
else:
text = render.Text(message)
return render.Root(child = text)
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Text(
id = "who",
name = "Who?",
desc = "Who to greet.",
icon = "arrowsMaximize",
default = DEFAULT_WHO,
),
schema.Toggle(
id = "small",
name = "Small text",
desc = "Display the greeting with a smaller font.",
icon = "text",
default = False,
),
],
)
Pass configuration values to a local render as key=value arguments:
tetra render app.star "who=SolidPixels" "small=True" -o app.webp
Use a stable, unique id for every field. Increment version when a schema
change requires SolidPixels to refresh previously stored configuration.
Icons
The icon property selects the icon displayed beside a field. SolidPixels
currently publishes these icons in its
attribute icon catalog:
An unrecognized name uses the default icon.
Dynamic fields
Most fields contain a fixed value. Dynamic fields also receive a handler
function that SolidPixels calls while the installation form is being filled
out:
Generatedreturns more schema fields based on another field.LocationBasedreturns options for a selected location.OAuth2exchanges an authorization response for an access token.Typeaheadreturns options matching entered text.
Handlers run during configuration, not during the normal main(config) render.
Color
Color displays a color picker. Its configuration value is a hex color string
with a leading #, ready to pass to a render widget. Add palette to suggest
useful choices without preventing a custom color.
load("schema.star", "schema")
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Color(
id = "color",
name = "Color",
desc = "Color of the screen.",
icon = "brush",
default = "#7AB0FF",
palette = [
"#7AB0FF",
"#BFEDC4",
"#78DECC",
"#DBB5FF",
],
),
],
)
Read it with config.str("color", "#7AB0FF").
DateTime
DateTime displays a date-and-time picker. Its configuration value is a string
accepted by time.parse_time().
load("render.star", "render")
load("schema.star", "schema")
load("time.star", "time")
DEFAULT_TIME = "2026-01-01T00:00:00Z"
def main(config):
event_time = time.parse_time(config.str("event_time", DEFAULT_TIME))
return render.Root(
child = render.Text(event_time.format("2006-01-02")),
)
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.DateTime(
id = "event_time",
name = "Event time",
desc = "Date and time of the event.",
icon = "clock",
),
],
)
Dropdown
Dropdown selects one value from a fixed list. Each schema.Option has the
label shown to the user in display and the saved configuration in value.
load("render.star", "render")
load("schema.star", "schema")
OPTIONS = [
schema.Option(display = "Pink", value = "#FF94FF"),
schema.Option(display = "Mustard", value = "#FFD10D"),
]
def main(config):
return render.Root(
child = render.Text(
"Hello",
color = config.str("color", OPTIONS[0].value),
),
)
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Dropdown(
id = "color",
name = "Text color",
desc = "Color of the displayed text.",
icon = "brush",
default = OPTIONS[0].value,
options = OPTIONS,
),
],
)
Generated
Generated adds fields based on the current value of another field. Set
source to that field's id; the source value is passed to handler.
Generated forms are harder to understand and test than fixed schemas. Prefer a fixed set of fields when possible.
load("schema.star", "schema")
def pet_options(pet):
if pet == "dog":
return [
schema.Toggle(
id = "leash",
name = "Bring a leash",
desc = "Show the leash reminder.",
icon = "dog",
default = False,
),
]
if pet == "cat":
return [
schema.Toggle(
id = "litter_box",
name = "Litter box",
desc = "Show the litter-box reminder.",
icon = "block-question",
default = False,
),
]
return []
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Text(
id = "pet",
name = "Pet",
desc = "Enter dog or cat.",
icon = "dog",
),
schema.Generated(
id = "pet_details",
source = "pet",
handler = pet_options,
),
],
)
Location
Location lets someone choose a place. Read it with
config.get("location"); the returned object contains:
| Key | Value |
|---|---|
lat | Latitude string |
lng | Longitude string |
description | Human-readable place |
locality | City or locality |
place_id | Place provider identifier |
timezone | IANA time zone, such as America/New_York |
load("schema.star", "schema")
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Location(
id = "location",
name = "Location",
desc = "Location used by the app.",
icon = "location-dot",
),
],
)
Before sending coordinates to a third-party API, reduce their precision to the minimum that API needs. Do not expose a user's exact location unnecessarily.
LocationBased
LocationBased calls its handler with a JSON-encoded location and displays the
returned schema.Option list. The selected configuration value is a JSON string
containing both display and value.
load("encoding/json.star", "json")
load("schema.star", "schema")
def nearby_stations(raw_location):
location = json.decode(raw_location)
locality = location.get("locality", "")
if locality == "New York":
return [
schema.Option(
display = "Grand Central Terminal",
value = "grand_central",
),
]
return []
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.LocationBased(
id = "station",
name = "Train station",
desc = "Choose a nearby train station.",
icon = "location-crosshairs",
handler = nearby_stations,
),
],
)
The selected value has this shape:
{"display": "Grand Central Terminal", "value": "grand_central"}
Decode it with json.decode(config.get("station")) before reading value.
OAuth2
OAuth2 starts an OAuth 2 authorization flow. It requires a client ID,
authorization endpoint, scopes, and a handler. The handler receives a
JSON-encoded object containing the authorization response and must return the
access token.
load("schema.star", "schema")
def oauth_handler(params):
# Exchange the provider's authorization code for an access token here.
# The exact request and response are provider-specific.
fail("Configure this handler for your OAuth provider")
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.OAuth2(
id = "auth",
name = "Connect account",
desc = "Authorize access to your account.",
icon = "key",
handler = oauth_handler,
client_id = "your-client-id",
authorization_endpoint = "https://provider.example/oauth/authorize",
scopes = ["profile:read"],
),
],
)
The redirect URL and token exchange depend on the OAuth provider configured in
SolidPixels. Register that configured redirect URL with the provider. Store a
client secret with the platform's OAuth provider configuration or encrypt it
with tetra encrypt; never commit the plaintext value.
PhotoSelect
PhotoSelect opens a photo picker. SolidPixels crops the selected image to
64 × 32 pixels and stores it as a Base64-encoded string.
load("encoding/base64.star", "base64")
load("render.star", "render")
load("schema.star", "schema")
def main(config):
photo = config.get("photo")
if photo == None:
child = render.Text("Choose a photo")
else:
child = render.Image(src = base64.decode(photo))
return render.Root(child = child)
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.PhotoSelect(
id = "photo",
name = "Add photo",
desc = "Photo shown on the display.",
icon = "image",
),
],
)
Text
Text displays a text input and saves its string value under the field id.
load("schema.star", "schema")
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Text(
id = "message",
name = "Message",
desc = "Message shown on the display.",
icon = "text",
default = "Hello",
),
],
)
Read it with config.str("message", "Hello").
Toggle
Toggle displays an on/off switch and saves True or False. Use
config.bool() so command-line configuration is converted to a boolean too.
load("schema.star", "schema")
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Toggle(
id = "party_mode",
name = "Party mode",
desc = "Enable the party animation.",
icon = "flag",
default = False,
),
],
)
Read it with config.bool("party_mode", False).
Typeahead
Typeahead calls its handler with the current search text. Return matching
schema.Option values. Like LocationBased, the selected configuration value
is a JSON string containing display and value.
load("schema.star", "schema")
FRUIT = [
schema.Option(display = "Apple", value = "apple"),
schema.Option(display = "Apricot", value = "apricot"),
schema.Option(display = "Banana", value = "banana"),
]
def search_fruit(pattern):
query = pattern.lower()
return [
option
for option in FRUIT
if option.display.lower().startswith(query)
]
def get_schema():
return schema.Schema(
version = "1",
fields = [
schema.Typeahead(
id = "fruit",
name = "Fruit",
desc = "Search for a fruit.",
icon = "hashtag",
handler = search_fruit,
),
],
)
The selected value has this shape:
{"display": "Apple", "value": "apple"}