Log In  

Hey All! PICO-8 0.2.6b is up now up on lexaloffle, Humble, itch.io, and for PocketCHIP and web (Education Edition). Note: you'll need to update to 0.2.6b to play new carts and SFX snippets created in 0.2.6!

Inverted Draw Operations

Thanks to @p01 for nudging me about this one! Filled draw operations (circfill, ovalfill, rectfill) can now be drawn inside-out: every pixel outside the area is drawn instead of every inside pixel. This can be controlled in a way similar to setting the fill pattern per draw call: first poke(0x5f34,0x2) to enable inverted draws, and then set bits 0x1800 in the colour argument. Here is a snippet to blank out everything except a circle in the middle (that changes size):

circfill(64,64,50+cos(t()/4)*10,0 | 0x1800)

And a short program that draws a tunnel:

function _draw()


    -- hold ❎ to skip fill
    cc = circfill
    if (btn(❎)) cc = circ

    for z=7,1,-1 do
        local sx = cos(z/15+t()/4) * 50
        local sy = sin(z/15+t()/4) * 50
        cc(64+sx/z,64+sy/z,64/z, 7+z | 0x1800)

High Memory Video Mapping

Before 0.2.6, display memory and spritesheets could be mapped to each other (at 0x0000, and 0x6000). They can now also be mapped to one of the four high 2k sections at 0x8000, 0xa000, 0xc000, and 0xe000, as long as they don't overlap with the map mapping which takes precedence. There is a nominal cpu cost when a mapped region changes between graphics and map, but otherwise changing mappings is "free" apart from the poke() call overhead.

This was a previously rejected wishlist feature, but due to a bug discovered (and rightly abused!) by @StinkerB06, it seemed proper to offer this as a substitute before that bug is "fixed" in a future version. Well played!

Here's an example of moving the spritesheet to 0x8000 so that 0x0 can be used for something else. Just a reminder of a confusing gocha: remapping the spritesheet remaps the whole memory area 0x0..0x1fff. So once @0x5f54 is set to e.g. 0x80, even memory functions like memcpy, memset that operate on 0x0..0x1fff will be operate on 0x8000..0x9fff.

-- copy spritesheet to 0x8000
-- clear spritesheet at 0x0 to prove it is no longer used!
-- remap spritesheet to 0x8000
-- draw something to prove it worked
spr(1, 50,50)

Waveform Instruments

Waveform instruments work roughly the same as SFX instruments: they each take up one SFX slot worth of data (SFX 0..7), and can be triggered from a regular SFX. But instead of treating the 64 bytes of note data as a regular SFX, they are used to represent 64 8-bit samples of a short looping waveform. Click on the new toggle button at the top right of the SFX editor to draw a waveform, and optionally pitch it an octave down with the "bass" toggle button. Waveform instruments can be used from inside SFX instruments, and also observe the detune, reverb and dampen filters.

Here are a couple of short demos (excuse the new WIP player -- it needs an initial tap to load it for browser compatibility). The first pattern shows some custom bass and lead instruments that are quite different from the built-in waveforms. Patterns 2&3 are more subtle, but those two instruments are also quite tonally different from any of the standard ones.


I think that doodling custom waveforms is great fun and opens up a new world of possibilities, but of course that in itself does set off alarm bells in terms of fantasy console design. I've come to view them as a worthwhile source of complexity that feels playful rather than overwhelming, and without creating a discontinuous jump in the "PICO-8 sound". Having said that, I'm sure I'll look back one day at earlier PICO-8 music with nostalgia for its particular simple charms. Here's a fitting tune by @ridgek to send off the old version!

Cart #fairwellfairfriend-0 | 2023-11-20 | Code ▽ | Embed ▽ | No License

Music Scale Snapping

A low-key (ha!) feature of PICO-8 since very early on is that holding CTRL while drawing frequencies snaps each note to the C minor pentatonic scale. This is useful for both sound effects and music -- you can't really go wrong walking up and down (or jumping around) those 5 notes.

In 0.2.6, the scale that is snapped to while holding CTRL can now be customized in the music editor. There is a toggle button at the bottom right to switch between volume and scale snapping. Click on the keyboard to toggle scale selection mode. There are two buttons for transposing (<<, >>), 3 preset scales, and an invert button to get 3 more:

Dim   Diminished 7th    // invert to get a whole-half scale
Maj   Major scale       // invert to get pentatonic
Who   Whole tone scale  // invert to get.. the other whole tone scale

Changing the scale does nothing to alter the existing SFX -- it is applied only when holding CTRL and drawing frequencies.

A Little Music Theory

What is a scale anyway? Very roughly speaking, it is a selection of notes that are chosen to have a particular character or mood when used together. You might already be familiar with the scale formed by all of the white notes on a piano (or using keys qwertyu in PICO-8): C Major. Hit the Maj preset button to select this scale, and hold down CTRL to doodle a sound (spd:1) or melody (spd:16) in frequency mode.

Inverting the major scale (hit Inv) gives an Eb minor pentatonic scale, which is another name for all of the black notes. Try doodling some shapes again, and see how different that sounds. I think pentatonic scales are the most useful for starting out with melodies and sound effects, with its bright, resonant sound. To get from Eb minor pentatonic back to the default C minor pentatonic scale, hit << 3 times to transpose down 3 semitones. Examples of major and pentatonic scales are given in the first 2 patterns:


The other two scale presets also have their own distinctive character, with examples above in patterns 2..4. Who for a wholetone scale (every second semitone -- pattern 2), gives a floating ethereal feeling. Good for things like "falling down a hole" or "found a secret level". Dim for a 4-note diminished 7th scale (every third semitone -- pattern 3) gives something more unresolved ("entering a hidden chamber", or "a boss appears"). Inverting the diminished scale gives the whole-half diminished which has an even more mysterious quality that is more like "that lever triggered something but we don't know what it is yet".

These are oversimplified and silly examples, but I hope it gives you an idea of the kind of things you can explore with scales! If you'd like to know more, I highly recommend @Gruber's tutorial series that has a lot of handy music theory weaved in and also @bikibird's interactive music theory tutorials.

Handheld Improvements

With the rise of handheld devices like the RGB30 and Miyoo Mini Plus, there are many more handheld users of PICO-8 now (welcome aboard!). 0.2.6 has a few adjustments to make life easier:

Metadata Mending

When favouriting a bbs cart in 0.2.5g using the typical RGB30 / MM+ configuration, it was showing up as a local file with no metadata (blue cart icon instead of orange). Not a huge problem, but those carts can not show their full title, author and lose the ability to auto-update and find similar carts.

0.2.6 fixes that bug, and also deals with those carts by pinging the bbs for metadata when they are opened. So to "mend" such a bbs cartridge that has a blue label in the favourites list, just open it once while wifi is enabled.


This is an option in config.txt, that treats the first n controllers as if they were a single merged controller. This is useful in situations where you want to use the built-in buttons on a handheld device, but then later plug in a controller (e.g. when you connect it to a TV), but want that controller to also be used for the same player. To set up PICO-8 for such a system, use merge_joysticks 2 in config.txt.

Shutdown from Options

You can now close PICO-8 from the options menu while playing a game. This is handy for devices that do not have a 'kill app' option / button combination. Previously it was necessary to first exit to splore, then open a cartridge menu and use the options menu from there.


Mac Universal Binaries

PICO-8 now ships with native support for Apple silicon, as well as intel versions bundled as a universal binary. The exporters produce executables in that same universal format. To do this, I had to bump the minimum required MacOS to 10.8. I know there are still a few of you out there using PICO-8 on older Macs that will otherwise become doorstops. I don't have a good solution for this yet, but later on I'll look at setting up a legacy build system for such machines if there is sufficient demand.

Menuitem Button Filtering

By default, pause menu items creating using menuitem() respond to any button press, including left and right. This is handy in some situations (toggle buttons) but annoying or dangerous in others (clear game data). menuitem() can now take a bit mask in the high bits of the first parameter, indicating which button presses to ignore. Bits 0x100 and 0x200 mean LEFT and RIGHT, so if you can ignore those button presses with:

menuitem(0x301, "option 1", my_callback)

Improved Search

The search box in splore and on the bbs now returns more sensible results. Posts are sorted by number of stars, so if you type in "celeste", the first two results will be the original Celeste and Celeste 2. Imagine that! As a side-effect hack, you can search for " " and get an all-time highest starred cartridges list.

While working on search and scanning the BBS for preprocessor breakage, I made this collage of the 14 pages of featured cartridges that are now available (out of around 18k published carts). W00t! \o/

Preprocessor Removal

This is an internal change, but worth mentioning. 0.2.6 no longer uses a preprocessor at all (thanks to z8lua), so all of the code is running through a (modified) Lua 5.2 implementation as-is. Most of this happened in 0.2.5*, but there were a few leftover language features like short form print (using ?) and number parsing. 0.2.6 now also allows the use of "do" instead of "then" in if statements, which is something the preprocessor allowed (by accident!) and a number of early carts use it. There is a small amount of breakage of older carts that have things like unclosed or otherwise ill-formed comments that shouldn't be accepted. For those types of cases, I'm gradually working through older carts to make stealth fixes where needed. At this point the vast majority of existing carts should run as expected -- please do let me know if you see something weird that isn't a syntax error, which I can scan the BBS for automatically.


There are 2 new social usernames addable to your BBS profile: twitch.tv, and bluesky which is now open for signups without an invite. My social network of choice is still the fediverse / mastodon, but I think bluesky has the potential to coexist and be a nice place in the future ~ especially if they end up supporting gifs.

-> Add social handles to your profile

-> Find other lexaloffle users on bluesky / twitch



Added: 2 more players worth of mappable keyboard controls in config.txt (button_keys)
Changed: finished removing preprocessor; was causing e.g. "function --[[oops]]f() end"
Changed: "do" can be used instead of "then" // a bunch of older carts were able to do this via preprocessor
Changed: removed CTRL-O as a way to open the cpu profiler so that custom devkit carts can use it
Fixed: When bbs carts folder is inside root_path, opening favourite while offline clobbers item metadata
Fixed: Missing metadata for favourited carts; bbs is pinged to grab metadata and splore item is mended on play
Fixed: save() / export() called from headless script on existing file only overwrites every second file
Fixed: pasting music pattern data does not recreate sfx instruments that do not already exist in target cart
Fixed: Format string when exporting .wav is unstable / insecure
Fixed: bad block scope caused by nested short forms e.g. if (1)?"foo" // #dinkykong, /bbs/?tid=140066
Fixed: >><=, <<>= operators missing (from 0.2.5d)
Fixed: atan2(1, 0x8000) returns 0.25 (should be 0.75)
Fixed: audio crackling on Miyoo Mini Plus (regression in 0.2.6, but unreleased)


Added: Custom waveform instruments
Added: Configurable scales in music editor (for using ctrl to snap to scale)
Added: Inverted draw operations
Added: Video and spritesheet memory addresses can be mapped to 0x8000, 0xa000, 0xc000, or 0xe000
Added: stat(111): same as stat(109) except returns a higher value on web to overfill audio and reduce crackle
Added: menuitem(0x300|index, ...) ignores left and right button presses. 0x7000 to ignore X/O/MENU.
Added: config.txt "capture_timestamps 1" to use timestamps as suffix in screen/video capture filenames
Added: (Mac) Universal binaries, also generated when exporting
Added: (Mac) Updated to SDL2 2.28.5 (-> minimum MacOS version is now 10.7)
Added: config.txt:merge_joysticks to map n controllers to a player (e.g. to plug a gamepad into a handheld)
Added: config.txt:use_wget to use wget for downloads instead of libcurl (wget must be installed)
Added: SHUTDOWN PICO-8 from the options menu while running a cartridge in -splore mode
Added: Preserve window position and size when switching to and from fullscreen mode
Changed: ADD(TBL, X, NIL) now behaves the same as ADD(TBL, X) (used to produce an out of bounds error)
Improved: Moved internal globals out of top level to improve vm perf on carts with no _draw()
Improved: Boot time and memory usage reduced on low end machines
Fixed: 0x808 audio produces buzz on web browsers that mix at 48000MHz (ref: #rp8, #waterflakes)
Fixed: When bbs carts folder is inside root_path, favourited carts show up as local files without titles
Fixed: (from 0.2.5d) compound operators (a+=1) cost more than their expanded equivalents (a=a+1)
Fixed: cstore out of range when storing to self while running a bbs cart causes segfault
Fixed: tab complete on non-existant directory adds garbage to commandline
Fixed: can not navigate songs patterns with -/+ when pattern is empty
Fixed: backspace/del removing cart from favourites list even when inside the fold-out cartridge menu

That's all for now -- I'll catch you in a couple of weeks with a new machine!

P#142119 2024-02-28 13:33

Erm. Not sure why, but every time I click on the SFX editor button, Pico8 just hangs and then drops me back at the desktop :( Is there a logfile anywhere ?

P#142123 2024-02-28 14:12

exciting update!

P#142127 2024-02-28 14:40

I'm excited for the upper-memory sprite and video methods, this and the inverted draw functions are wonderful surprises! I'm so glad to be getting into PICO-8 at this time.

Thank you @zep! Looking forward to Picotron!

P#142131 2024-02-28 15:45

I was wondering if there was a way to make waveforms other than the mouse?

P#142133 2024-02-28 16:22

Yay! Really nice update, thx @zep
Guess I have a few updates to factor into the Cheat Sheet
(it's ok - nice problem to have!)
Thx again, as always 🤓 <3

P#142152 2024-02-28 19:40 ( Edited 2024-02-28 19:48)

I wondered why the search order had been shuffled around! While sorting by stars is a pretty good way of going through the standard search, IMO not so much for a by-author search; before the easiest way to see if someone you liked had made something new was to find a cart of theirs in your favorites, tap enter, scroll down and select the CARTS BY @zep (or whoever), and PICO-8 would automatically search for BY:ZEP, with the newest cart(s) on top. But now, it just shows their most popular work instead (odds are, you already know about it), with the newest one(s) likely being somewhere near the bottom (due to being more recent, and therefore having much less time to be starred). I would suggest that the old behavior should be restored when using a filter like BY: or THREAD:, reserving the star-sorting behavior for normal searches and the SIMILAR: filter.

P#142153 2024-02-28 19:40

Wow, I feel so official! Thanks for everything, @zep! ❤️

P#142154 2024-02-28 19:55

Been testing that out myself, if you center the circlefill at 64,64 and do radius 0 then there is a tiny dot in the middle. I found I had to do a if else statement to do cls() if r <= 0 to get it to completely wipe.

P#142188 2024-02-29 09:15

That tunnel looks familiar 👀

After playing with the waveform instruments for a few minutes, I can safely conclude that I have no idea what I'm doing

The upper memory thing seems like a good way to put layers in an art tool

P#142194 2024-02-29 12:52


P#142202 2024-02-29 14:18

Since there's changes being done to the search I have a suggestion about the web site.

When you link to a game from , for example discord, the preview displayed just says the name of the game. For people who are not used to seeing Pico 8 links, this link might look a bit like just a random link, rather than a link to a cool pixel game. It would be nice if the page's metadata would have at minimum the cartridge of the game.

P#142206 2024-02-29 15:00

Why include pentatonic minor though? Wouldn't it make more sense to pick a minor scale and then let people choose to use less of the notes, especially since you're including major anyway?

P#142211 2024-02-29 15:45

@RyanC a circ of r=0 will appear as a single pixel. Try r=-1

P#142212 2024-02-29 16:12

Has anyone else experienced crashes when hitting the SFX editor button ?

P#142229 2024-02-29 21:01

@Minion what environment are you running in, and what if any error messages are you seeing?

P#142232 2024-02-29 22:25

thanks for continuing to support the PocketChip :)

P#142256 2024-03-01 08:50

Thanks for all the hard work @zep

P#142303 2024-03-02 05:44

@kozm0naut its windows 10. and there is no message. I click on the SFX editor button and the mouse hangs for a short while then it just closes down. Not to worry tho, I've just gone back to the previous version which is stable.

P#142308 2024-03-02 08:25


I can't speak to zep's motives obviously but for whatever it's worth, I've seen/heard advice for people who want to be able to play around on the piano but don't necessarily want to learn to "play piano" to stick to improvising on only the black keys (AKA F# Major/D# Minor pentatonic.)

It's shockingly difficult to make something sound bad if you're sticking to a pentatonic scale which is not necessarily the case with the natural minor scale. Giving them mino and letting them choose fewer notes sort of requires they know which set of notes to choose. But not everyone who wants to try their hand at making a game will have a music theory background. A nice friendly, "just stick to these five notes and you'll be fine," can be the confidence boost someone needs to try making their own music.

Not everyone, even complete beginners, will either want or need that. But it's easier for people who already know what they're doing to diverge from the defaults and get good results. So pentatonic seems like a reasonable default to me at least. YMMV

P#142321 2024-03-02 14:33

Love these new features!

Please consider this for a future release: It's easier to write visualizers for PCM audio than it is for standard PICO-8 music because it's easy enough to get a byte that represents the current amplitude, but that's not possible with music/SFX. For example, writing an oscilloscope visualizer is pretty much impossible for music/SFX, but simple for PCM. Ideally, I'd like a stat that would return the current amplitude of the music/SFX as it is being played.

P#142424 2024-03-04 20:37

This could be a bug; observed on this latest version (MacOS build).

The code below draws a moving vertical line.
It runs smoothly (as in, line is drawn progressively towards screen edge) on 0.2.5g.
It does not (occasionally jumps back a few pixels before "resuming" at next expected position) on 0.2.6b.

Can anyone reproduce this ?


x = 0

function _update60()
  x += 1
  if x > 127 then x = 0 end

function _draw()

EDIT : glitch sometimes only observed after a few sweeps ( 0 1 ... 128 0 1 ... 128 0 1 ... )

P#142757 2024-03-11 12:32 ( Edited 2024-03-12 07:24)

@alexr I'm not able to reproduce this unexpected behavior in 0.2.6b (on Linux via Chrome OS). Everything looks good here.

P#142760 2024-03-11 14:36 ( Edited 2024-03-11 15:17)

@kozm0naut Thanks. Strange. This could be a Mac specific issue. I'll test it on another machine.

P#142761 2024-03-11 14:44 ( Edited 2024-03-11 15:13)

Is it me or "merge_joysticks" is not working as intended? I've tried on Steam Deck (linux) and RGB30 (rPi) and instead of merging two or more physical controllers into a single virtual "joystick 0" it does the opposite: the inputs from the physical controller are being applied to virtual joysticks for Player1 and Player2 in Pico-8.

merge_joysticks 2 #not working?
P#144836 2024-03-28 13:44 ( Edited 2024-04-01 13:53)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-04-15 12:33:31 | 0.170s | Q:67