CLI tool
tidbyt/pixlet avatar
tidbyt/pixlet

Pixlet: a Starlark runtime for 64 by 32 pixel displays

Build apps for pixel-based displays ✨

846 stars119 forksGoApache-2.0

At a glance

What is it?
Pixlet is a Go app runtime and UX toolkit for tiny displays, using a Python-like scripting language called Starlark and a widget tree that renders to WebP or GIF. Apps written with it can be previewed in a browser, and pushed to a physical Tidbyt device, which is what makes it more than a renderer.
Who is it for?
Pixlet suits a developer who wants to publish an app for a tiny LED matrix display without learning a display specific language, since Starlark is a small Python-like language and the widget tree does the layout work. It does not suit a project that needs a rich screen, because a 64 by 32 RGB matrix is the design target and the layout primitives are sized for it.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A 64 by 32 RGB matrix is the design target, not an afterthought

Pixlet is an app runtime and UX toolkit for highly constrained displays. The reference hardware is a Tidbyt, which has a 64x32 RGB LED matrix display. Everything about the framework follows from that number.

The problem being solved is specific: how do you build an app for a screen that is thirty two pixels tall, where a line of text is a handful of pixels, where there is no pointer, no scrolling container and no room for a dialog. The framework gives you a widget tree, a fixed pixel font set and a renderer, and it gives them to you in a language that does not require a build step for the app itself.

That last point is why Starlark is the scripting language. Pixlet scripts are written in Starlark, a Python-like language, and the reference implementation in Go is the one linked from the README. The advantage is that an applet is a single file you can fetch over HTTP and run, which is exactly what the tutorial does.

The apps have three output paths. They can be served in a browser, they can be rendered as WebP or GIF animations, and they can be pushed to a physical Tidbyt device. The first two are for development. The third is the product.

The audience is developers who want to write a small utility that shows up on a cheap display on their desk or their wall: a clock, a price tracker, a status board. The examples directory in the repository shows the range, with a clock, a bitcoin tracker, a QR code renderer, a sunrise calculation, a life counter, a humanizer, a quadrants demo, a font preview and a schema example.

The project is Apache-2.0 licensed and is written in Go, with a Go module named tidbyt.dev/pixlet.

A Starlark script returns a widget tree, and the tree is the whole API

The Hello World applet is the clearest possible statement of the model.

starlark
load("render.star", "render")
def main():
    return render.Root(
        child = render.Text("Hello, World!")
    )

There is no scene, no component, no lifecycle. The script defines a function called main, and that function returns a widget tree. render.Root is the top of the tree, render.Text is a leaf, and the child argument attaches one to the other.

The clock example shows what a slightly more elaborate applet looks like, and it introduces two things: configuration and animation.

starlark
load("render.star", "render")
load("time.star", "time")

def main(config):
    timezone = config.get("timezone") or "America/New_York"
    now = time.now().in_location(timezone)

    return render.Root(
        delay = 500,
        child = render.Box(
            child = render.Animation(
                children = [
                    render.Text(
                        content = now.format("3:04 PM"),
                        font = "6x13",
                    ),
                    render.Text(
                        content = now.format("3 04 PM"),
                        font = "6x13",
                    ),
                ],
            ),
        ),
    )

The main function takes a config argument, which is how an applet receives settings from whoever installs it. Here it reads a timezone key with a default fallback. The time module is a Starlark module, loaded the same way render is, and gives a time value that can be moved to a location and formatted.

The animation is built by giving render.Animation a list of children, and the delay of 500 on the root is the frame duration in milliseconds, so the two frames alternate every half second. That produces the blinking colon separator described in the text, achieved by formatting the time two different ways in the two frames.

The fonts are named by their pixel dimensions, so a font called 6x13 is six pixels tall and thirteen wide. The docs include a notes file on the available fonts, and a font preview example applet exists in the repository.

The widget vocabulary is documented separately in a widget reference, an animation reference, a modules reference and a schema reference, plus an authoring notes document on how to think about apps for this class of display.

Serving an applet from a URL is the entire first run

Installing the CLI is the only setup step, and the two platforms are handled differently.

On macOS it is a Homebrew formula.

code
brew install tidbyt/tidbyt/pixlet

On Linux you download the pixlet binary from the latest release, or you build from source, and the README links a build document for that.

The first run is a single command that pipes a script straight from GitHub into the server.

console
curl https://raw.githubusercontent.com/tidbyt/pixlet/main/examples/hello_world/hello_world.star | \
  pixlet serve /dev/stdin

The result is viewable at http://localhost:8080. The serve command runs the script and hosts the result so you can look at it in a browser, which is the fastest feedback loop available for a display this small.

The command line surface is described in the README in terms of what the CLI does with a script. It runs the scripts and renders the result as a WebP or a GIF animation, and you can view the animation in your browser, save it, or push it to a device with pixlet push.

The push flow is a sequence of steps rather than one command, and it is worth walking through because each command has a distinct job. You render the applet to a file, log in to your Tidbyt account, list the devices you can push to, and then push the rendered file to a device by its ID.

console
# render the bitcoin example
pixlet render examples/bitcoin/bitcoin.star

# login to your Tidbyt account
pixlet login

# list available Tidbyt devices
pixlet devices

# push to your favorite Tidbyt
pixlet push <YOUR DEVICE ID> examples/bitcoin/bitcoin.webp

The device ID comes from the pixlet devices command, or from the settings for the device in the Tidbyt app on your phone, where there is a Get API key control.

A push without an installation ID shows the app once

This is the detail in the README that changes how you think about the push model, and it is easy to skim past.

Pushing an applet to a Tidbyt without an installation ID simply displays the applet one time. To have the applet display continuously as part of the rotation, you add an installation ID to the push command.

console
pixlet render examples/bitcoin/bitcoin.star
pixlet push --installation-id <INSTALLATION ID> <YOUR DEVICE ID> examples/bitcoin/bitcoin.webp

The installation ID is a name, and the example uses Bitcoin, which is how the applet then appears in the mobile app.

The note at the end of that section explains the division of labour between rendering and pushing. pixlet render executes your Starlark code and generates a WebP image. pixlet push deploys the generated WebP image to your device. And you need to repeat the process if you want the app to keep updating.

That is the sharpest limitation in the whole tool, and it is a design decision rather than an oversight. The device displays a static image that the device fetches; the applet is not a continuously running program on the device. The applet is executed on your machine, at render time, and the result is a picture that is pushed.

The alternative path is Community Apps, hosted separately, which run on Tidbyt's own servers and update automatically. So the project documents two models: a local applet you render and push yourself, on a schedule, or a hosted community app that the platform runs for you.

The manifest directory in the repository is where the app metadata and schema live, and the schema reference in the docs describes the format the device expects, which matters if you are writing an applet that will be installed by someone else rather than just pushed to your own device.

The Go side has generators for widgets and fonts, and a Starlark runtime

The repository is mostly Go, but it is a Go project with a JavaScript subproject attached, and the split is visible in the top level listing.

The Go module is tidbyt.dev/pixlet, requiring Go 1.22 with a 1.22.2 toolchain. The main source directories cover the runtime, the render package, the encode package, the server, the manifest handling, the schema, the Starlark utilities, the command line layer under cmd, and the fonts.

The Starlark interpreter itself comes from go.starlark.net, the Google implementation, and the module also pulls in qri-io/starlib for the standard library of Starlark modules. The time module used in the clock example is one of those library modules.

The rendering path is where the interesting dependencies are. There is a Go library for WebP encoding, which is what the push pipeline needs, plus a pure Go library for SVG rendering, a rasteriser, a QR code generator, a library for sunrise and sunset calculation, a colour quantiser, an image resizer, and a cowsay implementation. The module list reads like the ingredient list of a small pixel graphics stack.

Two Makefile targets explain a lot about the design. The widgets target runs a generator in the runtime directory and then formats the tree, and the embedfonts target runs a generator in the render directory and formats. So the widget set and the font set are generated into the source tree rather than written by hand, and the generated code is committed.

There is a bench target that runs a specific benchmark in the encode package with a twenty second benchtime, and a test target that runs the whole tree with verbose output and coverage. The lint target uses buildifier for Starlark files, installing it if it is not present, and format depends on lint, so formatting and linting are one step. Release targets exist for macOS, Linux and Windows, and the goreleaser configuration at the root is what drives them.

Where Pixlet is the wrong tool

The first wrong-tool case is anything that needs a real screen. Every design decision, from the 6x13 font to the widget set, assumes a 64 by 32 pixel matrix. A dashboard, a terminal UI or a phone app is a different problem, and Pixlet will not get you there.

The second case is a display that needs continuous updating. The push model is render on your machine, push a still image, repeat. If you want a second-by-second clock, the update has to be pushed on a schedule, which is what the Community Apps model exists to solve, but that means hosting on Tidbyt's servers rather than running the applet yourself.

The third case is a team that wants a general scripting environment. Starlark is deliberately small and deterministic, which is the right property for a display applet and the wrong one for a scripting language you want to grow into. There is no package manager for applets, no shared library mechanism beyond the load statement, and the standard modules are the ones the framework ships.

There is also a release cadence question worth flagging. The listed release tags are v0.34.0 from 2024-09-30, v0.33.5 from 2024-09-19 and v0.33.4 from 2024-09-12, while the last push to the repository was on 2026-10-19. The source tree is being worked on, and the README notes that a new documentation site has moved to tidbyt.dev with the repository docs to be updated in the coming weeks. Between the tags and the current tree there is a gap, and the documentation itself is mid-migration, which is worth knowing if you are pinning a version for a device you cannot easily reach.

On licensing, the project is Apache-2.0, and the repository carries a LICENSE.txt file, so redistribution of the runtime and the fonts is straightforward. The applets you write are yours, and the fonts are shipped in the repository with their own notes in the docs.

Editorial conclusion

Pixlet suits a developer who wants to publish an app for a tiny LED matrix display without learning a display specific language, since Starlark is a small Python-like language and the widget tree does the layout work. It does not suit a project that needs a rich screen, because a 64 by 32 RGB matrix is the design target and the layout primitives are sized for it. Before adopting, install the CLI with brew install tidbyt/tidbyt/pixlet on macOS or take the release binary on Linux, and read the widget reference and schema reference in the docs directory, since the schema is what the device expects when an app is pushed.

Frequently asked questions

What is Pixlet and what is it for?

Pixlet is an app runtime and UX toolkit for highly constrained displays, developed for Tidbyt devices with a 64x32 RGB LED matrix display. Apps written with it can be served in a browser, rendered as WebP or GIF animations, or pushed to a physical Tidbyt device.

How do I install Pixlet and run my first applet?

On macOS install it with brew install tidbyt/tidbyt/pixlet, and on Linux download the pixlet binary from the latest release or build from source. Then pipe an example into the server with pixlet serve and open http://localhost:8080 to see the result.

What language are Pixlet applets written in?

Applets are written in Starlark, a simple Python-like language, using the Google Go implementation go.starlark.net. An applet defines a main function that returns a widget tree, as in the Hello World example using render.Root and render.Text.

How do I push an applet to a Tidbyt device?

Render the applet to a file with pixlet render, log in with pixlet login, list your devices with pixlet devices, then run pixlet push with the device ID and the rendered WebP file. Adding an installation ID with the --installation-id flag makes the applet display continuously as part of the rotation instead of showing once.

Does a pushed Pixlet applet keep updating itself?

No. pixlet render executes your Starlark code and generates a WebP image, and pixlet push deploys that image to the device, so you have to repeat the process to keep the app updated. Alternatively you can create a Community App that runs on Tidbyt's servers and updates automatically.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. tidbyt/pixlet on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tidbyt-pixlet.svg)](https://hysenlabs.com/projects/tidbyt-pixlet)

Was this useful?