Version 3.0.1
ℹ️ This is a minor bugfix over 3.0.0 to reset screen.cursor every frame so screen.text("Hi") doesn't fly off the bottom of the screen. We've also added a backlight floor so the backlight is lit across its entire range (it comes on quite suddenly at low brightness and previously that was about 40-50% up the range.)
To say we've changed a few things in Badgeware would be an understatement. Almost no stone has gone unturned, but we've paired this release with an extensive documentation overhaul. to soften the blow.
We're not going to bury the lede: your custom apps will break. But hopefully for the better.
The bits that'll get ya
In brief, load_font() and pixel_font.load() have been folded into font.load() and you'll get back the correct type.
text.draw() is now folded into screen.text() which supports all that juicy rectangle layout stuff, now with added horizontal and vertical alignment options, and configurable truncation (clip vs ellipses).
Text, on the whole, is now cursor driven so screen.text("message") without a position is totally valid, and called repeatedly it will wrap messages down the screen. Set screen.cursor = vec(x, y) or supply a position or rectangle to reset the cursor.
source.alpha is now ignored in all blend operations, you should set dest.alpha (usually screen.alpha) if you want a brush, shape or otherwise to draw with transparency.
New stuff
A new fetch.url() API aims to make... fetching... urls... with an asynchronous, generator-driven pattern much easier. You just need to poll in your update loop and do something with the data when it arrives.
Filters. So many, many filters. To name but a few there's glitch and noise and bloom and even fractals for generative textures.
image.spritesheet(rows, cols) now returns a spritesheet object which gives you a .sprite(x, y) and/or .sprite(n) method for addressing sprites. This is the type you get if you image.load() an animated gif, though you have to do the legwork to play gif frames.
image.load() on a P8 image will now give you access to modify the palette. This allows some incredible palette cycling effects if you're lucky enough to possess savant level pixel art skills.
Making colour even more fun, creating a colour now preserves its origin so color.rgb(r, g, b) and color.oklch(l, c, h)` carry a bunch of methods to compare and mutate them.
We've added a gradient brush and an erase brush, which - to be frank - is a little bit of a workaround for the lack of blend methods but handy for punching windows into things, or clearing an offscreen image to transparent if you're building scenes in layers.
Tweening. Interpolate over time between floats, vec2s, rects or mat3s.
Performance
We've rewritten things and rewritten them again. Just for fun we might have rewritten them a third time. Honestly I've lost count. In the endless pursuit to squeeze a little bit more out of Badgeware we've bumped the minimum CPU frequency up to 250MHz. Beyond that, more or less every drawing operation has received careful optimisation and everything feels faster. So much so we've had to slow some of the games down to make them playable again. Bee Amazed might have been forgotten... but bees are buzzy anyway.
Performance optimisations even delved into MicroPython itself, and we're shipping a handful of experimental fixes to garbage collection, plus some additional optimisations we've contributed back upstream.
What didn't make the cut
We really, really, really wanted to make working with the badge less of a pain. Having a huge, read-only filesystem to deal with - alongside a small hidden one for caching and state - remains quirky and awkward. There's stuff you can write but not see, stuff you can see and not write... one day we'll figure it out, but for now you can play with a Badgeware Tufty entirely in your browser, no awkward file copies required.
This is by no means an exhaustive list of changes. We hope you find joy and excitement discovering everything else we've broken changed!