I’m out of the rabbithole. Oh, the things I’ve seen. I’ll spare you the theatrics, though. You’re here for the content. Playnote 0.2 is here, so let’s dive in.
Theming tribulations
That’s the big feature of the release. Visually the UI is identical, but now it’s driven entirely by a theme that describes every visual and layout detail, and even the behavior of the playfield. You can create a theme from scratch, rewriting every screen you can see, or inherit from the built-in theme to make small tweaks. Themes can be packaged and distributed to others, who can then install them by dragging the file onto the game, just like song imports. The current theme can be edited while the game is running, and the changes show up instantly.
KDL is used for metadata and structure partials, AngelScript is the scripting layer, and PlaynoteCSS is a CSS-inspired but otherwise built-from-scratch stylesheet language. It’s somewhat like the HTML+JS+CSS web development trifecta, though laser-focused on the game’s unique needs.
I could keep writing and writing about all the cool things in it. And I did! The whole thing is documented in a ten-thousand-word series of articles in the project wiki. I’m very proud of it, if you can’t tell. Ultimately, though, the point of it is to make future feature development easier. Tweaking the UI until it looks Just Right will now be a pleasant, interactive process, rather than requiring a rebuild of the code and a game restart every time. It is often said the first user of any modding system is the developer. I’m very excited to be its user.
Command-line cravings
There are a few smaller improvements and conveniences to mention. For the mouse-averse, it is now possible to import songs and install themes by starting Playnote with command-line arguments. If you’re interested, run Playnote help to get started. Or Playnote -h, I don’t judge.
If the game’s not running, the command will execute right then and there. If the game is running, the command will be sent to the game via an IPC interface.
Technical touch-ups
Minor, but all in the name of the ultimate experience:
- A lot of my windowing code was written assuming SDL2’s quirks. It turns out that SDL3 made most of these workarounds obsolete. The input thread now uses native OS event timestamps, and blocks on events rather than polling at 1000 Hz.
- The frame pacer was rewritten, again, to explicitly calculate variances of individual OS timings and more responsively converge to a reliable sleep value in a changing environment. I torture-tested it with a laptop, on battery, running a script that artificially toggled the GPU between the lowest and highest frequency. It didn’t drop a single frame.
- On Linux, signals like
SIGTERMare now handled gracefully. The handler does its best to shut the game down cleanly, no matter what it was doing at the time.
Infrastructure intermissions
The migration to Forgejo Actions, mentioned in the previous post, is now complete. In addition to the security improvement of not having another internet-facing login screen, CI runs are now integrated into the repository (like this), and it’s now easier than ever to download the latest dev build.
On top of that, the builder VMs are now fully reproducible! If (when) the time comes to update the compiler versions to get the shiny new C++ feature, creating new VMs will be just one script away.
Final farewell
This is the last time you’ll be hearing from me in a tear.moe blogpost. Adieu! Right after finishing this post, I’ll be getting to work on the proper project homepage, which will replace the roles of both this blog and the repository wiki.
And, after that, the long-promised player profiles and score saving.