Log In  

PICO-8 0.2.4 is now up on lexaloffle, Humble, itch.io, and for PocketCHIP.

This update is another attempt at freezing the API before the last feature update (0.3 -- high scores), but let's see how it goes! 0.2.4 also includes an important security update (see below for details), so please do consider updating. Cartridges posted after this release post will only be visible from SPLORE when running 0.2.4 or later.

64k RAM

64K of Base RAM is now enabled by default. In 0.2.4 it is safe to PEEK/POKE/MEMCPY memory 0x8000 and above (i.e. -0x8000 .. -1) without setting the hardware extension bit at 0x5f36.

Because PICO-8's numbers only cover 0xFFFF, this means it is impossible to poke or memcpy out of range. The original motivation for having 32k by default was to give new programmers some concept of illegal memory operations, and as an extra form of feedback when code isn't working as expected. But over time, these reasons haven't proved as useful as the benefits of allowing 64k by default. Additionally, 0.2.4 introduces the first feature that explicitly uses the upper 32k section (see Big Maps).

Video Remapping

The video memory sections can now be mapped to each other, allowing the screen to be used as if it were the spritesheet, and/or to draw to the spritesheet as if it were the screen.

The mapped address for the spritesheet is stored at 0x5f54, and the mapped address for the screen is stored at 0x5f55. There are only 2 legal values that should be poked to each address: 0x00 (which means map to 0x0000), and 0x60 (map to 0x6000). This gives 4 combinations:

0x00, 0x60: default settings
0x60, 0x60: gfx functions (spr, circ..) use the screen as sprite data
0x00, 0x00: gfx functions all draw directly into the spritesheet
0x60, 0x00: swap spritesheet and screen

Here's an example of re-colouring and zooming a section of the screen, pasted in at the end of jelpi.p8's _draw() function. This was possible in earlier versions, but required a lot of memcpy()'ing to backup, use and then restore contents of the spritesheet:

-- lighter colours; no transparency
pal({[0]=1,5,13,13, 9,13,7,7, 14,10,15,11, 6,6,15,15})

-- set the screen memory as the spritesheet
-- and stretch screen->screen
poke(0x5f54, 0x60) 
sspr(48,80,32,32, 32,32,64,64) 
poke(0x5f54, 0x00) pal() -- return to defaults

Big Maps

Similar to gfx memory mapping, the map can now be placed at address 0x8000 and above (in increments of 0x100). This gives 4 times as much runtime space as the default map, and an additional POKE is provided to allow customisable map sizes.

Legal values are 0x20 (the default) and 0x80 and above. There are two pokes you need:

poke(0x5f56, 0x80) -- set the map to 0x80. Default is 0x20
poke(0x5f57, 0)    -- set the width of the map (0 means 256). Defaults to 128

The height of the map is determined by how much data is available in the memory section. So in this case, there is is 32k available divided by 256, which gives a map height of 128 cels -> 256x128.

Note that the map editor still always writes and loads at 0x2000. This feature doesn't come with extra cartridge space to match! So to use 0x8000 and above, you'll need to manually mset() or memcpy() some map data. This feature will be most useful for carts that procedurally generate their maps or have some custom data storage scheme.

The map address is observed by all map functions: mget(), mset(), map(), tline()

One-off Characters

P8SCII character data can be specified and printed in-line using "\^." followed by 8 bytes of raw binary data, or "\^:" followed by 8 2-digit hexadecimal values. The data format is the same as custom fonts; each byte specifies a row of 1-bit pixel values, with the low bit on the left.


Audio Sync

STAT(46)..STAT(56) can be used instead of STAT(16)..STAT(26) to query the state of the sound system with more precision. Although there are many carts that managed fine with the old STAT() calls, it required a bit of fiddling and data smoothing to get right, derived from whatever state the mixer is in at the start of each frame (which only changes ~20 times a second, depending on the host platform and phase of the moon).

The new version (STAT 46..56) works by storing a history of sound mixer states at each tick, along with timestamps for sound driver mix requests, to estimate which state snapshot is currently audible at any moment in time. It's still not perfect, but requires less to work to get pretty good sync going.


API Changes

Some small conveniences:

CHR() can now take multiple arguments to build a string:

> ?chr(104,101,108,108,111)

SUB() can take nil or _ as the last argument to return a single character (instead of the rest of the string). This is useful when the second parameter (the index) is some long expression that you don't really want to repeat in the last parameter, or go to the trouble of assigning a temporary variable to.

PAL(N) can be used to reset one of the three palettes to their default state (0 draw palette, 1 display palette, 2 secondary palette).

> sub("hello", 3, _)
> sub("hello", 3)

Cartridge Formats

The .rom.p8 format (a raw 32k block of cart data) can now be used by CSTORE(), RELOAD() and in multicarts. This should make it easier to generate cartridge data using external tools without needing to jump through the hoops of writing to .p8 / .p8.png format.

On a related note, the EXPORT command can now also be used with any cartridge format. So, to convert between cartridge formats from commandline, the -export switch can be used (pico8 foo.p8.png -export foo2.p8.png). From inside PICO-8, it is also a handy way to save a copy of the current working cartridge without altering the current working filename:


64-bit Raspberry Pi Builds

The file archive ending _raspi.zip now includes a build for the 64-bit version of Raspberry Pi OS called pico8_64. Exported binaries also have a matching file (e.g. mygame_64).

Security Patch

PICO-8 0.2.3 had quite a serious security flaw affecting Mac OS and Linux machines, that allow arbitrary commands to be injected into LOAD("#...") calls and executed on the host machine with the same privileges as PICO-8. PICO-8 0.2.4 fixes this in two places: the illegal cartridge ID is not allowed to be processed in the first place, and the URL used to fetch cartridges / listings is only allowed to contain a limited subset of characters. Earlier versions only had the second check, which was faulty.

As far as I can tell, there are no BBS cartridges that have used this exploit, and as a precaution SPLORE will no longer allow cartridges newer than this post to be listed to older versions of PICO-8.

So please do update to 0.2.4 to ensure you are not affected by this vulnerability, including for cartridges obtained from somewhere outside of SPLORE.

Server Test: Doodlemud

The last remaining part of PICO-8's api is SCORESUB() -- a simple api function for submitting highscores, but with some internal complexity. I've set up some new infrastructure for this to be reasonably future-proof and scalable, and a simple game for battle-testing it. You can try it here:


Doodlemud is a multiplayer world-building / exploration game where each player can switch between drawing each room and being a player in it. This test requires a keyboard and mouse (no touch / tablet support); press cursors to move around, and G to toggle gravity for everyone in that room. Feel free to change the url to start new empty worlds (any alphanumeric name after the hash is ok), but keep in mind that it is experimental, and all of the data will be erased when it gets updated!

ASCII Manual

The .txt version of the manual is back! It is included in the archives, and you can find it on the Resources Page. The text and html versions of the manual are now both generated from the same source file, so should always be in sync.


You can find the full changelog here:


P#101292 2021-12-03 07:22 ( Edited 2022-04-05 16:34)


Horray! congrats on getting player scores up and running I'm really happy to see this in the works. Thanks again for all the fantastic work you've put into this creation. It's such a fantastic thing and there's so many amzing games and amzing tools to creat games. Thank you so much.

P#101299 2021-12-03 08:56

Congrats on the release! I'm getting a "URL not found" after clicking the download URL for Linux, RPi or Mac Is it just me?

EDIT: nevermind, working now! Thanks. :)

P#101300 2021-12-03 10:40 ( Edited 2021-12-03 11:25)

thanks for continuing to support the pocket chip :)

P#101301 2021-12-03 10:49

Nice, @zep ! May I request you extend the sprite set in the sprite editor from 4-pages to a possible 6- possible 8-pages as you now have the ability to read/write from that area in code.

Failing this is going to make it tricky for people to draw sprites in that area.

Another problem I am finding. Despite having copied the first strip of sprites to the memory of the mapper, and testing it with:


It does not draw anything.

Test with the code HERE. Be aware this is self-modifying code. It will save it's memory each time it is run. It must be run and modified in the P8 system to see what the example.

Cart #sprite_move-0 | 2021-12-03 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#101361 2021-12-03 19:04 ( Edited 2021-12-03 19:52)

new update!!! :D

I think the itch binaries haven't been marked with which OS they belong to (like this: https://cdn.discordapp.com/attachments/840979590499663903/905225401322852383/unknown.png), which makes the install/upgrade button in the itch desktop app not work

edit: its fixed now; thank you!

P#101392 2021-12-04 00:41 ( Edited 2021-12-04 20:34)

I'm still fairly new here and this is the first update since I started with pico-8. Are updates always this game changing? :o

Coincidentally, I've been trying to figure out how to fit what I needed to in the smaller memory space before. To be honest it did force me to learn some key concepts relating to memory and optimization, but I think new coders will still find ways to reach that point on their own.

P#101393 2021-12-04 00:41

I've found 3 bugs that crash the console (none of them new, but all of them still present in 0.2.4)

(is making these posts a good way to report bugs? should I be writing " @zep" on posts like this?)

P#101408 2021-12-04 01:29 ( Edited 2021-12-04 01:29)

@zep - sub is broken in 0.2.4 on some inputs:

P#101425 2021-12-04 08:00

THANK YOU @zep ^_____^

@dw817 until spr(...) supports 16bits sprite number, we'll have to remap the spritesheet address so the range of sprites 0-255 gives access to any "sprite" we need in memory

P#101431 2021-12-04 09:58

i downloaded the update and for some reason i cant import spritesheets anymore
i keep dragging and dropping an image into the spritesheet tab and it doesn't change anything

P#101450 2021-12-04 17:37


I get a "COULD NOT FIND CART" error when trying to load this.

P#101458 2021-12-04 20:07

An aarch64 build, at last, with some great extras! Great news, @zep; I look forward to setting up PICO-8 on a Pi-powered retro machine!

P#101525 2021-12-05 06:15

A new Version, what amazing!!!

P#101533 2021-12-05 10:43

Thank you for continued support for PocketChip!

P#101577 2021-12-05 22:03


Maybe sub(str,i,0) might be a little less cryptic for getting just the one character? It's not legal to index character 0 of a lua string, so it's a good magic value that's the same type as the usual value in that arg spot. Might simplify your underlying C code a bit.

ᴵ ᵈᶦᵈ ⁿᵒᵗ ˢᵃʸ ᵗʰᶦˢ
ᴵ ᵃᵐ ⁿᵒᵗ ʰᵉʳᵉ

P#101581 2021-12-05 22:50 ( Edited 2021-12-07 15:21)


On reflection, I think my suggestion could cause problems for a lot of cases where people would expect to get an empty string as a legitimate result of sub(s,i,j) where j==i-1 and i==1. Never mind, don't do that.

P#101869 2021-12-07 15:11 ( Edited 2021-12-07 15:16)


P#102045 2021-12-08 18:35
P#102047 2021-12-08 19:06

awww i LOVE doodlemud!

P#102104 2021-12-08 23:41

two notes:

  1. a documentation bug:


> Each nibble in the map size means 2^n cels. The default is 0x76 (128x64)

This seems wrong (out of date?)

  1. a documentation bug?

the changelog says:

> Changed: Can turn P8SCII wrap on/off with "\^$", "\^-$"

but this isn't in the manual anywhere; I would expect it to be listed under https://www.lexaloffle.com/dl/docs/pico-8_manual.html#Rendering_mode_options__

P#102164 2021-12-09 05:32

yeah for linear maps but meh for 0x20 limit, see ‘bug’: https://www.lexaloffle.com/bbs/?tid=45729

P#102896 2021-12-16 07:54

Sprite drag and drop doesnt work now

P#103296 2021-12-22 02:21
P#104815 2022-01-11 15:13

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2023-09-23 01:53:11 | 0.026s | Q:55