Devlog
- I spent some time last weekend playing with Htmgo by making a simple world clock that would update every second. I ended up remaking this as a static web page backed by some WASM code. Knowing the time in UTC and some American cities could come in handy for my job. At least, thatās the theory: I havenāt had a need for it yet.
- I also made some changes to Nano Journal to add support for uploading multiple attachments at once.
- Nano Journal now keeps the current draft post in browser local storage, so that itāll no longer get clobbered when youāre redirected to the login screen when trying to post an entry. This was a source of anxiety for me and meant I was less likely to write something off the cuff, so Iām glad this is now fixed.
- Blogging Tool now has a new app which takes a clip videos produced by Pocketcasts ā which is currently generated in an Instagram-style vertical video ā and crops it as either a square or a letterbox.
- The `seq` function, used for generating a sequence of integers. I like how I built this: itās effectively a virtual list ā that can be indexed, iterated over, or calculated the length of ā but does not take up linear space.
- Comparator functions, like `eq`, `ne`, `gt`, etc. plus settling on a type system much like Python, where values are strongly type (canāt compare ints to strings) but are also dynamic.
- Arithmetic functions, like `add`, `sub`, etc. which operate on integers, and the `cat` function use to concatenate strings (these functions do try to cohere values to the correct type)
- Logical functions, like `and`, `or`, and `not`.
In other building-small-things-for-myself news, I spent a bit of time this morning on the image processor for Blogging Tools. The big new change was adding support for working with multiple source images, instead of just one. This made way for a new āPhone Shotā processor, which arranges multiple screenshots of phone apps in a row, while also downscaling them and proving some quick crops and distribution options.
This should reduce the vertical size of mobile app screenshots I post here, something thatās been bothering me a little.
Some more work on that feed reader app. You know how I said that I wanted to hold off looking at appearances? Well, I abandoned that approach when I installed the app on my phone and tried viewing a few articles. And oof! Thereās work to be done there.
First, itās slow. Very slow. Itās taking a good second or two to pull feeds and entries from Feedbin. I was expecting this, and Iāve got a few plans on how to speed this up. But the biggest concern is the janky list scrolling. I mean, I wasnāt expecting the buttery smoothness of iPhone list scrolling, but I expected Flutter to be better than what I was experiencing. Iām hoping that itās just because I was running a debug build, but part of me fears that Flutter is just not optimised for smooth list scrolling, favouring ease of development and a common runtime. I rather not change frameworks now, especially after spending an evening dealing with all the build issues, but I donāt want to live with this for ever.
But speed is not the biggest issue. The biggest offender was the feed reader view. The embedded web-view was only lightly styled, and it felt like it. The margins were all off, and I didnāt like the default font or colours. It made reading the article a bad experience to a surprising degree. Iāve dealt with rushed or poorly designed UIs in the past, but I didnāt have much tolerance for this. Not sure why this is, but I suspect itās because Iāve been using feed readers that put some effort into the design of their reader screen.
In any case, a couple of evenings ago, I decided to put some effort into the styling. I replace the body text font with Noto Sans and the fixed-font with Ubuntu Mono. I dropped the font-size a little to 1.05 em (it was previously 1.1 em, with felt a little big, and 1.0 em felt a little small). I bought the margins in a little. And I styled the block-quote, figure, and pre elements to an appearance that, despite being a little overused, felt quite modern.
The results look much better, at least to my eye (and my emulator). Here are some side-to-side comparison shots of the changes (left side is the unstyled version, while the right side has the new styling changes):



I still need to actually install this on my phone and try it out. Iām wondering whether I should do so after a bit more work syncing the read status with Feedbin. Thatās a feature thatās keeping me on Feedbinās PWA for now.
Spent the last few evenings continuing work on a Flutter-based RSS feed reader. This project is now further along then my previous attempts at doing this. Iām at the point where feeds and feeds items are being fetch from Feedbin and displayed in a list view:


The aesthetics are taking a bit of a back seat in favour of functionality for now; I havenāt even changed the default accent colour. But the infrastructure is there: tapping a feed will bring up the entries for that feed. This is using named routes for navigation, and cubits for state management. Itās a bit more work upfront, but it does make for a neater codebase.
The biggest challenge so far was getting the actual reader view working. I hoping to use the webview plugin, but when I tried adding it, I ran into a bunch of Gradle errors. These were either class version errors or dependency errors, depending on what I tried to fix it (I didnāt get screenshots, sorry). I eventually stumbled upon this Flutter Gradle plugin migration guide, and following this, along with upgrading Java to OpenJDK 25, got Gradle working again.
But I was still getting build errors. The first couple were Gradle plugins com.android.application
and org.jetbrains.kotlin.android
that needed to be updated. Easy stuff. And then I got this error message:
Execution failed for task ':webview_flutter_android:compileDebugJavaWithJavac'.
> Could not resolve all files for configuration ':webview_flutter_android:androidJdkImage'.
> Failed to transform core-for-system-modules.jar to match attributes {artifactType=_internal_android_jdk_image, org.gradle.libraryelements=jar, org.gradle.usage=java-runtime}.
> Execution failed for JdkImageTransform: /Users/leonmika/Library/Android/sdk/platforms/android-34/core-for-system-modules.jar.
> Error while executing process /Users/leonmika/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/jlink with arguments {--module-path /Users/leonmika/.gradle/caches/8.10.2/transforms/575ccd1a7426c0be21d9fe3a81898be3-05a021da-a1a7-409f-a30a-bba769b57371/transformed/output/temp/jmod --add-modules java.base --output /Users/leonmika/.gradle/caches/8.10.2/transforms/575ccd1a7426c0be21d9fe3a81898be3-05a021da-a1a7-409f-a30a-bba769b57371/transformed/output/jdkImage --disable-plugin system-modules}
Running a web search on the error revealed this Stack Overflow answer, which resolve it. There were still a few complaints about the the NDK version but after all that, the app finally launched with the web-viewer.

I still need to actually render the entry, plus style the HTML a bit. The immediate goal after this, once the reader view, is getting this on my phone to start playing with it. Itās just barebones for now, but I find that the sooner I can start using a project myself, the more likely I am to keep at it.
Looking for my next project to work on. I have a few ideas but my mind keeps wandering back to an RSS reader for Android. I read RSS feeds quite frequently on my phone and Feedbinās web app is great, but I think I prefer a native app.
I just need to get over the hump of setting up my Android Studios. Thereās something about starting a new project there that just sucks the life out of you.
Playing around with some possible UI design choices for that Android RSS Feed Reader. I think I will go with Flutter for this, seeing that I generally like the framework and it has decent (although not perfect) support for native Material styling.
Started looking at the feed item view. This is what I have so far:

Note that this is little more than a static list view. The items comes from nowhere and tapping an item doesnāt actually do anything yet. I wanted to get the appearance right first, as how it feels is downstream from how it works.
The current plan is to show most of the body for items without titles, similar to what other social media apps would show. It occurred to me that in doing so, people wouldnāt see links or formatting in the original post, since theyāll be less likely to click through. So it might be necessary to bring this formatting to the front. Not all possible formatting, mind you: probably just strong, emphasis, and links. Everything else should result with an ellipsis, encouraging the user to open the actual item.
Anyway, still playing at the moment.
Itās done! Cyber Burger, the Pico-8 arcade game Iāve been working on for the last few months, is finished and can now be played online in a (desktop) browser. Check it out here.

I also decided to put the documentation āon-boardā, as opposed to putting it on the web. Yes, it breaks from what was typical during the 8-bit gaming period, but Iāve got the space, and it makes adding illustrations easier.

Also forces me to keep it brief, which is no bad thing.
Building out the meta elements of Cyber Burger, including the āmenu du jourā a.k.a. the main menu. Iāve used food-service terms for the menu items to maintain the theme, but there is a button to switch them over to more conventional names should it be too unclear.

Weekly Update - 3 Nov 2024
I probably should stop calling these āweekly updates,ā seeing that they come up a lot less frequently than once a week. Maybe I should switch to something like āSunday updates,ā or maybe something closer to what this is, which is an excuse to procrastinate by writing about what Iāve been working on, rather than just working on it.
But Iām sure youāre not interested in my willowing about the frequency of these updates, so letās just get straight to the meat of it.
Cyber Burger
All the logic, graphics, and sound-effects for power-up/power-downs are now finished. They now spawn in randomly, with a frequency and specific types dictated by the current stage. I also added the notion of a āmilkshake bonusā which awards the player a bonus multiplier for a short amount of time.
Iāve also made a few balancing changes around demerits. Based on my own testing, I was pretty blasĆ© about loosing demerits, as you could recover a demerit every time you finish a burger. I wanted to discourage that, so I changed things around a little. You still loose demerits if you screw up the burger your trying to build ā such as making it too high or not catching the correct item ā but you no longer recover demerits for every burger you complete. Instead, you recover one demerit for every $50 youāre awarded. This is now every three to four burgers, depending on how sophisticated they are, which I hope would make loosing demerits something the player would want to avoid.
Thereās still the difficulty curve stuff left to do, but I think Iāll start working on the meta elements, like the title screen, main menu and high score tables. I can probably leave out the addition of stages and a difficulty curve if Iām honest, but I would like to have a decent title and menu screen.
The other thing to do is write the manual. I made a start the other day, but thereās much left to do on this front. Part of me wonders whether it make sense adding āon-board documentation.ā But part of the fun of using Pico-8 on this project is to imagine a time where this game came out during the late 70ās and early 80ās and the 8-bit era of home consoles. And those games didnāt have on-board documentation. That said, I might add a quick start guide for those that didnāt RTFM.
UCL
Iāve been using that tool Iāve written for work quite often so there was a need to add some additional features to UCL. The biggest one was adding exceptions, but thereāve been a lot of little things like rounding out the standard library.
All the code written in a rush is starting to weigh this project down though, and I do think Iāll need to do some refactoring to tidy things up a little. I may need to work on documentation too, just for my own sake more than anything else. I doubt this would be anything more than the toy language it currently is, but it does have itās uses, and whenever I need to reference a built-in, Iām always going to the source code. Which is fine, but I think I can do better on this front.
Other Projects
A few other things I worked on during the last fortnight:
So thatās the update for this past fortnight.
Title design this morning. Trying to get as close as I can to the Cyberspace Raceway font as my pixel art skills will allow for.

Try-Catch In UCL - Some Notes
Stared working on a try
command to UCL, which can be used to trap
errors that occur within a block. This is very much inspired by
try-blocks in Java and Python, where the main block will run, and if any
error occurs, it will fall through to the catch block:
try {
echo "Something bad can happen here"
} catch {
echo "It's all right. I'll run next"
}
This is all Iāve got working at the moment, but I want to quickly write some notes on how Iād like this to work, lest I forget it later.
First, much like everything in UCL, these blocks should return a value. So it should be possible to do something like this:
set myResults (try {
result-of-something-that-can-fail
} catch {
"My default"
})
--> (result of the thing)
This is kind of like using or
in Lua to fallback to a default, just
that if the result fails with an error, the default value can be
returned from the catch
block. In might even be possible to simply
this further, and have catch
just return a value in cases where an
actual block of code is unnecessary:
set myResults (try { result-of-something-that-can-fail } catch "My default")
One other thing to consider is how to represent the error. Errors are
just treated out-of-band at the moment, and are represented as regular
Go error
types. It might be necessary to add a new error
type to
UCL, so that it can be passed through to the catch
block for logging
or switching:
try {
do-something
} catch { |e|
echo (cat "The error is " $e)
}
This could also be used as the return value if there is no catch
block:
set myResult (try { error "my error" })
--> error: my error
Another idea I have is successive catch blocks, that would cascade one after the other if the one before it fails:
try {
do-something
} catch {
this-may-fail-also
} catch {
echo "Always passes"
}
Unlike JavaScript or Python, I donāt think the idea of having catch
blocks switching based on the error type would be suitable here. UCL is
dynamic in nature, and having this static type checking feels a little
wrong here. The catch
blocks will only act as isolated blocks of
execution, where an error would be caught and handled.
Finally, thereās finally
, which would run regardless of which try or
catch block was executed. I think, unlike the other two blocks, that the
return value of a finally
block will always be swallowed. I think this
will work as the finally block should mainly be used for clean-up, and
itās the result of the try
or catch
blocks that are more important.
set res (try {
"try"
} catch {
"catch"
} finally {
"finally"
})
--> "try"
Anyway, this is the idea I have right now.
Update ā I just realised that the idea of the last successful try block return an error, rather than letting it climb up the stack defeats the purpose of exceptions. So having something like the following:
try { error "this will fail" }
Should just unroll the stack and not return an error value. Although if there is a need to have an error value returned, then the following should work:
try { error "this will fail" } catch { |err| $err }
--> error: this will fail
Weekly Update - 20 Oct 2024
Yeah, I know, itās been a while⦠again. A lot has been happening in life and thereāve been many days that I havenāt done any work on anything. Things are starting to settle down now, although I am expecting a few more bumpy days ahead, so weāll see how we go with project work.
Cyber Burger
Yeah, Iām getting pretty tired of this one. Iām right in the trough of despair here, where the initial excitement has worn off and I just want to finish it. All the remaining work for it has been defined, which I think helps, and now itās just a matter of plowing through the tasks.
Recent work done on this is the addition of power-ups and power-downs, which does things like bump the remain time remaining, give the player a ātractor beamā weapon, and clearing the play-area of items, amongst other things. Iām about 2/3 through this one: most of the these power-ups have been implemented, including the tractor beam. After that, the remaining work on this project is adjusting the difficulty curve, improving the main menu, and finally finishing off the website.
Despite how fatigued I feel about this, it has been fun learning how to build for the Pico-8. The expect fidelity of the pixel art is within my skillset, and itās quite impressive what it offers in terms of audio effects. I havenāt explored the music options, and I probably wonāt for this game, but something to look at for the next one (if there will be a next one).
Coasters
This was a bit of a side tangent to get my mind off working on Cyber Burger. It was a long weekend, and I was passively scrolling through the sample of Vintage Logos when I thought about recreating a game that was published in the weekend newspaper we read while I was growing up. Youāll be presented with two images and a clue, and youād have to guess the word or phrase these alluded to. For example, if the clue was āinsectā and the images were:

Then one possible answer would be ābutterflyā.
The newspaper used stock photos, like the example above, but I was hoping to creates logos for fake companies as they would appear as if printed on cardboard coasters youād find in pubs. The idea is that a new puzzle would be shown to the user a day, much like the word games you find online.
I coded up most of this in a single day and had a working version by the end of the weekend. I had a very simple Go server which served up a new puzzle every day at 00:00 UTC. The web frontend was mainly HTML, with some JavaScript for handling the playerās guesses. The puzzles themselves were defined in a CSV file which was imported into a Sqlite DB on server startup. This was a strange way of doing things, and was more of an accident as I was deploying this as a Docker container and I didnāt setup a persistent volume that survived restarts. I had plans of adding an admin section to the Go server so that I could design puzzles in advanced.
Fortunately I resisted this as I ended up only producing twelve puzzles. Once the original run was completed, I basically bundled them all on a static site. I was able to keep most of the original HTML and JavaScript as it was, with only the Go backend being junked. Itās still online, and maybe Iāll come back to it in the future, maybe using stock images in place of logos I have to create myself.


So although this was not a long lived side tangent, it was good to be able to get something finished. I was feeling quite dispirited with projects that I was just not finishing or releasing. Doing something small like this, and seeing it through, helped a lot. Maybe thatās the secret in how I can see through something from conception to completion: get the bulk of it done quickly, deploy it as soon as you can, and keep it small. That would limit the types of project I can deliver, but hey, at least I would deliver them.
Other Stuff
I added a few things to Ted, my terminal CSV editor, this past week. Like many of the other features of this project, this was driven mainly by needs that arise at work. I finally bit the bullet and embraced the support for headers. The first row of the CSV file is now treated as a header and is now fixed above the column, instead of the column numbers which were much less helpful. It should, in theory, be possible to read a CSV file without headers, but I hardly deal with those files that itās probably just better to make headers the default.

I am also exploring ways to do more actions in bulk, such as add columns which are derived from the value of other columns. These are all quite experimental at the moment, and are more or less added in a quick and dirty fashion; just the bare minimum for what Iām trying to achieve. So not much to say here. A few other changes to other projects:


So, a lot of little things done this past month. Nothing worthy of a report on itās own, but still, itās something.
Iāve spent the last week working on a small puzzle game called Coasters, where you presented with two images and a clue, and you need to guess the word or phrase. One puzzle a day, sort of like Wordle. Iāve got 10 puzzles ready to go and I may add more but no promises. Check it out if you like.

Weekly Update - 22 Sept 2024
No preface today. Letās move on to the update.
Cyber Burger
Cyber Burger now has sound!
I started added some basic sound effects to the laser and the items flying across the screen. They may change, depending on how I find them after a while, but itās a start. I do like how Pico-8 makes these easy to make: select a waveform, then just draw out the pitch and volume graphically:

I also improved how items are spawned. Instead of the item types being completely random, theyāre now taken from a list, which gets refilled and shuffled once itās empty. This smoothes out the chance of seeing a particular item ā no more waiting around for a bun bottoms to start your burger ā while still making things random enough to be fun. The item types are distributed evenly, so every type will show up once per cycle. Maybe Iāll change this, but probably not, as it seems to be working reasonably well at the moment.
The Y location is now quantised a little so that items donāt completely overlap each other by a pixel or two. They can still be located on exactly the same Y position which⦠is not great ā I may need to take a look at that. But the slice spacing between each item looks good. Also, items now spawn in from the left as well as the right.
Lastly, I changed how demerits work. The previous version was not adding any when the player made a mistake. This made them pretty useless, and the game felt quite easy. So now, whenever the player catches an item in the basket that they werenāt suppose to, they get a demerit. If their burger gets too large, then get 2 demerits. To balance things out, the player now has 6 demerit points instead of 3, and every completed burger would remove one demerit until the player has zero again. I think this will require some more rebalancing, but it makes play a little more interesting.
Not sure what Iāll work on next. Iāll need to finish (or redo) the sounds, and then come up with some more tasks to do. Iām thinking either working on the difficulty curve, making things harder as the game progresses; adding power-ups and power-downs; or working on the start screen and menu. More on either of these in the future.
Blogging Tool
For my āextracurricularā activity this week, I spend some more time on Blogging Tool. I added the notion of jobs, which are essentially background tasks for long running processes. These can be monitored from within the Jobs section, which is accessible from the main nav:


Iām recording jobs in the Sqlite3 database, including the ones that are currently running. Jobs have the ability to report progress by updating the āsummaryā message, which would update the job record in the database. Iām generally not too keen on having the database act as storage for something that could be updated quite frequently, but the alternative was keeping this progress information in memory or deploying something like Redis, both I felt were worse. Besides, Iām curious as to how well Sqlite3 handles status updates from a running job like this. Iām not expecting jobs to be updating there status too rapidly anyway, so it should be fine.

The Image App got a few changes as well. Itās now possible to import an image from a URL (this is done within the browser so is subject to all the cross-origin rules that entails). I added this just so that I can touch up my own images that I already uploaded to Micro.blog, without having to download the image first. Speaking of, thereās now an option to send a processed image to a blog directly from the app, saving yet another download step. Iāve got this configured to Micro.blog but it uses Micropub to do this so it could, in theory, be any blogging system that supports that API.


The last thing that was added is the ability to upload a Zip file of images to a Micropub endpoint, and start creating a gallery. This has been a feature that I wanted for a while. It always took me ages to prepare a photo gallery in Micro.blog. I know there are apps which help here, but theyāre for iOS and just donāt fit my workflow. Now, whenever I want to add a photo gallery, I can select the images from Google photos, download them as a Zip file, then directly upload them to Micro.blog in one hit. The upload can take as long as it needs to (this uses the new jobs system as well), and once theyāre done, Blogging Tool will create a gallery for me so I can write the captions. To be able to do this without clicking around as much as I did is rather exciting.

Or at least it will be, when I find out how I can get large uploads working. Uploading a 27 MB Zip file in development was not an issue, but when I deployed it to my Dokku server and try it for real, I kept getting 502 errors. Iām not sure whatās causing these yet: both Nginx and Blogging Tool have been configured to accept files much larger than this, and there are no logs in either to suggest a problem. There might be a timeout somewhere that needs to be raised. In any case, hopefully this is the last hurdle I need to clear to get this working. Anyway, thatās all for this week. Oh, actually, one more thing: while working on the UI for the Upload Zip screen, I found that I never got around to changing the instructions on the Transcode Audio screen after copying and pasting the HTML from the New Gallery screen:

Just goes to show how little I pay attention to this copy, even while working on my own apps. š
Weekly Update - 15 Sept 2024
Two projects to discuss this week.
Cyber Burger
Iāve decided to ditch game mode A, where the player is given a series of stages they need to clear. Instead, Iām changing this to be closer to an old-school arcade experience. In this mode, you start the game with a 45 second timer, and you need get as high a score as you can before the timer runs out. Your score depends roughly on how large and āinterestingā your burger is. Every burger you make also adds 10 seconds to the clock, so the ultimate aim is to balance making interesting burgers for a higher score, vs. trying to avoid letting the clock run down to zero. Or at least thatās the idea. I need to do some rebalancing, as I think the game is a little easy.
I am wondering whether to award points based on how fast you make the burger. It was originally my intention, but Iām now wondering if that would be considered unfair, as you donāt get to choose the items flying across the screen. I still do need to fix the random number generator too, so as to avoid keeping the player from waiting around too long for a bun base to start building their burger. Resolving these two things will be my goal for the next week.
This working version has been pushed to the web for anyone to try out. If you do, please let me know if you have any feedback.
Nano Journal
The next project I spent some time on was Nano Journal, the web-based
journalling app stolen from inspired by Kev Quirkās
journalling app.
I wasnāt intending to work on it this week, but I did have a motive to do so as I was expecting to do something that I wanted to document (I ended up not doing that thing).
The biggest changes I made were adding paging and post titles, plus making some improvements on the backend on how posts are stored and retrieved.

Setting the title is done using a slash-commands:
/title This is my post title
This is my post body
I also added an /append
slash-command to add to the latest post,
rather than create a new one. This also works for attachments too,
allowing a somewhat clunky way of adding multiple attachments to a
single post.

I am still considering this a prototype, but I have found myself writing here more often than Day One. I definitely need to start thinking about the long-term storage of posts if I want to āproductioniseā this. Ultimately I want to get them saved in a private Git repository. Each post is just a markdown file stored on the file-system, which will make this easy to do, but Iām somewhat procrastinating on relearning how to use the various Go Git clients that are available.
One other thing that Iād like to do is improve instances where a post couldnāt be saved due to network issues. The way Iām thinking of doing this is to store the current draft in browser local storage, at least until itās saved on the server. Iām also wondering if itās worth adding the concept of draft posts. Not sure at this stage whether that juice is worth the squeeze, at least not yet. This was meant to be a relatively simple side-track. But I guess thatās the danger (beauty?) of starting something and finding it useful. š¤·
Anyway, thatās all for this week.
Project Updates
Well, itās been three weeks since my last post here, and as hard as it was to write this update, not writing it wouldāve been harder. So letās just skip the preamble and go straight to the update.
Cyber Burger (That Pico-8 Game)
Iām terrible at being coy, Iāll just spill the beens. That game Iāve been working on is call Cyber Burger. Itās based on a DOS game I saw on YouTube, and it seemed like a fun project to try and work on, with some tweaks to the gameplay that I think would make it more forgiving.
In the weeks since my last update, I finished with the prototypes and started working on the game itself. The initial set of art is done and a very simple āGame Aā mode has been implemented. In this mode, you are shown a burger youāll need to make in your basket. You do so by shooting down the items flying across the screen and catching them in order. When you do, you get a ātipā, which basically amounts to points. If you make a mistake, youāre given a demerit. There are five rounds in total, and once the round is complete, you move on to the next one, with maybe slightly different items, or different item speeds, etc.

I managed to make a HTML version of this which plays through round 1. I gave it to someone at work to play test and the results were⦠well, they werenāt bad but it didnāt set the world on fire.
I think Iām okay with that, but I do need to keep working on it. I think one thing that would help is adding sound. And I think it might help me deliver this earlier if I abandoned Mode A and start working on Mode B, which is closer to an arcade style of game that would allow for continuous play. These two things, Iāll aim to work on this next week.
Oh, and Iāll need to fix the item spawner. Waiting ages for an item you need is no good.
If youāre interested in giving it a try, you can do so by following this link (it runs in the browser). Feel free to send any feedback you may have.
UCL
The other thing Iāve been spending some time on over the last week or
so was UCL. Iāve been using that work tool which has this language
quite often recently and Iāve been running against a number of bugs and
areas where quality of life changes could be made. Just small things,
such as allowing the foreach
command to be called with a proc name
instead of requiring a block, much like the map
function. Those have
been addressed.
But the biggest thing Iāve been worked on was building out the core library. I added the following functions:
Along with this, Iāve started working through the strings package, which would add the various string functions you see, like trimming whitespace, splitting, joining, etc. Iāve got trimming and converting to upper and lower case, and my goal for next week is to add splitting to and joining from string lists. Once thatās done Iāll probably put this on the back-burner again so I can finish off Cyber Burger or work on something else.
Just a reminder that thereās also a playground for this too, although I apologise for the lack of documentation. Iāll need to get onto that as well.
I enjoyed reading Kev Quirkās post about building a simple journal. Iām still using Day One, but I am still thinking of moving off it. So I was inspired to build a prototype similar to Kevās, just to see if something similar works for me. Built using Go instead of PHP, but it also uses Simple CSS.

Project Seed - A Pico-8 Prototype
Oof, another long stretch between updates. This has not been a productive winter.
Much of the project Iāve been writing about here are, shall we say, āon iceā. UCL is still being used for the project itās been built for, but thereās been no further work done on it recently. I think we can safely say Photo Bucket is dead, at least for now. Blogging Tool and that interactive fiction project is still ongoing, but both are running on a slow burn. I was hoping to get the fiction thing done by the end of winter, but itās likely that timeline will slip. Maybe some time in spring.
What have I been doing in the meantime? Watching YouTube videos on old DOS games, actually. Hardly an activity worth writing about here. But it did get me wanting to try working on a game again. And I did get an idea for one while watching videos of someone going through a collection of shovelware titles.
This project is designated the codename āProject Seedā. Iām going to be a little cagey about the details, at least for now. But I will say that Iām planning to use Pico-8 for this. I bought a license for Pico-8 about 2 years ago (oof, did not expect it to have been that long ago) and I watched a few videos on how to use it, but I didnāt have a good idea for a project then. It is a fascinating bit of software, and I know itās quite popular amongst hobbyists. One thing I like about it is that the games made with it are not expected to have great art. As someone who canāt draw to save himself, this works in my favour. So donāt expect anything resembling Celeste from me! š Pico-8 also targets HTML5, which works for me.
Anyway, I have this idea, and I thought about starting a prototype to see how it feels. I downloaded Pico-8, spun up a new project, and started drawing some of the graphics. Iāve got the bare minimum so far: a user-controlled paddle, called the ābasketā; a laser bullet, and a thing that needs to be shot.

Next was coding up the Lua code. Using the Pico-8 builtin editor was fine for a bit, but I eventually switch to Nova just for the screen size. I am still trying to adhere to the whole retro-style approach to Pico-8. The code I write is still bound to the 8192 token limit, and Iām trying to avoid using too much virtual memory, capping elements to only a handful. But, yeah, using Nova to write the logic is so much better.
Anyway, the first milestone was allowing the player to move the basket around and shoot laser bullets. Then it was to get one of the shootable items moving across the field. The idea is that the player will need to fire the laser to hit the shootable item. When itās hit, it begins to fall, and the player needs to catch it in the basket.

This took about an hour or so, and already the glimpse of the core game mechanics are starting to show through. Theyāre just ridiculously primitive at this stage. I mean, the item really shouldnāt fall through the basket like that. But given that itās a prototype, Iām okay with this so far.
Next experiment was spawning multiple items onto the field. This got off to an interesting start:

But adding a bit of randomness to the Y position and the spawn delay managed to make things a little more natural again:

One thing Iām considering is whether to add some randomness to the item X velocity, and even have items move from right to left. But this will do for now.
At this stage, items were just being added to an array, which grew without bounds, and were not being released when they left the screen. Obviously not a good use of memory (even though this is running on an M2 Mac Mini and not retro hardware from the 1980ās, but thatās hardly the point of this exercise). Furthermore, the player is only able to shoot one bullet at a time, and those bullets werenāt being released either. So I set about resolving this, trying to do so in the spirit of a Pico-8 game. Iāve setup a fixed Lua array, which will grow up to a max size, and added a simple allocator which will search for an empty slot to put the next item in.
function next_slot(tbl,n)
if \#tbl < n then
return \#tbl+1
else
for i = 1,n do
if tbl[i] == nil then
return i
end
end
end
return nil
end
This makes releasing items really easy: just set that slot to nil
. It
does mean that I canāt use ipairs
to iterate over items, though.
Instead I have to use the following construct:
for i,item in pairs(items) do
if item then
-- Do thing with item
end
end
Itās here that I wished Lua had a continue
statement.
I used this for both the item and bullets: there can now be up to 8 items and 4 bullets on the screen at a time. After making those changes, the prototype started to play a little better:

So, a good start. But there are definitely things need to be fixed. The basket needs to be wider, for one. Itās fine for the prototype, and Iām okay with it the collision being pretty lenient, but itās too narrow to make it fun.
But the biggest issue is that the collision logic sucks. Bullets are flying through the items, and items are falling through the basket. Iām using a point-in-rectangle approach to collision detection, with a few probing points for each item, but they obviously need to be adjusted.
So collision is what Iām hoping to work on next. More on this when I get around to it.
Current Project Update
Hmm, another long gap between posts. A little unexpected, but thereās an explanation for this: between setting up Forgejo and making the occasional update to Blogging Tools, I havenāt been doing any project work. Well, at least nothing involving code. What I have been doing is trying my hand at interactive fiction, using Evergreen by Big River Games.
Well, okay, itās not completely without code: there is a bit of JavaScript involved for powering the āinteractiveā logic part. But a bulk of the effort is in writing the narrative, albeit a narrative thatās probably closer to a video game rather than a work of pure fiction.
Why? The main reason is to try something new. I had the occasional fancy to try my hand at fiction, like a short story or something. I have an idea for a novel ā I mean, who doesnāt? ā but the idea of writing it as a novel seems daunting at the moment (Iāve written it as short story for NanoWriteMo. Itās sitting online as an unedited draft somewhere. I should probably make a backup of it, actually). But the idea of writing something as interactive fiction seemed intriguing. I was never into text parser adventures, but I did enjoy the choose-your-own-adventure books growing up.
So whatās the story about, I hear you saying? Well, believe it or not, itās about gardening. Yes, something I have zero experience in. And perhaps thatās what made it an interesting subject to explore.
Iāve been working on this for about a month now. Iām well past the everything-is-new-and-exciting phase, and I think I just made it through the oh-no-why-the-heck-am-I-even-doing-this pit of despair. I can see the finish line in terms of the narrative and the logic, and all that remains there should just be a matter of cleaning up, editing, and play testing. The biggest thing left to do is illustrations. I have zero artistic skills myself so Iām not quite sure what Iāll do here.
If youāre curious about it, hereās a sample. Itās about the first third of the story. Itās a little rough, and requires editing and proof-reading, and illustrations. But let me know what you think.
More Tools For Blogging Tool
Spent the last week working on Blogging Tool. I want to get as much done as a I can before motivation begins to wain, and it begins languishing like every other project Iāve worked on. Not sure I can stop that, but I think I can get the big ticket items in there so itāll be useful to me while I start work on something else.
I do have plans for some new tools for Blogging Tool: making it easier to make Lightbox Gallery was just the start. This last week I managed to get two of them done, along with some cross-functional features which should help with any other tools I make down the road.
Move To Sqlite
First, a bit of infrastructure. I moved away from Rainstorm as the data store and replaced it with Sqlite 3. Iām using a version of Sqlite 3 that doesnāt use CGO as the Docker container this app runs in doesnāt have libc. It doesnāt have as much support out there as the more popular Sqlite 3 client, but Iāve found it to work just as well.
One could argue that it wouldāve been fine sticking with Rainstorm for this. But as good as Rainstormās API is, the fact that it takes out a lock on the database file is annoying. Iām running this app using Dokku, which takes a zero-downtime approach to deployments. This basically means that the old and new app container are running at the same time. The old container doesnāt get shut down for about a minute, and because itās still holding the lock, I canāt use the new version during that time as the new container cannot access the Rainstorm database file. Fortunately, this is not an issue with Sqlite 3.
It took me a couple of evenings to port the logic over, but fortunately I did this early, while there was no production data to migrate. Iām using Sqlc for generating Go bindings from SQL statements, and a home grown library for dealing with the schema migrations. Itās not as easy to use as the Rainstorm API but itāll do. Iām finding working with raw SQL again to be quite refreshing so it may end up being better in the long run.

Imaging Processing
Once thatās done, I focused on adding those tools I wanted. The first one to sit alongside the gallery tool, is something for preparing images for publishing. This will be particularly useful for screenshots. If you look carefully, youād noticed that the screenshots on this site have a slightly different shadow than the MacOS default. Itās because I actually take a screenshot without the shadow, then use a CLI tool to add one prior to upload. I do this because the image margins MacOS includes with the shadow are pretty wide, which makes the actual screenshot part smaller than I like. Using the CLI tool is fine, but itās not always available to me. So it seemed like a natural thing to add to this blogging tool.
So I added an image processing āappā (Iām calling these tools āappsā to distinguish them from features that work across all of them) which would take an image, and allows you to apply a processor on it. You can then download the processed image and use it in whatever you need.

This is all done within the browser, using the Go code from the CLI tool compiled to WASM. The reason for this is performance. These images can be quite large, and Iād rather avoid the network round-trip. Iām betting that itāll be faster running it in the browser anyway, even if you consider the amount of time it takes to download the WASM binary (which is probably around a second or so).
One addition I did add was to allow processors to define parameters which are shown to the user as input fields. Thereās little need for this now ā itās just being used in a simple meme-text processor right now ā but itās one of those features Iād like to at least get basic support for before my interest wains. It wouldnāt be the first time I stopped short of finishing something, thinking to my self that Iād add what Iāll need later, then never going back to do so. That said, I do have some ideas of processors which could use this feature for real, which I havenāt implemented yet. More on that in the future, maybe.

Audio Transcoding And Files
The other one I added deals with audio transcoding. Iāve gotten into the habit of narrating the long form posts I write. I usually use Quicktime Player to record these, but it only exports M4A audio files and I want to publish them as MP3s.
So after recording them, I need to do a transcode. Thereās an ffmpeg
command line invocation I use to do this:
ffmpeg -i in.m4a -c:v copy -c:a libmp3lame -q:a 4 out.mp3
But I have to bring up a terminal, retrieve it from the history (while itās still in there), pick a filename, etc. Itās not hard to do, but itās a fair bit of busy work
I guess now that Iāve written it here, itāll be less work to remember.
But itās a bit late now since Iāve added the feature to do this for
me. Iāve included a statically linked version of ffmpeg
in the
Docker container (it needs to be statically linked for the same reason
why I canāt use CGO: thereās no libc or any other shared objects) and
wrapped it around a small form where I upload my
M4A.

The transcoding is done on the server (seemed a bit much asking for this to be done in the browser) but Iām hoping that most M4A files will be small enough that it wouldnāt slow things down too much. The whole process is synchronous right now, and I couldāve make the file available then and there, but it wouldnāt be the only feature Iām thinking of that would produced files that Iād like to do things with later. Plus, Iād like to eventually make it asynchronous so that I donāt have to wait for long transcodes, should there be any.
So along with this feature, I added a simple file manager in which these working files will go.

Theyāre backed by a directory running in the container with metadata managed by Sqlite 3. Itās not a full file system ā you canāt do things like create directories, for example. Nor is it designed to be long term storage for these files. Itās just a central place where any app can write files out as a result of their processing. The user can download the files, or potentially upload them to a site, then delete them. This would be useful for processors which could take a little while to run, or run on a regular schedule.
I donāt have many uses for this yet, apart from the audio transcoder, but having this cross-functional facility opens it up to features that need something like this. It means I donāt have to hand-roll it for each app.
Anyway, thatās the current state of affairs. I have one, maybe two, large features Iād like to work on next. Iāll write about them once theyāre done.