The Year of the Picotron Desktop
1 year ago, on March 14, 2024, Picotron released! I had a lot of fun messing around with everything in the days after its release. On the 20th, I wrote up a blog post about some of the programs I made in it: a DVD screensaver, a bunch of cli utilities, a wordle clone, a very basic and janky Mastodon client, and a pipes screensaver. I’ve also posted on this blog about my pretty_printh
function to print with ANSI codes.
This blog post will be a showcase of a bunch of the software I’ve made in Picotron in the past year (including some that haven’t been fully published yet!). I’ll also talk about how the way that I personally customize and use Picotron. If you follow me on the Fediverse (or if you’ve seen my posts on the Picotron BBS), you may have seen a bunch of this stuff before.
As I started writing the blog post, I realized that I made a lot of things in Picotron this year! So I’ll try to be brief on most things. Most cartridges will be embedded here, and can be played directly from this post. (The cart image is used as a fallback on smaller screens.)
Projects and Cartridges #
Picotron Utilities #
Picotron Utilities (GitHub, BBS) is one of the very first things I started working on in Picotron.[1] A lot of it is the same from where it was a year ago, but there are also a lot of improvements. Three new utilities were added (echo, fd, and stat), and a bunch of improvements (such as colorized output on most commands).
Many of these utilities make using the Picotron terminal way nicer. touch
provides an easy way to create files from the terminal, grep
makes it possible to do a project wide search, fd
makes it easy to search for a file name, and tree
lets you get an see an overview of a folder.

Fuzzy Finder #
Fuzzy Finder (GitHub, BBS) is a fuzzy finder utility I made, ala fzf. It lets you do a fuzzy search for files, and quickly open them.
Picotron Remote Terminal #
Picotron Remote Terminal (GitHub, BBS is one of my first attempts to control Picotron remotely from the host to make external editing easier. There is (at least, as far as I’m aware) no way to watch for an external change to a file or to get a message from the outside without polling. So that’s what it does. It polls a web server for commands, and executes them when they’re received.
Before landing on a webserver, I tried using a named pipe (doesn’t work, locks up Picotron). You could also get it working with polling a instead, but being a web server brings one cool benefit: you can run host commands from inside Picotron! It’s a neat trick to access git from inside Picotron
I might try reworking this when TCP / websockets support is added.
Picotron Definitions #
Picotron Definitions is a set of LuaLS definition files I’ve written to make it possible to use a language server with Picotron projects.
8Ball and Snowglobe #
Magic 8 Ball (BBS) is a simple little demo I made to mess around detecting when the window moves. It was also kinda inspired by Clairvoyant by Cassidy James Blaede. I thought it would be a fun application to make, and it would cool if you could shake the window to get the answer!
Snowglobe (GitHub, BBS) is similar. It uses the same window shaking trick as 8ball, but this time shaking causes snow to fall!
PUSH #
PUSH (Picotron Upgraded SHell) (GitHub, BBS) is one of my favorite things I’ve made in Picotron.
Over the past year, I ended up switching my shell from Bash to Fish. Fish has a lot of really useful shortcuts (basically everything under Shared Bindings), and I wanted to include some of them in Picotron. (Like pressing Alt+L
to list the directory under the cursor, or cd history) But with some of the changes I wanted to make, there’s no way easily patch the terminal with something like sedish. So, I modified terminal.lua to include a modloader, and used that to make the changes I wanted. I have a bunch of examples in the readme for things PUSH can do (and by “examples”, I just mean my setup. I use all of them lol).
Pico 1K Jam 2024 #
Balloon Run (Itch, BBS) is a fun little game that I made for Pico 1K Jam 2024. Pico 1K Jam is a game jam where you have to make a game in Pico-8 or Picotron in 1KiB (1024 bytes) or less. I made a Balloon Fight-ish game, and fit it in 1021 bytes.
Advent of Code 2024 #
2024 was my second year participating in Advent of Code. I decided to do it in Picotron (the year before, I did it in TypeScript and a little C++).
I chose to do it in Picotron because the year before I saw some cool looking visualizations in Pico8, and I wanted to try making a solution with a visualization. I never published it as a cart, but it should be runnable from source, if you’d like to run my solutions.

Trash Manager #
Trash Manager (GitHub, BBS) is a program that implements trash in Picotron, loosely following the XDG Trash Spec.
When sent to trash, it moves the files to the trash directory (/appdata/trash/files
) and drops an info file in the info directory (/appdata/trash/info
). The info file contains the original path of the file and deletion date, allowing the file to be restored. Filenav.p64 includes a basic trash implementation where deleted files are moved to /ram/compost/
, but because this is in RAM, it gets wiped when you close Picotron.
Trash Manager can be used in a bunch of different ways: a CLI app, a GUI app, a tooltray indicator, and even integrated directly in Filenav.p64 using a sedish script.
extload
and extrunner
#
extload
and extrunner
(BBS) is the solution I ended up landing on for working with an external editor.
According to the docs, one of the recommended ways of using an external editor is to simply include
the files from an external folder. However, this requires you to make changes to your code, and remove all the external include
s before publishing.
extload
is a modified version of load.lua
that loads an external folder by saving the path of the folder you want to load, and loading the extrunner
cart instead. extrunner
is a dummy cart that cd
s into the external folder, and includes the code. /system/lib/resources.lua
is the file that loads the graphics and audio from the cart, so including it again will load it from the external folder, and including main.lua
will include all of the code.
This is a really simple and convenient method. Nothing special needs to be set up on the host. The only requirement is that the cart is extracted!
Bouncy Ball #
Bouncy Ball (BBS) is a fun little desktop toy. It spawns a bouncy ball that you can throw around on your desktop!
You can move a window automatically with window({ x=x, y=y })
. I have a basic physics simulation keeping track of the position of the window and automatically moving it. Throwing it is handled by calculating the delta of the mouse in the move
event. (You can’t use mouse()
for this, as coordinates are given relative to the window position! The move
event gives absolute position.) Window collision is done by reading /ram/shared/windows.pod
, which contains the currently opened window positions.
Originally, my plan for this was to be a toy you could put on your tooltray. While you can put this on the tooltray, it doesn’t work very well. It will drop behind the shade and you won’t be able to see it! So, I decided to rework it for the desktop and added window collision.
Fun fact: the collision here is largely the same as in Balloon Run! For size reasons, Balloon Run only checks collision for half the character. If you stand on the left edge of a platform, you’ll fall through! This was also a problem in Bouncy Ball, so I ended up fixing it here.
There was also a bug where if you got clipped into the ground the player would vibrate. This is because of how bouncing is implemented. When you hit a wall, floor, or ceiling, your speed in that direction will be inverted. However, if you are clipped into an object, you are constantly having ceiling collisions, meaning your vertical speed is being continually inverted causing the player to vibrate. I fixed this in Bouncy Ball by changing it so that ceiling collisions take the absolute value of your vertical speed[2] instead of inverting it.
Calendar and Clock Widgets #
The calendar widget (BBS) and clock widget (BBS) are two little widgets I made to fill out my tooltray. I like analog clocks, so I wanted to replace the clock widget with an analog version. (Also, I like 12 hour time, and the default clock widget was 24 hour!)

Tooltray Widget Credits
Libraries and Cool Tricks #
Startup Folder #
Something that a bunch of programs do to make configuration easier is splitting a config file into different files. Often, this is done with a config folder (such as something like ~/.bashrc.d/
or ~/.config/fish/conf.d/
).
I have the startup script (/appdata/system/startup.lua
) set up to load files from a folder (/appdata/system/startup/
), so that my startup files are easier to manage.
startup_folder = "/appdata/system/startup"
if fstat(startup_folder) == "folder" then
for file in all(ls(startup_folder)) do
filename = startup_folder .. "/" .. file
if fstat(filename) == "file" and file:find("%.lua$") then
create_process(filename)
end
end
end
Before drag and drop tooltray installation was added in 0.1.1e, I had different scripts for each tooltray widget. Now, I have 4 main startup files:
- One to setup PUSH
- One to run some sedish scripts (like setting up trash support in Filenav.p64)
- One to automatically clear trash after 30 days
- One to launch the new utility (so that I always have a blank cart loaded when I startup Picotron)
Easy to Access Logs #
Using printh()
, you can print to stdout. This can be very useful for making logs or debugging programs (especially in situations where you can’t/it doesn’t make sense to print debug info onscreen).
However, there’s typically no way to access this unless you launch Picotron from the terminal (which I often forget to do). I have a picotron-logging
script that saves the output to a temp file (/tmp/picotron.log
), so that the log is always accessible.
#!/usr/bin/env bash
picotron > /tmp/picotron.log 2>&1
Then, to view the log, I do tail -f /tmp/picotron.log
, which will print the log and automatically print new changes!
INI Parser #
INI Parser (BBS) is a function to load INI(-ish) files into a lua object. The idea is that you can add comments to an INI file, unlike a POD or JSON, which may make them better for config files.
Inline Image Editor #
Inline Image Editor (BBS) is a tool to create one-off characters. I know there are a few of these made for Pico-8 (which supports the same format for one-off characters), but I hadn’t seen one for Picotron, so I made one.
Work in Progress #
Archive Utility #
Archive Utility (GitHub) is a tool that can extract .tar
, .gz
, and .tar.gz
files. It uses LibDeflate to decompress the gz archives.[3] This library works out of the box in Picotron (but you have to provide your own sorting function, as table.sort
is not in Picotron). I’m also using this CRC32 utility to verify the gz checksum.
Technically, everything is working. DecompressGZ()
can read and decompress a gz file (also supports multiple concatenated gz files!). ExtractTar()
can read and extract the files from a tar archive. The default behavior of the cart right now is to extract a .tar
or .tar.gz
into a folder.
You can even download and extract archives from the internet (such as from GitHub!)
Honestly, I’m not sure how far I want to go with this. I probably want to make a GUI mode that lets you preview an archive without writing its files, but IDK if it would make sense to create an archive from inside Picotron.[4]
Cointris #
I’m working on a Coin Conveyor (from Super Mario Party Jamboree) clone, working title “Cointris”. I have the conveyor belt, the playfield, and completing lines working. Completing a line of coins will destroy them, and destroying a bomb will destroy the 3x3 area around the bomb.
I think it’s pretty close to a playable version: just needs scoring and some polish (such as an animation/particle effect when the coins break; It’s pretty jarring for them to just disappear).
Pac-Man Thing #
I don’t really know where I’m going with this one. I started with making something Pac-Man-ish. But I wanted to see if there was a way to have the sprite rotate without needing different sprites for all 4 directions. I ended up finding this sprite rotation library, and I started playing around with it, making this little demo where Pac-Man rotates and can be launched in the direction he’s facing.
After playing around with it for a bit, I liked the way I had it set up to bounce off the walls, and decided to make the Bouncy Ball cart.
But this demo seems like it might serve as a nice base for a pool or maybe golf game.
LulPeg #
LPeg is a lua library based on Parsing Expression Grammars. It can be used to create more involved parsers.
LulPeg is a port of LPeg written in pure lua. With a little effort, I was able to get it working in Picotron! Though, if I’m being honest, I don’t really have anything to use it for. I mainly wanted to see if it was possible (and it is!).
Weather #
When I was making the clock and calendar widgets, I kinda wanted to make a weather widget to go along with them. I found Open-Meteo, which seems to provide a nice weather API, but there’s a bug in Picotron where fetching long URLs causes Picotron to crash. So, I’m not going to bother with this until that’s fixed.
The initial commit was on March 15, 2024! ↩︎
Remember, in Picotron positive Y is down! ↩︎
Technically, DEFLATE is the same compression algorithm used in zip files, so it could also support zip files. ↩︎
When you write a file in Picotron, it includes a metadata comment in the first line. This doesn’t really matter, but it might cause problems if you want to read the file from an outside program. ↩︎