Log In  

Joseph White, a fantasy console & game developer based in Tokyo. I'm currently working on Voxatron and PICO-8.

PICO-8 0.2.1
by zep
PICO-8 0.2 (Beta!)
by zep
PICO-8 For PocketCHIP
by zep

Hi All! PICO-8 0.2.1b is now up on lexaloffle, Humble, itch.io, and for PocketCHIP. This update started as a continuation of 0.2.0 bug-fixing work, but I also relaxed my position on API minimalism just enough to add some new features :D

UPDATE: 0.2.1b is now live and fixes the print() bug, and a few other things. See the changelog below for details.


You can draw ovals (technically, ellipses) both when running a cartridge, and when using the shape tools in the graphics/map editors. Ovals are specified by their boundary rectangle, and follow the usual draw state rules.


function _draw()
 for i=0,31/32,1/32 do
  local x=64+cos(i+t()/8)*48
  local y=64+sin(i+t()/8)*44
  local w=8+cos(i*2+t()/2)*6
  local h=8+sin(i*3+t()/2)*6


 print("pico-8 0.2.1",40,62,13)

Serial I/O

To make it easier to set up workflows for getting data in and out of carts during development, some new serial() channels are available. You can turn a file on your host machine into a binary stream, or drag and drop it into the running cartridge to do the same. From the manual:

Additional channels are available for bytestreams to and from the host operating system.
These are intended to be most useful for UNIX-like environments while developing toolchains,
and are not available while running a BBS or exported cart. Maximum transfer rate in all 
cases is 64k/sec (blocks cpu).

        0x800    dropped file   //  stat(120) returns TRUE when data available
        0x802    dropped image  //  stat(121) returns TRUE when data available
        0x804    stdin
        0x805    stdout
        0x806    file specifed with: pico8 -i filename
        0x807    file specifed with: pico8 -o filename

Image files dropped into PICO-8 show up on channel 0x802 as a bytestream:
The first 4 bytes are the image's width and height (2 bytes each little-endian, like PEEK2),
followed by the image in reading order, one byte per pixel, colour-fitted to the display 
palette at the time the file was dropped.

Drag and Drop

On a related note, you can also now drop .p8.png cartridges into PICO-8 to open them. If there is a cartridge with unsaved changes, it will prompt before continuing. You can also drop .png files into the spritesheet, by first selecting the sprite that should be the top-left corner location.

API Changes

add() now comes with an optional 3rd parameter: an integer that specifies the location in the table that the new value should be inserted at. Similarly, a new variation of del() is available: deli(tbl, index) ("delete by index") allows deleting from a given location in the table rather than by value.

split() is also new. It complements the common strategy of storing data as strings. From the manual:

split str [separator] [convert_numbers] 

Split a string into a table of elements delimited by the given separator (defaults to ",").
When convert_numbers is true, numerical tokens are stored as numbers (defaults to true).
Empty elements are stored as empty strings.

split("1,2,3")               -- returns {1,2,3}
split("one:two:3",":",false) -- returns {"one","two","3"}
split("1,,2,")               -- returns {1,"",2,""}

Binary Storage

It is now also more efficient to store 8-bit binary data in the source code section, by encoding it as a binary string. The .p8.png format stores uncompressable sequences as a raw block of data, effectively allowing cart authors to choose how much of the code section to trade for raw binary storage.

Binary strings can be encoded by escaping characters that can't appear in the source code. For example:
0 should become "\000" (or "\0" when not followed by another number), etc. To make this easier, previously invisible characters C1..C15 have font entries, and also unicode replacements when copying and pasting. I'm working on a snippet for converting between data strings and raw binary data, to make this process easier. UPDATE: here's the snippet.

HTML Touch Support under iOS

Touch controls for HTML exports is now a little smoother, and works when running from inside an iFrame (including itch.io game pages). I removed the mobile buttons menu by default (the buttons along the top: fullscreen, sound, close) as they aren't very useful and are messy, but they can be turned back on in the options near the top of the exported html.

Changelog // added 0.2.1b

There are many other bug fixes in this update, but I haven't gotten around to replying to the BBS threads yet. For now, please check the complete changelog:


Added: split(str,"") splits by single characters
Updated: Tower of Archeos 1.1 via INSTALL GAMES
Fixed: print(num,x,y) always prints numbers num in hexidecimal
Fixed: .p8.png decoder can enter an infinite loop (caused exports to freeze on boot)
Fixed: Can't save screenshot/gif when running a BBS cart with illegal characters in title.
Fixed: INSTALL_GAMES is broken
Fixed: Mouse is broken in HTML exports


Added: oval() ovalfill() split()
Added: circle drawing tool is now an oval tool (hold shift for circle)
Added: hold shift with line tool to snap to 22.5 degree angles from origin (0:1, 1:1, 2:1 gradients)
Added: serial() channels for stdin,stdout
Added: raw binary and image files dropped in to PICO-8 also become byte streams readable w/ serial()
Added: add(tbl, val, index) -- insert val into table at index
Added: deli(tbl, index) -- delete element from table by index (index defaults to last element)
Added: show progress while exporting binaries (can be slow now that generating zip files)
Added: -e to add an extra file to exported binaries zip files // export -e manual.txt foo.bin
Added: RESET command to reset the runtime / draw state
Added: drag and drop cartridges into PICO-8 window to load them
Added: hash stored in .p8.png so that cartridges corrupted by image quantization can show a specific error
Added: raw data blocks in compressed code format (useful for storing long binary strings efficiently)
Added: clip(x,y,w,h,true): 5th parameter indicates that the clipping region should be clipped by the old one
Added: -export switch can be used to convert .p8 files to .p8.png from commandline. // pico8 foo.p8 -export foo.p8.png
Added: extcmd("screen",scale) and extcmd("video",scale) to override the default scale (e.g. scale 2 means 256x256)
Added: printh(str, filename, overwrite, save_to_desktop) -- 4th parameter to save output file to desktop
Changed: add(), del() no longer implemented with Lua snippet; lower cpu cost.
Changed: line(),rect() cost the same as rectfill() when drawing equivalent shapes
Changed: all drawing operations in sprite editor now observe fill pattern state
Changed: numbers can be immediately followed by identifiers (a=1b=2) // lexaloffle.com/bbs/?tid=38038
Changed: Sprite editor shows only active area after shift-selecting sprites
Changed: copy/paste in the code editor treats uppercase ascii characters as puny font only when puny mode (ctrl+p) enabled
Changed: C0 Controls characters (except for 0x0,0x9,0xa,0xd) encoded in .p8 / clipboard with unicode replacements
Changed: stat(4) converts characters to PICO-8 format (P -> puny p, hiragana unicode -> single character etc.)
Changed: serial() returns number of bytes processed (1/8ths included for partial bytes)
Changed: IMPORT SPRITESHEET.PNG now uses the current sprite as the destination coordinate instead of 0,0.
Changed: Standardized name of the display palette to "display palette" (was sometimes referred to as "screen palette").
Changed: tostr() returns nil (used to return "[nil]")
Changed: don't need to set bit 0x40 at address 0x5f2c to use secondary palette.
Improved: exported binary's data.pod file 90% smaller (~870k -> ~85k)
Fixed: pack(...).n is shifted right 16 bits
Fixed: ctrl-r doesn't reload external changes for carts which are over compressed code capacity
Fixed: false positives when detecting external changes for some older cart versions
Fixed: .p8.png carts saved with dense code (compressed size > raw size, including very small carts) stores junk
Fixed: error message duplication when loading future version of .p8.png carts
Fixed: Illegal colours can enter spritesheet via serach-replace after setting with color()
Fixed: Preprocessor: "foo():a().x+=1" "a=b[1]c+=1"
Fixed: hex numbers written with punyfont characters breaks syntax high-lighting
Fixed: shift+- in sprite editor jumps too vertically when zoomed in
Fixed: clicking a note in sfx editor creates a selection (-> backspace clears without moving rows)
Fixed: print()/printh()/stop() doesn't respect __tostring metatable method (regression)
Fixed: time() and btnp() speed changes after stopping program, typing a command and then resuming.
Fixed: phantom drag & drop events sent to unused music channels causing them to occasionally unmute themselves
Fixed: undo after moving sprites in map mode only undoes the changes to the map and not the spritesheet.
Fixed: inconsistent token counting for negative or bnot'ed numbers https://www.lexaloffle.com/bbs/?tid=38344
Fixed: Crash when INSTALL_GAMES / INSTALL_DEMOS without a writeable disk
Fixed: stat(4) (clipboard contents) does not convert unicode to corresponding glyphs
Fixed: (MacOS) Using discrete GPU ~ drains battery. Now using integrated GPU when available.
Fixed: screensaver is blocked while PICO-8 is running (needed to set SDL_HINT_VIDEO_ALLOW_SCREENSAVER: "1")
Fixed: screen glitches after running for 25 days
Fixed: (HTML Exports) touch controls not registering when running under iOS from an iframe (e.g. on an itch.io page)
Fixed: (HTML Exports) tap and hold brings up the select menu under iOS
Fixed: (HTML Exports) button blocked by canvas when overlapping on small screens

P#78861 2020-07-04 00:59 ( Edited 2020-07-05 21:37)

// Promo video by m7kenji with music by Kyohei Fujita

Shibuya Pixel Art 2020 is accepting submissions until the end of June, and this year there is a new category for 128x128 games! Lexaloffle is sponsoring the game category with a prize (a Picade Cabinet), and by offering a limited number of PICO-8 licenses to participants.

Similar to a game jam, entries should be based on one or more of the following themes: Shibuya, AI, Humanity, Game and/or Landscape. Unlike typical game jams, existing work can be adapted or reused, as long as it did not win a previous contest. You can find previous winning entries for 2018 and 2019.

To enter: simply post the image on twitter or instagram with the hashtag: #shibuyapixelart2020. It is possible to submit more than one entry. For game submissions, post an image of the titlescreen along with a link to the playable game (this BBS / itch.io etc). I suppose for images you'd also want to post a link to the original non-compressed version if needed. Also note that previous years' selections also included gifs/mp4s that also work as still images.

Apart from a Grand Prize (300k yen + a Wacom tablet), there are also 4 special category awards for: Limited Pixel Art, Analogue Pixel Art, Beyond Pixel Art and Pixel Art Game. Winning entries are announced in early August, with an exhibition and awards ceremony in September. But you don't need to be in Japan to enter!

For more information, and to read the full terms & conditions of entries, please visit the official contest homepage: https://pixel-art.jp/ (there is an automatic English translation button near the top of the main content).

UPDATE: I'm not sure if there are restrictions on team projects yet, but will update this thread with any news.

SHIBUYA GIRLS by @yacoyon 2019

生まれ変わる町 by @m7kenji 2019

P#76632 2020-05-15 16:12 ( Edited 2020-05-15 16:15)

by zep
Cart #orbys-0 | 2019-05-18 | Code ▽ | Embed ▽ | No License

Back to 2016! This is a demo @castpixel (also on twitter ) and I made in the weeks leading up to Tokyo Demo Fest 2016, as newly formed group: POD. Because it was made in a hurry, I felt I should tidy up the code before posting it. But that's never going to happen, so here's an even messier post-compo version with a few extra details added instead! The rotating orbycube effect can now be found in /demos though if you'd like to see roughly how it works. Also, if you're curious you can find the compo version with: load #orbys_compo

P#76564 2020-05-14 15:42

Download 0.2.0i at lexaloffle or via Humble, or for PocketCHIP.

Alright, let's do this! PICO-8's core specification is complete, and it appears to do what it says on the tin. So I'm calling it:

PICO-8 is in Beta!

The main purpose of 0.2 is to finish freezing the core of PICO-8 -- the api, cpu counting, specs, cart format, memory layout, program behavior, backwards and future-compatibility should no longer change.

Earlier attempts at settling on a fixed core in 0.1.11 and 0.1.12 failed because of technical issues creeping in and also some design decisions that just didn't sit right. It has only been due to the ongoing process of users like @Felice, @electricgryphon, @jobe, @freds72, @Eniko, @samhocevar, and many others prodding at the boundary of what PICO-8 can do -- and what it should do -- that all of those nooks and corners finally took shape. I'm really happy with the way the last pieces of PICO-8 have snapped together, and I think it has reached a point where it feels not only like it should never need to change, but that it never could have been any other way.

To make this happen required some jolting changes and a string of patches to get right, and the last few weeks PICO-8 has been in an uncomfortably liquid state. My apologies to everyone who was riding that bumpy update train (but thanks so much for the bug reports!). There might be one or two emergency patches in the next weeks, but I think any left-over quirks and design flaws will simply become part of the machine.

New Features and Changes

Character Set

PICO-8 now has a full 8-bit character set that can be accessed with CHR() to get a character by index, and ORD() to get the index from a character.

> PRINT(CHR(97))

All characters from 0..255 (0..15 are control characters and are not visible)

All of the new characters 16..255 can now be typed directly into the code editor. There are 3 modes that can be toggled on and off:

  • Katakana (ctrl-k) // type in romanji: ka ki ku ke ko
  • Hiragana (ctrl-j) // ditto
  • Puny Font (ctrl-p) // shift-letter gives you regular font

Additional characters can be accessed in the 2 kana modes with shift-0..9

SFX / Music Organiser

These can be accessed in the music editor, and give you a cart-wide view of all of the patterns or SFXes in a cart. They can be selected by shift-clicking, copied and pasted, or moved around (with ctrl-x, ctrl-v), and can also be used to visualize which SFXes are being used while music is playing.


Bitwise functions can now instead be expressed with operators. The function versions are still useful if you want nil arguments to default to 0, or just as as matter of style. But the operator versions are a little faster and often more token-efficient.

BAND(A,B)   A & B
BOR(A,B)    A | B
BXOR(A,B)   A ^^ B
SHL(A,B)    A << B
SHR(A,B)    A >> B
LSHR(A,B)   A >>> B
ROTL(A,B)   A <<> B
ROTR(A,B)   A >>< B
BNOT(A)     ~A

There's also a handy integer divide, and operators to peek (but not poke)

FLR(A/B)   A \ B
PEEK(A)    @A
PEEK2(A)   %A
PEEK4(A)   $A

Capacity Adjustments


Bitwise functions (BAND, BOR..) and PEEK functions are now a little more expensive. They can be replaced with operators counterparts to improve speed, but even they are not as fast as the 0.1.11 bitwise functions, especially when used in deeply nested expressions.

This change was necessary because I badly miscalculated how much real-world CPU load would be required to run the most bitwise-heavy carts. Lua functions cost a lot of (real) CPU compared to vm operators, and the result was carts that could completely obliterate a web-browser or real-world CPU on an older machine. This is a problem because a central goal of PICO-8 is to allow authors to forget about real-world CPUs across platforms, and just focus on the PICO-8 one.

Unfortunately, another central goal is to not mess with or break existing carts! So this was a hard choice to make. I've tried to balance this change somewhat with the introduction of native operators, tline(), and by adjusting the vm costs in a way that feels natural but also frees up some extra cycles. Along with bitwise and peek operators, the add and subtract vm instructions now also cost half as much as other vm instructions. So if you consider PICO-8 to be running at 8MHz, they cost 1 cycle per instruction, while most vm instructions cost 2.

CPU: Coroutines

Previous versions of PICO-8 handled CPU counting inside coroutines very badly. It was easy to accidentally (or intentionally) get 'free' cpu cycles when running a coroutine over a frame boundary, and in some versions the opposite could sometimes happen -- a coroutine or garbage collection would incorrectly yield the whole program causing unnecessary frame skipping. 0.2 contains a much cleaner implementation of cpu counting -- you can wrap anything in coresume(cocreate(function() ... end)), and get exactly the same result (minus the overhead of the wrapping). As a nice by-product, this has also made better STOP() / RESUME behaviour possible (see below).

Tokens and Code Compression

There is still a 8192 token limit (of course!), but negative numbers now count as a single token. This seemingly small fix, along with the new character set and bitwise operators, ultimately resulted in the code compression also improving. The result is that you can squeeze in around 10% more code.

If you want to peek behind the curtain, here's the story behind that:

The first version of PICO-8 had only a single limit for code side: 15360 characters. You can still see the remnants of this when you load a cartridge ("loaded foo.p8 (1049 chars)"). Soon after, tokens were introduced as the new limit, so that there was less incentive to bother minifying code except for really heavy carts. For this to work, the character limit was increased to 64k (so that you can get more than 2 characters per token), and the code became compressed so that it could still fit in the same 15360 byte block of a 32k cartridge.

The idea was to introduce compression that was just good enough so that you'd normally hit the token limit before you hit the compressed size limit. It favored characters that were commonly used, and was intended to compress code rather than data. By virtue of being simple, it was also fast enough to compress up to 64k of code every key press, so that as you approach the compressed limit you can be altered as soon as you surpass it (which is still true).

It held up pretty well, but over time, things changed. Token counting was adjusted to solve common problems, and generally allowed more code to fit within the limit. Carts included more data stuffed into the code section, often containing characters the compressor wasn't intended for. As a result, the compressed code size limit started to become as much of a pressing concern a the token limit. Carts packed to the brim would often use both to capacity.

So, these 3 changes (in token counting, character set, and bitwise operators that cost less tokens), have put even more pressure on the compressor, and the old one just wasn't cutting it anymore. I really want to keep the token limit as the one that normally matters the most, and so better compression was in order. 0.2.0e features a code compressor that does about as well with any character subset, is decent at compressing byte-wise structured data stored in hex strings, and compresses around 10% better than previous versions.

Also, and this is a little embarrassing, I found some unused space in the 32k cartridge format that has been sitting dormant since its creation in 2014. It has been given to the code section, which is now 0x3d00 bytes instead of 0x3c00.


The tline() function ("Textured Line") is a mixture of line(), sspr(), and map().

You can use it to draw a line of pixels (same as line()), where each colour is sampled linearly from an arbitrary line on the map. It's not much use out of the box, but can be used as a low-level primitive for many purposes including polygon rendering, DOOM-style floors and walls, sprite rotation, map scaling, drawing gradients, customized gradients and fill pattern schemes. I've only played with it a little bit so far, but it's really fun, and I'm looking forward to seeing what it winds up being used for.

API Changes


Give rnd() a table as an argument, and it will return a random item in that table.

BTNP Custom Repeat Delays

From the manual:

Custom delays (in frames @ 30fps) can be set by poking the following memory addresses:

POKE(0x5F5C, DELAY) -- set the initial delay before repeating. 255 means never repeat.
POKE(0x5F5D, DELAY) -- set the repeating delay.

In both cases, 0 can be used for the default behaviour (delays 15 and 4)

Fill Patterns Constants

Use the glyphs (shift-a..z) with fillp() to get some pre-defined fill patterns.

circfill(64,64,16,0x7) -- transparent white

They are defined with the transparency bit set. You can use flr(★) or ★\1 to get 2-colour patterns.

circfill(64,64,16,0x7c) -- white and blue

Demo Carts

Most of the demos have been updated, including Jelpi which now has a few more monsters and tilesets to play with! Use INSTALL_DEMOS to get the new versions. 0.2 also features 2 extra pre-installed games: 8 Legs to Love by @bridgs, and Embrace by @TRASEVOL_DOG. You can install them with INSTALL_GAMES.

Tabs and Tabs

Tab characters are now optionally visible (but off by default). You can turn them on in config.txt
Press shift-enter to automatically add an END and indent.

Also, there are 8 more code tabs. Click the right or left-most visible tab to scroll.

Shape Drawing Tools

Both the map and sprite editors now have circle, line, and rectangle drawing tools. Click the tool button to cycle through those 3 modes, and hold ctrl to toggle filled vs. outline circles and rectangles.

Map Tile Moving

It's now a little easier to move sprites around that are referenced by the map. In the map editor, select the sprites you'd like to move, use ctrl-x and ctrl-v to move them, and the map cell data will also be updated to avoid broken references. This operation applies to the selected region on the map (ctrl-a to select half, and ctrl-a again to select the whole map including shared memory).

This operation is a little tricky, because it adds items to both the spritesheet undo stack and the map undo stack, so you need to manually undo both if desired. Back up first!


Every time you launch a BBS cartridge, PICO-8 will now ping the server to check for a newer version and prompt you to update if it exists. You can turn this off in config.txt

There's also a 'search thread' option in splore's cart menu, which will be useful for long jam-style threads in the future. And is already great for browsing the tweetjam thread! (You can go to the search tab in splore, and search for "thread:tweetjam")



The HTML exports now run a lot smoother on older machines, and with more reliable page formatting and mobile controls.

.zip File Output

A common problem when exporting cross-platform binaries, is that the machine you're generating files from doesn't necessarily support the file attributes needed to run programs on other operating system. This was especially problematic for Mac and Linux binaries exported from Windows, which had no way to store the executable bit (and so end-users would have to manually fix that). To get around this problem, the EXPORT command now produces ready-to-distribute .zip files, that store the needed file attributes when unzipped on any other operating system. As a bonus, you also don't need to bother manually zipping up each platform folder! There's currently no way to add other files (e.g. documentation) though, so in that case you might need to zip the .zip along with any other desired files.

Options menu

Binary exports now come with an OPTIONS menu that shows up when a cart is paused, and includes the same settings available in HTML exports (sound, fullscreen, controls).

Activity Log

Have you ever wondered how much time you've spent in PICO-8 editors or carts? Or which carts you've played the most? 0.2 now logs your activity to activity_log.txt (in the same folder as config.txt) once every 3 seconds (unless the PICO-8 is left idle for 30 seconds). There aren't any tools to process this data yet, but it is human-readable. I should clarify: this information is not transmitted anywhere! You can turn this off in config.txt (record_activity_log 0)

Frame Advance

PICO-8 can now be resumed from exactly the point that code stopped running. For example, if you put a STOP() in your code, and then type RESUME from the commandline, the program will continue as if the STOP() had not occurred. It's possible to type in commands before resuming to modify the state of the program though, which is useful for debugging.

A common debugging tool is to slow a game down and advancing frame by frame. You can do this by stopping suspending a program with escape, and then typing . and pressing enter. This will run the program until the next flip() call and then stop again. You can get subsequent frames in the same way, or just keep pressing enter after the first one. To add additional debugging behaviour, you can use stat(110), which returns true when running in frame-by-frame mode.

That's all for now -- I hope you enjoy 0.2 and I'll catch you soon!

-- zep

Full Changelog: (scroll down to 0.2.0 for the main changes)


Added: pack(), unpack()
Changed: bitplane read/write mask only reset after finished running program
Fixed: tline() doesn't draw anything when the layers argument is not given


Added: tline() takes an optional layers parameter, similar to map()
Added: high bits of 0x5f5e taken as colour read mask, low taken to be colour write mask
Added: Double-click in the sfx tracker to select all attributes of a single note.
Fixed: assignment shorthand RHS scope wrong when contains certain operators. e.g. a+=1&127
Fixed: while/if shorthands fail when "do" or "then" appears on the same line as part of an identifier
Fixed: ctrl-c copies the wrong sfx after clicking pencil button (next to pattern #) in organiser view
Fixed: spinning cart icon present in video memory when cart boots from splore


Added: Window title shows current cartridge filename while editing
Changed: ~ preceeding a numerical constant (e.g. ~1) counts as a single token
Fixed: >>> operator behaviour does not match lshr(a,b) when b >= 32 (again)
Fixed: PICO-8 freezes when shift by -0x8000
Fixed: .p8 format does not store extpal label colours
Fixed: Can not save screenshot when filename contains ":"


Changed: @@ operator (peek2) to %
Fixed: Exported wasm crashes on boot when code contains a numerical constant out of range.
Fixed: HTML Shell treats controller shoulder buttons as MENU; easy to accidentally bump.
Fixed: shift operators behaviour undefined for negative values of n (now: x << n means x >> -(n\1))
Fixed: >>> operator behaviour does not match lshr(a,b) when b >= 32
Fixed: INFO crashes when code is close to 64k of random characters
Fixed: Code editor undo step not stored when starting to edit a new line (hard to see what happened)


Added: zip file creation (with preserved file attributes) when exporting binaries
Added: cpu working animation when cpu usage > 120 skipped frames
Improved: stop() / resume now works at the instruction level
Fixed: tline clipping broken (from 0.2.0d)
Fixed: cpu counting is wrong inside coroutines
Fixed: coroutines interrupted by garbage collection
Fixed: code compression suddenly much worse for carts > 32k chars
Fixed: code compression ratio can be less than 1 in extreme cases
Fixed: pasting a string ending in '1' into the command prompt opens the editor
Fixed: html export can run out of pre-allocated heap when doing heavy string operations
Fixed: hex memory addresses displayed in puny font on windows
Fixed: devkit mouse message shown once per cart -- should be once per chain of carts
Fixed: can't paste sfx notes after moving to another sfx via keyboard
Fixed: copying note select vs. sfx vs. pattern range is ambiguous
Fixed: crash after redefining type()


Added: rnd(x) when x is an array-style table, returns a random item from that table
Added: gif_reset_mode (in config.txt / CONFIG command). Defaults to 0.1.12c behaviour
Added: print(str, col) form behaves the same as: color(col) print(str)
Added: Operators: <<> >>< <<>= >><=
Changed: tline now also observes an offset (0x5f3a, 0x5f3b)
Changed: tline rounds down to integer screen coordinates (same as line)
Changed: Final cpu adjustments (see release post)
Changed: Removed experimental "!"->"this" shorthand
Changed: clip() returns previous state as 4 return values
Fixed: Included files remain locked (and can not be edited by external editors)
Fixed: Carts loaded as plaintext .lua fail to handle BOM / DOS characters
Fixed: palt() returns previous state of bitfield as a boolean instead of a number
Fixed: CPU speed on widget doesn't exactly match stat(1)
Fixed: stat(1) occasionally reports garbage values when above 1.0
Fixed: Custom btnp repeat rates (0x5f5c, 0x5f5d) speed up when skipping frames
Fixed: gif_scale setting not read from config.txt
Fixed: tline: texture references are incorrect when sy1 < sy0
Fixed: tline: single pixel spans are drawn as two pixels
Fixed: binary exports' controls menu always shows 0 joyticks connected
Fixed: Pressing DEL on first row of tracker doesn't do anything
Fixed: host framerate regulation is slow (~1/sec) when PICO-8 frame takes < 1ms to execute
Fixed: fillp() return value (previous state) does not include transparency bit
Fixed: clip"" setting all clip values to 0 (should be ignored)
Fixed: Raspberry Pi static build / static export requires GLIBC 2.0.29 (now .16)
Fixed: stop(nil) crashes
Fixed: print(), printh(), stop() prints "nil" with no arguments (should have no output)
Fixed: trace() can not be used with coroutines


Changed: Compressed size limit now 0x3d00 bytes (reclaimed an unused 0x100 byte block)
Fixed: >>>= operator (was doing a >>= replacement instead)
Fixed: #including large .lua files causes crashes, weird behaviour
Fixed: Sandboxed CSTORE: writing partial data to another embedded cart clobbers the remaining data.
Fixed: Multicart code storing regression introduced in 0.2.0 (code from head cart stored in other carts)
Fixed: Can not edit spritesheet after panning
Fixed: Junk error messages when syntax error contains one of the new operators
Fixed: Crash with: 0x8000 / 1


Changed: #include directive can be preceeded by whitespace
Changed: Activity logger records nothing after idle for 30 seconds
Fixed: Mouse cursor movement in editor is not smooth
Fixed: Screen palette doesn't reset after exiting splore
Fixed: PALT() returns 0 instead of previous state as bitfield
Fixed: Rectangle and line tools broken when used in map editor
Fixed: INSTALL_GAMES under Windows produces broken cart files
Fixed: Stored multicart sometimes has code section truncated (fails to load())


Added: 8-bit character set with kana, alt font
Added: ord(), chr()
Added: SFX / Pattern organiser view
Added: SFX edit buttons on pattern channels
Added: tline // textured line drawing
Added: SPLORE automatically updates BBS carts when online
Added: Search for similar (shared tags) cartridges, or by thread
Added: predefined fillp() pattern values assigned to glyphs
Added: btnp() custom delays (poke 0x5f5c, 0x5f5d)
Added: "." shorthand command for advancing a single frame (calls _update, _draw if they exist)
Added: Current editor/cart view is recorded every 3 seconds to [app_data]/activity_log.txt
Added: Cutting (ctrl-x) and pasting selected sprites while in map view to also adjust map references to those sprites
Added: Clipboard is supported in the html exports (with some limitations) // load #wobblepaint for an example.
Added: Can load .lua files as cartridges
Added: Operators: ..= ^= \ \= & | ^^ << >> >>> ~ &= |= ^^= <<= >>= >>>= @ @@(update: @@ replaced with %) $
Added: New demo carts: waves.p8 dots3d.p8 automata.p8 wander.p8 cast.p8 jelpi.p8 (use INSTALL_DEMOS)
Added: Extra pre-installed games: Embrace, 8 Legs to Love (use INSTALL_GAMES)
Added: Splore cart labels for .p8 files
Added: Now 16 code tabs (click on the rightmost ones to scroll)
Added: ipairs()
Added: SAVE from commandline to quick-save current cartridge (same as ctrl-s)
Added: BACKUP from commandline to save a backup of current cartridge
Added: CPU usage widget (ctrl-p while running cartridge)
Added: Button / dpad states exposed in memory at 0x5f4c (8 bytes)
Added: Random number generator state exposed at 0x5f44 (8 bytes)
Added: pico8_dyn version is included when exporting to Raspberry Pi
Added: allow_function_keys option in config.txt (CTRL 6..9 are now preferred -- will phase out F6..F9 if practical)
Added: Visible tab characters (draw_tabs in config.txt)
Added: pal({1,2,3..}) means: use the value for each key 0..15 in a table
Added: palt(bitfield) means: set the colour transparency for all 16 colours, starting with the highest bit
Added: Options menu for binary exports (sound / fullscreen / controls)
Added: Shape drawing tools in sprite and map editor
Improved: Miscellaneous HTML shell / player optimisations and adjustments
Improved: Lower cpu usage for small foreground_sleep_ms values (changed host event loop & fps switching strategy)
Changed: This update is called 0.2.0, not 0.1.12d! (grew into plans for 0.2.0, and bumped cart version number)
ChangeD: Reverted cheaper 0.1.12* costs on bitwise operators & peek (recommend replacing with operators if need)
Changed: negative numbers expressed with a '-' count as a single token
Changed: glitchy reset effect does not leave residue in base RAM (but maybe on screen when using sprites / tiles)
Changed: sset() with 2 parameters uses the draw state colour as default
Changed: line() or line(col) can be used to skip drawing and set the (line_x1, line_y1) state on the next call to line(x1,y1)
Changed: vital system functions (load, reboot etc.) can only be overwritten during cartridge execution
Changed: sqrt(x) is now more accurate, and a little faster than x^.5
Changed: sqrt(x) returns 0 for negative values of x
Changed: btnp() delay and repeats now work independently per-button
Changed: pairs(nil) returns an empty function
Changed: Default screenshot scale (now 4x), gif scale (now 3x)
Changed: gif_len now means the length when no start point is specified (used to be the maximum recordable length)
Changed: (Multicarts) When loading data from many different carts, the swap delay maxes out at ~2 seconds
Changed: (Raspberry Pi) removed support for (and dependency on) libsndio
Changed: camera(), cursor(), color(), pal(), palt(), fillp(), clip() return their previous state
Changed: Can not call folder() from a BBS cart running under splore
Changed: F9 resets the video, so that multiple presses results in a sequence of clips that can be joined to together
Changed: color() defaults to 6 (was 0)
Changed: Backed up filenames are prefixed with a timestamp.
Changed: Automatically start on the (host's) current path if it is inside PICO-8's root path
Changed: tostr(x,true) can also be used to view the hex value of functions and tables (uses Lua's tostring)
Changed: Can hold control when clicking number fields (spd, pattern index etc.) to increment/decrement by 4 (was shift)
Fixed: HTML exports running at 60fps sometimes appear to repeatedly speed up and slow down
Fixed: HTML export layout: sometimes broken -- option buttons overlapping in the same place
Fixed: __tostring metatable methods not observed by tostr() / print() / printh()
Fixed: Mac OSX keyboard permissions (fixed in SDL2 0.2.12)
Fixed: Audio mixer: SFX with loop_end > 32 would sometimes fail to loop back
Fixed: btn() firing a frame late, and not on the same frame as stat(30)
Fixed: #include can not handle files saved by some Windows text editors in default format (w/ BOM / CRLF)
Fixed: Exports do not flatten #include'd files
Fixed: Default window size has too much black border (now reverted to previous default)
Fixed: Functions yielded inbetween frames occasionally push an extra return value (type:function) to the stack
Fixed: can't load png-encoded carts with code that starts with a :
Fixed: .gif output unnecessarily large
Fixed: .gif recording skipping frames when running at 15fps
Fixed: printh does not convert to unicode when writing to console or to a file
Fixed: cart data sometimes not flushed when loading another cart during runtime
Fixed: Can not navigate patterns with -,+ during music playback
Fixed: Mouse cursor not a hand over some buttons
Fixed: Laggy mouseover messages (e.g. showing current colour index, or map coordinates)
Fixed: Can't paste glyphs into search field
Fixed: Tab spacing always jumps config.tab_spaces instead of snapping to next column
Fixed: -p switch name is wrong (was only accepting "-param" in 0.12.*
Fixed: Code editor highlighting goes out of sync after some operations
Fixed: Multicart communication problem (affecting PICOWARE)
Fixed: time() speeds up after using the RESUME command
Fixed: Audio state is clobbered when using the RESUME command
Fixed: Audio glitch when fading out music containing slide effect (1)
Fixed: Toggling sound from splore cart->options menu has no effect
Fixed: Devkit keyboard works when paused
Fixed: "-32768 % y" gives wrong results
Fixed: Replacing all text in code editor breaks undo history
Fixed: Double click to select last word in code does not include the last character
Fixed: Weird block comment behavior in code editor
Fixed: HTML export: cart names can not contain quotes
Fixed: HTML export: menu button layout under chromium
Fixed: HTML export: Adding content above cartridge breaks mobile layout
Fixed: HTML export: Can touch-drag PICO-8 screen around (breaks simulated mouse input)
Fixed: LOAD("#ABC") does not always immediately yield
Fixed: Infinite RUN() loop crashes PICO-8
Fixed: Mouse cursor is not a finger on top of most "pressable" button-style elements
Fixed: CD command fails when root_path is relative (e.g. "pico8 -root_path .")
Fixed: poke in fill pattern addresses (0x5f31..0x5f33) discards some bits
Fixed: After using ctrl-click in map editor, can not modify map outside that region
Fixed: Shift-selecting sprites from bottom right to top left selects wrong region
Fixed: Changing GIF_LEN from PICO-8 commandline sometimes breaks gif saving
Fixed: pget() sometimes returns values with high bits set
Fixed: Preprocessor: unary operator lhs is not separated in some cases (e.g. x=1y+=1)
Fixed: Preprocessor: ? shorthand prevents other preprocess replacements on same line
Fixed: Preprocessor: fails when multiple shorthand expressions + strings containing brackets appear on the same line
Fixed: Loading a .p8 file with too many tabs discards the excess code.
Fixed: Map editor's stamp tool wraps around when stamping overlapping the right edge.
Fixed: Very quick/light tap events sometimes do not register
Fixed: SFX tracker mode: can't copy notes with shift-cursors before clicking (whole sfx is copied instead)
Fixed: "..." breaks syntax highlighting
Fixed: Click on text, press up/down -> cursor reverts to previous horizontal position
Fixed: CTRL-[a..z] combinations processed twice under some linux window managers
Fixed: ctrl-up/down to jump to functions in the code editor breaks when "function" is followed by a tab
Fixed: map & gfx drawing selection is not applied consistently between tools
Fixed: Using right mouse button to pick up a colour / tile value sometimes also applies current tool

P#75686 2020-05-08 19:49 ( Edited 2020-05-11 17:08)

Cart #aps-6 | 2019-12-28 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Merry Christmas and Happy Holidays everyone!

This is my cartridge for the 2019 Advent Calendar. It is a simple toy/game with no secret endings at all. Nope.

There are 26 (or more! wink wink) carts available now, and you can get the full experience by playing from @enargy's main cart. It is a truly joyful collection!

P#71381 2019-12-25 11:40 ( Edited 2020-02-01 02:36)

The BBS's media storage system has recently been updated, and image attachments are now sent to a cloud bucket. Let's stress-test it with some gifs!


  • No gif, no post!
  • No explanation of the gif is required.
  • No quality required.

To save these, I used "CONFIG GIF_SCALE 3" from the PICO-8 command prompt, but any size is ok.

Some of these are doodles, some are unfinished carts, some are abandoned projects that will only live on as gifs.

P#70602 2019-12-05 17:30 ( Edited 2019-12-05 17:33)

Cart #blocks_for_life-0 | 2019-04-30 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

At the start of each level there is a shop. You can spend hearts on 3 things:

  • Blocks: use these to build bridges, barriers, and to clobber monsters.
  • Jetpack fuel: press and hold jump while in mid-air to use your jetpack.
  • Gems: become your final score.

Life is replenished on completing each level.
Monsters also drop fuel and blocks sometimes.
You can modify your block placement with up+left/right etc.

Ludum Dare page: https://ldjam.com/events/ludum-dare/44/blocks-for-life

P#64066 2019-04-30 00:58 ( Edited 2019-04-30 01:28)

Cart #px9-5 | 2020-05-29 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

PX9 is a lightweight gfx & map compression library, intended to replace PX8. It uses the same ideas and interface as px8, but is smaller (297 292 274 tokens to decompress), and requires zero configuration.

To compress some data:

px9_comp(x,y,w,h, dest_addr, vget)

returns the number of bytes written

x,y,w,h is the source rectangle (e.g. on the spritesheet or map)
dest_addr is where to write it in memory
vget is a function for reading values (e.g. sget when compressing from spritesheet)

To decompress it again:


x,y where to decompress to
src_addr is a memory address where compressed data should be read from
vget, vset are functions for reading and writing the decompressed data 
  (e.g. pget and pset when decompressing to the screen)

Unlike px8, the vget function does not need to return 0 when x,y are outside the destination rectangle


You can use px9.p8 as a utility for compressing other carts' data by replacing _init() with something like this:

reload(0x0, 0x0, 0x2000, "mycart.p8")
clen = px9_comp(0, 0, 128, 128, 0x2000, sget)
cstore(0x0, 0x2000, clen, "mycart_c.p8")

This would compress the spritesheet from mycart.p8 and store it in the spritesheet of mycart_c.p8, using memory from 0x2000.. as a temporary buffer. See the PICO-8 Manual for more information about reload() and cstore().

In the release cartridge, you only need the code from tab 1 (px9_decomp) in order to decompress, which should be 292 tokens.

The Algorithm

PX9 tries to predict the colour of each pixel based on the values of its top and left neighbours (this is why vget() as well as vset() is needed in the decompression function). For each combination of top and left values, a list of values is stored in the order they were last encountered (a "vlist"). This means than only an index into the vlist is required to specify the output colour (or an index into a single global vlist if there are no predictions for that neighbour combination yet). Furthermore, PX9 alternates between storing spans of successfully predicted values (index==0) or unsuccessfully (index>0). For the predicted spans, only the length of the span is needed. For non-predicted spans, the length of the span, and then a prediction list index for each pixel is stored.

Both span lengths and indices are stored in the same way: a sequence of n-bit little-endian integers where n = {1,2,3..}. The stored value is taken to be the sum of these integers, and the list is terminated when the last integer has at least one bit that is not set. i.e. is less than (2^num_bits)-1

So, values are stored in the bit stream like this:

0: 0
1: 1 00
2: 1 10
3: 1 01
4: 1 11 000
5: 1 11 100
6: 1 11 010

This distribution of encoded lengths works well for pixel&map values and span lengths, as both predictions and near-predictions (index==1) can be stored with single bits, and typical source data roughly produces a log2n distribution in most cases otherwise.

Slideshow Cart

I'd like to make a pixel art slideshow cart using PX9, with around 5~10 images -- if you have any 64x64 ~ 128x128 pico-8 palette images kicking around that you would like to include, or if you'd like to make one, please email them to me! (hey at lexaloffle dot com).

felice's getval() replacement
fixed px9_comp() return value (was returning one larger than needed when aligned to 8bit boundary)

v4: // More improvements by @Felice & @Catatafish
Fixed the bit-flushing bug at EOF
Perf should be better in 0.2.0
Down to 274 tokens

P#63989 2019-04-26 18:34 ( Edited 2020-05-29 09:19)

A thread for Ludum Dare 44 this weekend. Feel free to post any updates, WIPs or meet-ups here!

Theme voting: https://ldjam.com/events/ludum-dare/44/theme

For anyone in Tokyo, Pico Pico Cafe will be open both days for ludumdarers, 10am Saturday ~ late Sunday. If you'd like to join, there is an rsvp form. (Note there is an overlapping picotachi from 7pm~ on Saturday)

P#63925 2019-04-24 08:21

Update: Download 0.2.1b for CHIP and PocketCHIP here: pico-8_0.2.1b_chip.zip

You can just unzip it somewhere and run it, but if you want to install over the default location so that the launcher buttons still works, open Terminal and type the following:

wget www.lexaloffle.com/dl/chip/pico-8_0.2.1b_chip.zip
sudo unzip pico-8_0.2.1b_chip.zip -d /usr/lib

(the default password is: chip)

Update: I've seen instances of the launcher button pointing to both /usr/lib/pico-8 and /usr/lib/pico8. If you're still getting some older version when using the launcher button (check the boot screen), use:

sudo mv /usr/lib/pico-8 /usr/lib/pico8

This is the first time I've released a build for CHIP, as they were previously handled by the late Next Thing Co. In 2016 I spent a week at their workshop in Oakland, hacking out a proof of concept along with the first version of SPLORE, so that we could see how it would all fit together. It was not a large company, but everyone I met there were stand-up hackers driven to make something new and interesting. It's remarkable what they were able to achieve, and I'm glad to be able to contribute to the legacy a little by continuing support for these devices.

Unfortunately, it seems NTC fell into insolvency with a lot of paid-for but yet-to-be-shipped PocketCHIPs sitting in storage somewhere. I know as much as the next person about this, but for what it's worth, it certainly wasn't for lack of caring about customers. If you were one of the people that got caught out, feel free to mail me (hey at lexaloffle dot com) with a screenshot of your order (and 'PocketCHIP' somewhere in the subject), and I'll send you some virtual hardware instead.

-- zep

P#63840 2019-04-22 16:05 ( Edited 2020-07-05 00:23)

Cart #pico8_0112-0 | 2019-04-16 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Hey PICO-8 people! Builds for 0.1.12 are now live on Lexaloffle and Humble. UPDATE: PocketCHIP users can get it here.

If you just want to see what's new, please scroll down a bit. But first of all, I should issue a..

Breakage Warning!

Future Compatibility: You'll need to update to 0.1.12 to play cartridges made in 0.1.12 or later. This update is another attempt at eternal future compatibility (can handle any future carts). There were a few bugs in 0.1.11g that needed a cart version bump to fix, and so I also took the chance to tweak the API (more on that below).

Backwards Compatibility: The time() function (also aliased as t() for tweetjammers) now always means time in seconds even at 60fps. This breaks a couple of 60fps carts that I know of (sorry @rez and @jobe!) but I think it's worth biting the bullet now to be more consistent and to match Voxatron's t() behaviour. With any luck this will also be the last backwards compatibility breakage.

A less disruptive change is in the music mixer: both the drop (3) and vibrato (2) effects are observed when playing an SFX-instrument. This only affects carts using SFX instruments, and which happen to have those (previously) dormant values sitting around, but I couldn't find any examples in the wild yet.

Unlimited Undo

The gfx, map and audio editors now have unlimited undo stack. Unlike the code editor which has one undo stack per tab, the other undo stacks are global to the cartridge. It also works during audio playback, so it's possible to make a bunch of changes to various SFX and/or song patterns, and then roll the changes back and forth while it is playing.


As well as diving code into tabs, it's now also possible to insert code from external text files each time a cartridge is run. This is particularly useful when using an external text editor (no need to modify the .p8 file directly), and also to share code across cartridges while still being able to modify it in one place. Note that this does not make a difference to size limits -- it is just a convenience when working with .p8 files. (When saving .p8.png, the external code is injected). From the manual:

Source code can be injected into a program at cartridge boot (but not during runtime), 
using `#INCLUDE FILENAME`, where FILENAME is either a plaintext file (containing Lua code), 
a tab from another cartridge, or all tabs from another cartridge:


When the cartridge is run, the contents of each included file is treated as if it had been 
pasted into the editor in place of that line. Normal character count and token limits apply.

SFX Snippets

Copying a range of SFXes or song patterns will now copy them into the text clipboard in a format that can pasted into other cartridges, or into a BBS post (similar to GFX snippets). To select a range of SFX or patterns, click the first one you want, and then shift click the last one before using CTRL-C. When pasted into a post, it will show up like this: (doesn't work on mobile yet)


You can copy the snippet back into a cartridge by pressing the [ sfx ] button, CTRL-C, click the destination sfx or song pattern, and then CTRL-V. Note that songs that use SFX instruments will probably not work if you paste into a cartridge that already has data in SFX 0..7.


HTML Template

The default HTML template used for exporting now includes:

  • Adaptive layout that also works on mobile
  • Touch controls
  • Gamepad support
  • A controls help menu
  • A start button with embedded preview image
  • Fixed sound under iOS
  • Integrated pause button / pause menu

The default shell and upload also works a bit smoother with itch.io now -- see the manual for uploading instructions.

WASM support

Instead of exporting a .js and .html pair, it is now possible to also generate a Web Assembly (.wasm) file which contains the main player code.


Web assembly is supported by almost all browsers and servers now, and is more compact and in theory faster to load. CPU cost seems around the same for PICO-8, but the total exported filesize when zipped is around 300k instead of 400k. This hasn't been tested much yet though, so it's not the default and is marked experimental for now.

Raspberry Pi Binary

The binary exporter now generates a Raspberry Pi binary. It is the version with statically linked SDL2 and dynamically linked WiringPi, that I believe works for most Raspberry Pi users. But let me know if you need to generate the equivalent of pico8_dyn.

-export switch

To export cartridges from commandline, you can use the new -export switch, and operate on cartridges outside of PICO-8's filesystem. The parameters to the EXPORT command are passed as a single string:

pico8 jelpi.p8 -export "-i 48 jelpi.bin"

Raspberry Pi


Serial() allows you to communicate with other devices via the Raspberry Pi's data pins (the things sticking out that various hats also connect to). There are 2 supported for now: raw GPIO accesss, and WiringPi's spi interface (not tested!). Accessing GPIO via SERIAL() is useful when higher precision timing is needed than manually POKE()ing the gpio memory addresses; transactions including delay instructions are added to a queue that is executed at the end of each frame.

Here's an example, controlling a string of 40 LEDs inside Pimoroni's plasma button kit for Picade:

Incidentally, 0.1.12 is also optimized to run well out of the box on a Picade, but more on that later!

Windowed Mode

You can now used Windows mode under Raspbian's desktop environment; Just hit alt-enter to toggle as usual. This only works in software blitting mode, so if you use "pico8 -pixel_perfect 0" it will force the the rpi driver to be used instead of x11. Running under the default driver (x11) now also resolves the issue of leaking keypresses and clicks to the desktop, but it is still present when using rpi.


Code Editor Shortcuts

CTRL-B to toggle commenting of a Block of lines
CTRL-W to jump to the start (the staWt?) of a line (CTRL-E for End of line)
CTRL-H for Hyper search -- search across tabs

Code Editor CPU

The code editor now uses less cpu by caching code highlighting information, so is noticeable when editing long files on older machines or devices with limited battery life. Napkin calculation: after 250k hours of combined use, this will save enough electricity to drive a Chevrolet EV around the circumference of the Earth once.

Blue Background

The default code editor background is now blue! If you'd like to (permanently) change it back, you can now alter it from inside PICO-8 (instead of using config.txt):


Themes only control the background of the code editor at present, but might do more in future.

Blue Dots

When cel values in the map editor have corresponding sprites with only black pixels, or when only black pixels are visible when zoomed out, there is no way to see which tiles have a non-zero value. So for these cases, PICO-8 0.1.12 now displays a single blue dot for that cel to indicate this.

API Changes

API changes that required a cart version bump:

  • divide and abs sign flipping for 0x8000.0000
  • sqrt(0x0000.0001) freezes
  • "-1"+0 evaluates to 0xffff.0001

I took the opportunity to make some final adjustments to the API and CPU counting:

  • cursor(x,y,col) can set the draw state colour
  • t() / time() always means seconds even at 60fps
  • line(x1,y1) can be used to draw from the end of the last line
  • next() can be used to write custom iterators // core Lua thing
  • Raw metatable operations: rawset rawget rawlen rawequal
  • peek2() poke2() for writing/reading 16-bit values

CPU Costs

all(), foreach() are now not much slower than pairs() or manually iterating with integer indexes. The CPU usage reporting is also slightly more accurate, but it will will never be very precise, because keeping track of virtual CPU cost can be expensive itself! And also the PICO-8 CPU costs are made up and essentially silly when looked at too closely.

Display Blitting

PICO-8 0.1.12 is now a bit better at managing scaling to different screen sizes. You probably don't need to know any of this, but here's how it works..

When possible, PICO-8 uses "pixel perfect" scaling, which means it chooses the highest possible scaling factor that is a whole number for which the PICO-8 display will fit on the screen. This means that PICO-8 pixels are a nice regular size and without blurry scaling artifacts, but for smaller screen resolutions it means you can get quite wide black boundaries.

0.1.12 addresses this by automatically choosing when to run in pixel perfect mode by default. If the size of the margins is more than 10% of the smallest screen axis, it will turn pixel perfect off. You can still force pixel perfect with "pico8 -pixel_perfect 0".

0.1.12 also introduces another setting: preblit_scale. Instead of doing a filtered scale from a 128x128 image (super-blurry), PICO-8 first performs a non-filtered scale up to something like 384x384, and then lets the platform-specific blitter stretch that instead. The default value of preblit_scale is set to automatic, which attempts to find the best trade-off between regular pixel size and pixel crispness.

On a related note, PICO-8 is now better at deciding when it is running in the foreground. There was a bug in 0.1.11g and earlier under Windows that caused PICO-8 to think it was in the background and so sleep() longer each frame. So some Windows users might notice improvement when running 60fps cartridges under 0.1.12 using a desktop-sized window (the default fullscreen method).

Search for Author

Search for carts by the same author. You can find this option under the per-cart menu (hit the menu button while the cartridge you want is selected). It will send you over to the search list, with a search phrase of "by:authorname". This also works in the BBS search bar.

Road Ahead

This will be the last major update for PICO-8's alpha, apart from some stray bug fixing. Later this year PICO-8 will go into beta with one last feature: online scores. It will take a while though, as I'm hoping to make the architecture scalable and flexible, and will take some time to get it right. The high score tables allow an extra small blob of data that can be abused to do interesting things that might not even be related to keeping track of scores :p

Until then, I hope you enjoy 0.1.12, and please post any bugs if you find them!

-- zep



Added: #include a text file, or a tab from another cartridge
Added: Unlimited undo for gfx,map,sfx
Added: [sfx] snippets: copy and paste sound & music between PICO-8 instances and BBS posts
Added: (BBS) sfx snippet player
Added: CTRL-G in code editor to repeat search across all tabs
Added: Splore search text entry with cursor key button presses
Added: Custom tab widths (tab_width in config.txt)
Added: Web exporter template: joystick & touch support, preview image, menu buttons, adaptive size, controls screen
Added: .wasm exporter (use -w)
Added: Raspberry Pi binary exporter
Added: -export // run the EXPORT command from host commandline
Added: Toggle flags on multiple sprites at once by selecting them first
Added: Confirmations when loading/saving with unsaved changes
Added: Windowed mode support for Raspberry Pi
Added: serial() interface for Raspberry Pi // serial() -- spi, ws281x, direct bit banging
Added: api: peek2 poke2 rawset rawget rawlen rawequal next
Added: Comment/uncomment selected block with CTRL-B
Added: Can save screenshots and gifs from exported binaries via EXTCMD
Added: Can exit exported binaries after runtime error / stop(), and also via EXTCMD("SHUTDOWN")
Added: SHUTDOWN menu item added to pause menu when running via "-run cartfile"
Added: -kiosk to run in kiosk mode: boot into splore, favourites menu only, no cart menu
Added: -root_path to set root cartridges folder from commandline
Added: shift+space in song view to play from the current quarter of the selected channel
Added: CTRL-W, CTRL-E in code editor to jump to start / end of line
Added: -accept_future to load cartides made with future versions of PICO-8
Added: -preblit_scale (default: auto) for less blurry scaling with -pixel_perfect 0
Added: -pixel_perfect -1 (auto) only uses pixel perfect scaling when < 10% of the containing screen axis is wasted
Added: highlight all occurances when searching for text in code editor
Added: tab completion across directories
Added: In map editor, non-zero cels that are drawn all black are marked with a single blue dot
Changed: all(), foreach() cpu cost is now much cheaper (but still a little more than using a for loop)
Changed: cursor() can also set the current color with a third parameter
Changed: stat 24..26 return -1 when no music is playing
Changed: 3x4 font characters (uppercase in ascii) allowed in code editor (but not pasteable/editable)
Changed: time() / t() always means seconds since run (but still updated once per _update() / _update60)
Changed: line(x1,y1) can be used to draw from the end of the last line
Changed: del() returns the item deleted on success
Changed: single setting for audio volume (-volume switch, "volume" in config.txt)
Changed: allow '-' in cartdat() names
Changed: 8 and - only map to buttons 4 and 5 by default for CHIP build
Changed: Raspberry Pi pico8_dyn build does not support gpio/serial (and so does not require wiringPi)
Changed: Default theme is 1 (blue background in code editor)
Changed: When loading a cart from commandline, automatically set the current path if inside PICO-8's filesystem
Fixed: Code editor uses too much cpu / battery power
Fixed: cstore() with an external cart name broken when run from exported cart or as bbs cart
Fixed: Undoing changes to SFX after using pitch drawing tool clears SFX data
Fixed: Running headless scripts under Windows / Mac OSX crashes
Fixed: Running headless scripts with no video driver fails
Fixed: Can not load BBS carts in headless script mode (without auto-running)
Fixed: (Web exporter) mouse cursor doesn't work in fullscreen
Fixed: (Web exporter) mouse button 2 brings up context menu
Fixed: (Web exporter) Clusters of FS.syncfs calls causing error messages (and inefficient?)
Fixed: (Windows) PICO-8 behaves as if it is not the foreground application
Fixed: divide and abs sign flipping for 0x8000.0000
Fixed: sqrt(0x0000.0001) freezes
Fixed: "-1"+0 evaluates to 0xffff.0001
Fixed: shift-tabbing to unindent alters selection range
Fixed: background_sleep_ms reverts to default value
Fixed: "open in thread" option appears for local carts
Fixed: (code editor) undo markers in unexpected places
Fixed: root_path, desktop_path in config.txt doesn't work without trailing slash
Fixed: Audio sampling rate is wrong when device/driver doesn't support 22050MHz
Fixed: Loading cart with less than 5 pixel rows of gfx does not clear default white cross sprite
Fixed: cpu cycle exploit using peek4 with no parameters
Fixed: SFX keyboard editing operations (e.g. SPD +/-) sometimes applied to the wrong SFX
Fixed: Cursor behaviour when moving between song and sfx view, and when playing music
Fixed: Selecting SFX notes with shift + home/end/pgup/pgdown
Fixed: Vibrato (2) and drop (3) effects in SFX instruments not observed
Fixed: Can not place note at C-0 in pitch mode
Fixed: CTRL-F search in code skips matches that are close together
Fixed: (Mac) warning about unoptimized program (built with SDL 2.0.9, + now 64-bit)
Fixed: (Raspberry Pi) Keypresses leaking to desktop
Fixed: (Raspberry Pi) Keyboard layout fixed to US
Fixed: printh(nil) prints [false] instead of [nil]
Fixed: toggling audio mute twice returns to maximum volume
Fixed: alt+cursors moves cursor in code editor
Fixed: del does not work on first character of code or commandline
Fixed: preprocessor breaks on double slash in string s="\"
Fixed: sometimes code executing a little after point of runtime error
Fixed: Token count reported in editor is more than 0 after rebooting
Fixed: "Removed empty tabs" message displayed when loading cart with fewer tabs
Fixed: Member variables highlighted when same as API function names (e.g. actor.spr)
Fixed: Hot-plugged joysticks not recognized


Added: config command (e.g. CONFIG THEME CLASSIC)
Fixed: Windows sound resampling artifacts (moved to SDL2 2.0.9 audio:directsound)
Fixed: Glyphs stored as unicode can not load when #include'd
Fixed: Code highlighting is wrong after select and delete a line
Fixed: Last line endpoint not present in draw state memory
Fixed: Ubuntu 16.04 can not run because requires glibc 2.27 (reduced dependency to 2.14)
Fixed: stat(102) returns nil when run from binary instead of 0 (now 0)
Fixed: Loading cartridge from commandline fails when path contains "../"
Fixed: (OSX) Crash when reloading external changes with CTRL-R
Fixed: (Windows) Crash when running cart with included code
Fixed: Can not export or include extra cartridges outside of current directory
Fixed: Off by 1 when search for line 1 (affected ctrl-b, ctrl-l)
Fixed: html template -- mouse cursor showing over canvas (now hidden by default)


Fixed: CPU usage reported by stat(1) is higher than actual value
Fixed: Fail to load .p8 cartridges w/ BOM marker / CRLF endlines
Fixed: Syntax errors / crash caused by #including files containing BOM / CRLFs
Fixed: Can not save .p8 when contains unresolved #includes
Fixed: Can't open pico-8.txt in Notepad.exe (added CRLFs)
Fixed: Can delete null terminator at end of code (revealing previously deleted code)


P#63583 2019-04-16 21:40 ( Edited 2019-04-22 16:17)

This is a replacement for print() that draws a customizable 5x6 font. It encodes each character as one number, and then loops through each pixel checking to see if that bit is set. So it's not very fast, but is handy if you just want a quick solution for some text larger than 3x5.

Cartridge for generating and testing font:

Cart #font_5x6-4 | 2019-01-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

The spritesheet and the convert() function is not needed in the release version of a cart. Paste the following snippet into your code (and optionally replace fdat with your own data):

fdat = [[  0000.0000! 739c.e038" 5280.0000# 02be.afa8$ 23e8.e2f8% 0674.45cc& 6414.c934' 2100.0000( 3318.c618) 618c.6330* 012a.ea90+ 0109.f210, 0000.0230- 0000.e000. 0000.0030/ 3198.cc600 fef7.bdfc1 f18c.637c2 f8ff.8c7c3 f8de.31fc4 defe.318c5 fe3e.31fc6 fe3f.bdfc7 f8cc.c6308 feff.bdfc9 fefe.31fc: 0300.0600; 0300.0660< 0199.8618= 001c.0700> 030c.3330? [email protected] 746f.783ca 76f7.fdecb f6fd.bdf8c 76f1.8db8d f6f7.bdf8e 7e3d.8c3cf 7e3d.8c60g 7e31.bdbch deff.bdeci f318.c678j f98c.6370k def9.bdecl c631.8c7cm dfff.bdecn f6f7.bdeco 76f7.bdb8p f6f7.ec60q 76f7.bf3cr f6f7.cdecs 7e1c.31f8t fb18.c630u def7.bdb8v def7.b710w def7.ffecx dec9.bdecy defe.31f8z f8cc.cc7c[ 7318.c638\ 630c.618c] 718c.6338^ 2280.0000_ 0000.007c``4100.0000`a001f.bdf4`bc63d.bdfc`c001f.8c3c`d18df.bdbc`e001d.be3c`f3b19.f630`g7ef6.f1fa`hc63d.bdec`i6018.c618`j318c.6372`kc6f5.cd6c`l6318.c618`m0015.fdec`n003d.bdec`o001f.bdf8`pf6f7.ec62`q7ef6.f18e`r001d.bc60`s001f.c3f8`t633c.c618`u0037.bdbc`v0037.b510`w0037.bfa8`x0036.edec`ydef6.f1ba`z003e.667c{ 0188.c218| 0108.4210} 0184.3118~ 02a8.0000`*013e.e500]]
for i=0,#fdat/11 do
 local p=1+i*11

function pr(str,sx,sy,col)
 local sx0=sx
 local p=1
 while (p <= #str) do
  local c=sub(str,p,p)
  local v 

  if (c=="\n") then
   -- linebreak
   sy+=9 sx=sx0 
      -- single (a)
      v = cmap[c.." "] 
      if not v then 
       -- double (`a)
       v= cmap[sub(str,p,p+1)]

   --adjust height
   local sy1=sy
   if (band(v,0x0.0002)>0)sy1+=2

   -- draw pixels
   for y=sy1,sy1+5 do
       for x=sx,sx+4 do
        if (band(v,0x8000)<0) pset(x,y,col)

The fdat in that snippet has lower case letters and a star character mapped to `a..`z and `*
Unlike print(), you need to specify all 4 parameters (string,x,y,col):

pr("`*`* H`e`l`l`o W`o`r`l`d `*`*",10,60,11)
P#60769 2019-01-13 08:50

Hey look, it's a Voxatron update!

Builds are live on lexaloffle and Humble. If you have trouble accessing your account, see this page. If you own only PICO-8, you can now update to the Voxatron + PICO-8 bundle for the difference of $5 here.

This update folds in a lot of fantasy console work, and is the first time you can see Voxatron in something similar to its final form. It has the usual trappings of a fantasy console: carts with labels (and matching .vx.png file format), a boot sequence, a SPLORE-like interface, virtual cpu limitations, and most notably, a Lua scripting API. The API is a superset of PICO-8's one and can be used to write PICO-8 style programs from scratch, or mixed with built-in engine features.

[A note for returning Voxatron users, including "Humble Voxatron Debut" customers: you can also download PICO-8 with the key that you originally purchased with. And if you don't know what PICO-8 is -- have a quick look here because it is very relevant for this update! PICO-8 started as a playground for Voxatron's scripting system, but grew into the fantasy console concept that this update is based on.]

Lua Scripting


Here's an example script to get you started. From the main menu, press escape and then select DESIGNER to start editing a new cartridge. To add a script that runs in the default room, select the "New Object" pull-down menu inside one of the Objects tabs and click "New Script". Paste the following:

function draw()
    for i=0,48,0.5 do
        local x = 64 + cos(i/16+t()/4)*40
        local y = 64 + sin(i/16+t()/4)*40
        local z = 10+i + cos(i/7+t())*3
        sphere(x,y,z, 3, 8+i%8)

You can now jump back to the room (the button at bottom left with the arrow on it), select the new script, and then place it in the room. Hit CTRL-R to run and then ESCAPE to get back to the editor.

You can build whole games from scratch in Lua (PICO-8 style), or add scripts as actor components to customize their behaviour or appearance (see Molly in the default Players folder).

Warning: Experimental!

Future versions of Voxatron will load and run earlier carts the best they can, but you should consider scripted carts made with this update to be experimental. In particular: the virtual cpu costs, sphere(), and the palette are going to change over the next few updates.

Also, there's currently no limit on allocating Lua RAM while I sort out stability issues with forcing garbage collection when the limit is reached. But this will likely end up being 4MB or 8MB, depending on what kind of carts show up. Use stat(0) to check memory usage, and feel free to ping me if you're working on a cart that needs a lot of memory so that I can take care not to break it :) (joseph @ lexaloffle)


There is currently no way to manually store data (like dset / dget), but this will arrive during 0.3.* updates along with directly managing the savegame states. In 0.3.5, data created in Lua is automatically stored with a savegame by walking the global table and writing values and tables that aren't prefixed with a single underscore. References to functions are also stored if they existed at boot.

There's also no binary exporter yet. Exporting stand-alone carts is planned for future updates, but I don't have an eta yet.

PICO-8 Cart Support

In one of the Objects tabs, you can import .p8 files using the "Load Item Into Folder" button, and it becomes an object you can place in the room. Because the API, palette and display dimensions are all super-sets of PICO-8's, most cartridges will run with little or no modification. You can use set_draw_slice(z) to indicate which 128x128 slice should be drawn to. By drawing layers multiple times, and using the PICO-8 camera mode (in the room properties top right), you can make thick 2D games. Here's a quick test with Celeste:

Even though Voxatron and PICO-8 now share a lot more in common, I don't expect them to compete with each other. Voxatron is much more complex, and better suited to different kinds of projects. But it is still fun to fool around with PICO-8 adaptations and view old code in a new light.

Cartridge Format

Cartridges are now called .vx.png and encode data in the low 4 bits of each RGBA channel. They are stored in a staggered order to reduce visible artifacts.

The size limits are lot more relaxed than PICO-8. It is possible to have cartridges up to 1MB compressed, which is around twice the size of the current largest carts. Carts under 256k compressed appear in the png as a single cartridge like the one below, and then extra data >256k is added underneath if needed. The empty label space at the bottom will be for Title and Author in future.

Note that Voxatron cartridges have two labels -- there's the preview screenshot that shows up in the BBS player that you can grab with F7. But also an optional (but recommended!) 60x32 image that shows up in splore that can be edited in the Metadata tab. Perhaps in future we should just let anyone jump in and draw missing labels for any cartridges.

Looking Glass Support

Voxatron now runs on the Looking Glass: a real holographic display! Each frame, the virtual Voxatron display is rendered from 64 different angles, and then weaved into special format that, when viewed on the Looking Glass, gives the appearance of a solid object floating in space. You'll notice that footage of the display often has the camera moving left and right so that you can see the parallax, but in person you can keep your head still and get perfect binocular agreement without any glasses or head tracking.

The Looking Glass is now available and comes with a Voxatron license key, along with an Application Browser that includes a special edition of the new SPLORE for easy access to your favourite carts. For more videos and information, have a look at the Looking Glass website.

I'm also working on support for the Voxon VX1, but more on that later!

Microscripting and Actor Properties

The microscripting and actor editing tools have been completely reworked to be cleaner and more consistent. Microscripting events are also more predictable. For example, there is always exactly one frame that many event conditions are true in order for scripts to react to them via a single update() call: being killed, collected or entering or exiting room. This works regardless of the order that actors are defined, spawned, or are processed.

The Manual is still a little sparse on details, but I'll be rolling out some more demo carts and documentation in January.

Here's a changelist:


Added: gif saving
Added: button states via player object: pl:button(n)
Added: set_room()
Changed: Player 1 responds to keyboard controls even when control is set to gamepad
Changed: ESC immediate exits when running a cartridge from designer
Fixed: set_world_camera was only taking effect at the end of the frame
Fixed: t() // component time (in seconds) or room time if not inside a callback
Fixed: box() not drawing and kills cpu
Fixed: resource reference sometimes fails when in string form
Fixed: STATE:EXITING microscripting event not shown correctly in menu
Fixed: Removed unused config.txt variables
Fixed: (Windows) missing DLL


Added: Lua scripting
Added: PICO-8 cart support
Added: Splore // replaces BBS CARTS naviagator
Added: Custom labels (with new cart format)
Added: Boot sequence
Added: Extended palette
Added: Alpha demo carts: Hug Arena, Gallery of Curiosities
Added: New object editor with new attributes and behaviours
Added: New microscripting events and activation controller
Added: Looking Glass support
Added: Deep snow and trails
Improved: RAM usage
Improved: Rendering speed
Fixed: Collecting an item with external ammo does not apply collected quantity
Fixed: Patrolling monsters turn when blocked on sides (should only be when blocked in front)
Fixed: Crash when loading very old cartridges using a 64-bit build
Fixed: Jitter when scrolling single player even width / length
Fixed: [many bugs]

Have fun, and I hope you have a great new year!

P#60448 2018-12-31 06:00 ( Edited 2018-12-31 06:11)

Cart #bingle_jells-2 | 2018-12-24 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Ring all of the bells in each level to progress -- but be careful not to stand too close!

This cart is my contribution to the Advent Calendar 2018. I think it turned out well as a wee concept game, but it's really the equivalent of a hastily wrapped box of chocolates purchased at 3am on Christmas morning from the closest gas station, compared with the amazing work that can be found in the calendar. Try out the other 24 games here if you haven't already:

Cart #pico8adventcalendar2018-31 | 2018-12-25 | Code ▽ | Embed ▽ | No License

(or browse them in the main Advent Calendar Thread)

Thanks to everyone for the chance to join, and in particular @Bigaston for putting the whole thing together, and @2darray for making the rad menu cart and updating with work-arounds for the janky BBS. Making PICO-8 carts myself often gets pushed aside by more urgent things, and I really enjoyed the chance to make something for kicks again. I'm looking forward to more carts and collaborations next year!

P#60337 2018-12-25 06:36

I never imagined I'd be excited about releasing a website update, but here it is! This update addresses many ancient bugs and issues, but also aims to support the PICO-8 / Voxatron fantasy console ecosystem. There are new features to make collaboration, sharing, teaching and exploring carts a little easier.

lexaloffle.com is now also running on a new server, on top of a leaner stack that should be much more responsive. Along with a lot of new code running underneath it all, there will still be some new bugs to deal with (apologies to those who were around earlier this week for the bumpy migration process!) -- feel free to report any issues in the comments here, or in the PICO-8 bugs sub-forum.

New Features


View a feed of everything going on using the Superblog. You can also follow other users to create a tailored feed.

Featured Carts

The list of featured carts (same as in SPLORE) is now sorted by the time each cart was added to the list, so that it's possible to come back periodically and see what's new without digging too much for notable releases. Selection will be based on a combination of user interaction, manual curation, and the phase of the moon. To kick things off, the first few pages of the old featured lists will be fed through a few carts per day.

Featured cartridges also now show up on the main PICO-8 product page. I went with a whirlpool format, where newly featured carts start out big on the left and then get sucked down.

(this screenshot is from my test server -- you can see the live version here)

Custom Cart IDs and Versioning

When submitting a cartridge, you can now choose an alphanumeric id, for example: "spooky_forest". A revision number is automatically appended to the id: "spooky_forest-0". To refer to the most recent version of a cart, you can optionally use the id without the revision number: LOAD("#SPOOKY_FOREST") will download the most recent version.

Unlisted Cartridges

Unlisted carts can now be played online by anyone who knows the id: https://www.lexaloffle.com/bbs/cart_info.php?cid=silly_tree

This can be useful if you want to send someone (or yourself) a cartridge in a semi-private way. The id defaults to a relatively non-guessable string for this reason.

Cart Menu

The cart player now has an extra pull-out menu (top right) that displays more cartridges by the same author, along with some featured carts and a random cart for good luck. This selection is not currently aware of context (e.g. which carts you already visited), so it's not a great way to surf around more than a handful of carts, but I'm hoping it will draw at least a few hapless visitors into the rabbit hole.


If you'd like your cartridge to be embeddable on other websites, there is now an option on the submission page, or enable it on existing carts by pressing the 'edit' link under the cart player.


Each thread has a little notification button that can be toggled:

Any new replies to a thread you are subscribed to, or any @ mention of your username (e.g. @zep) will trigger an email notification. These can be muted with a global option under Settings if they become annoying.

Drafts and Unlisted Threads

New posts can be saved as a draft, and then retrived from your profile page under the 'Posts' section.

If you would like to create a thread that can be viewed via a secret url, you can also create an unlisted thread. Mentioning another user in an unlisted thread will only notify them if they have already posted there. Unlisted threads are handy for things like allowing other people to comment on drafts, semi-open invitations to collaborate or test ideas, and class / workshop threads where participants can share their work without having to make a more visible BBS thread.

Community Tags

Community tags can be added to any post by any user. There are just two tags for the moment:

  • Posts tagged with Mature Content will not be visible in SPLORE when the content_filter is set to 2 in config.txt (this will be easier to set up in future!).

  • Post tagged as spam will go under review to be removed. If your account is older than the posts account when you flag it as spam, the post contents are instantly hidden (plus a few minutes for caching to catch up) until it is reviewed. This is to limit the potential for shenanigans from relatively new users.

User Profiles

If you look under your Settings page, you'll find a place to put a homepage link, plus any social media account names. These show up as little buttons under your name, and at the top of your profile page. There are also options to make your likes and/or favourites lists public from your profile > Carts page.

In the pull-down menu next to each post you can also find an option to pin up to 3 posts to the top of your profile. Alternatively, whole playable cartridges can be included in the "About" field using [# followed by the cart id, followed by #].


Unfortunately there seems to still be a bunch of sleeper spam accounts to be weeded out over time, but it now a little harder for spammers to join up:

To be honest, this is not a very difficult CAPTCHA to defeat, but I'm counting on it not being worth any potential spammer's time to solve it just for one website. And if it came to it, I think we could make new carts faster than spammers can automate their solutions. (SPAMJAM?)

New Cart Players

Both the Voxatron 0.3.5 and PICO-8 0.1.12 players are live! There isn't much to see yet except for a new boot screen in Voxatron, but both players are needed before the binary updates are available to handle newer BBS features. But updates for both are also around the corner.

Missing features

Some things didn't survive the migration (yet), or are unfinished:

  • The 'Code' and 'Copy' buttons on the cart players are missing. I don't think we need copy anymore, because it is easier just to LOAD("#FOO") from inside PICO-8. I miss the Code button, which will return at some point, but possibly in a different form.

  • The GFX, SFX snippets and Tutorial sub-forums are empty because they're new. I've re-organised the way sub-forums are presented (now under 4 broad categories: Carts, Community, Snippets and Support), and the old Graphics and Music subs didn't fit very well. They only had a couple of pages of posts each, so I've bumped them into their respective authors' blogs for now.
P#59457 2018-11-29 18:42 ( Edited 2018-11-29 18:49)

Hey Everyone! PICO-8 0.1.11d builds are now live on Lexaloffle and Humble! We are still working on CHIP / Pocket CHIP builds -- I'll update this thread when they are live. [Edit: they're live now with 0.1.11g]

Welcome to the Core

Despite the unassuming version number of 0.1.11, this update marks something of a milestone: The core of PICO-8 is now feature-complete, with API and specifications that are likely to remain fixed. Before it becomes entombed as a read-only blob of C code however, there is still some time before beta to address any issues that crop up. Let's see how 0.1.11 works out and what points of friction emerge.

One of the goals of PICO-8 is to create a stable, familiar medium in contrast to the shifting sands of modern software development. Instead of growing by changing the core of PICO-8 over time, I'm aiming to settle on a minimal, eternal component that can be built on top of (improved tools and bbs integration), extended sideways (extra ports / host platform support), built out from the inside (making useful snippets and carts!), and around (nicer BBS, cartverse, documentation, resources and community events).

v0.1.11 is also the point after which PICO-8 and Voxatron co-development start to part ways -- Voxatron's API and specification is a superset of PICO-8 v0.1.11's. The upcoming Voxatron update looks basically like a 3D PICO-8, with its own version of splore, png cart format, labels, and bbs integration. I messed up the Voxatron release plan partly because of committing to this -- but more on this later in a separate post. o(_ _)o

Many thanks to the numerous PICO-8 users who helped iron out bugs in the 0.1.11 release candidates. I snuck 0.1.11 out via twitter thinking it was pretty solid, but it took 3 more builds to get right. If you find any old carts that don't run or behave strangely, please ping me on twitter, or better still, post a bug report in the support forum. There will be another follow-up (0.1.12) to catch any left-over issues. After that it will be onwards to beta (0.2.0) \o/

Also special thanks to Gruber for help with the SFX editor, rez for helping shape fill patterns & cpu changes, and everyone who posted thoughts and suggestions on the BBS -- many of which I folded into this update. I haven't posted much this year due to going into blinkers-on just-make-the-thing mode, but I do read and appreciate every piece of feedback. I'll be re-visiting some older posts to update how things have turned out, and I'm also looking forward to joining the party and making some more carts too :D

New Features

Binary Exporters

PICO-8 can now generate stand-alone, distributable binary versions of carts and multicarts for Windows, MacOS and 64-bit Linux (dynamically linked with SDL2). Use the export command with a .BIN target, with the -I switch to choose an icon (or skip to use the cart label by default):


Multicarts can be created the same way as exporting HTML -- just add up to 15 .p8 or .p8.png filenames at the end of the EXPORT command. Bundled carts behave just the same as local files -- they can be RELOAD()ed, CSTORE()ed to, and chain loaded with LOAD(), using the new breadcrumb and parameter features explained below.

SFX Instruments

Until 0.1.10, each of the 32 notes in a SFX were internally described with 15 bits: 6 for pitch, 3 each for instrument, volume and effect. 0.1.11 adds one extra bit to round out the 2 bytes: "SFX instrument mode" that can be set by toggling the button to the right of the instruments list.

When it is set, the instrument buttons turn into indexes 0..7, and when placing notes you'll see the instrument index appear green instead of pink. Instead of playing the built-in instrument, these notes will trigger the SFX of that index. In other words, SFX 0..7 are acting as instrument definitions. Each note will advance at the same speed as the definition, with the pitch shifted (relative to C-2), the volume multiplied, and the effects layered on top of each other. This can be used to reach a greater range of pitches, create per-note changes in texture and tone, and set up detailed volume envelopes.

Here's a rundown of other new SFX editing features, and a quick introduction to SFX instruments by Gruber (check out the other tutorials too!):

Fill Patterns

Along with SFX instruments, fill patterns are a late addition to the PICO-8 spec. In both cases I was planning to keep them as secret features, but they turned out to be too much fun and I couldn't wait! From the manual:

fillp p

    The PICO-8 fill pattern is a 4x4 2-colour tiled pattern observed by:
        circ() circfill() rect() rectfill() pset() line()

    p is a bitfield in reading order starting from the highest bit. To calculate the value
    of p for a desired pattern, add the bit values together:

        |32768|16384| 8192| 4096|
        | 2048| 1024| 512 | 256 |
        | 128 |  64 |  32 |  16 |
        |  8  |  4  |  2  |  1  |

    For example, FILLP(4+8+64+128+  256+512+4096+8192) would create a checkerboard pattern.

    This can be more neatly expressed in binary: FILLP(0b0011001111001100)
    The default fill pattern is 0, which means a single solid colour is drawn.

    To specify a second colour for the pattern, use the high bits of any colour parameter:

        CIRCFILL(64,64,20, 0x4E) -- brown and pink

    An additional bit 0b0.1 can be set to indicate that the second colour is not drawn.

        FILLP(0b0011010101101000.1) -- checkboard with transparent squares

Code Tabs

You can now organise your code into numbered tabs. They are not separate files, but rather the same block of code chopped up with special markers (internally: "-->8"). Hovering over a tab number displays the first line of code if is commented, which can be used as a makeshift method of naming tabs. To remove the right-most tab, just delete all of the text in the tab and then move off it.

Editing operations like undo, search and selections apply per-tab. It isn't currently possible to search across tabs -- this will be added later along with improved error messages that span multiple tabs.

Commandline Scripts

The new -x parameter to PICO-8 can be used to run carts as part of commandline tool chains. For example, if you have a long-winded process for copying data around and generating large multicarts, you could automate the process by creating a single cart that does the job:


And then run PICO-8 from commandline:

$ pico8 -x build.p8
EXPORT /home/zep/pico8/carts/myproj/mygame.bin -i 1 level1.p8 level2.p8 level3.p8

This will execute each line of build.p8 as if it had been typed in from a fresh boot of PICO-8, but without ever opening a window. It isn't truely headless yet because it still requires SDL2 (along with the video/audio driver) -- e.g. you can still play sound from it. I'll look at improving this in the future for people who want to make twitter bots and whatnot.

HTML Templates / Plates

This is still a work in progress as I don't have any sample plates to offer yet! But the basic concept works: you can put html files in {app_data}/pico-8/plates, and use them as templates for the html exporter. The template should include a magic string ("##js_file##") in place of the accompany javascript file's name:

<script async type="text/javascript" src="##js_file##"></script>

The template (in this example, one_button.html) can then be used when exporting like so:


The P is for 'Plate'. I use this more general term because they can act both as templates (custom control schemes like single-button, or to add technical javascript features) and also as faceplates (custom graphics around the PICO-8 screen e.g. based on the theme of the game). When doing the next round of website updates, I'll look at creating a way to submit plates as a community resource.

It is also possible in 0.1.11 to export the .js file separately (EXPORT FOO.JS) so that it is easier to work on the accompanying .html in the same folder as the exported cart.

Splore Menu

An extra per-cart menu can be accessed from splore by pressing the menu button (X and O still immediately launch the cart as before). This menu allows you to open the cart's BBS thread, remove it from favourites, and open a minimal options menu. The options menu includes SHUTDOWN which allows PICO-8 to be used from start to finish with only a controller (in -splore mode).

Extra splore tip that I forgot to mention in the docs: instead of typing SPLORE, you can use just S.

API Changes

  • add() returns the value that was added
  • assert() can take an optional error message parameter
  • coresume() returns an error, making it useful to wrap with assert: assert(coresume(foo))
  • getmetatable()
  • sfx() takes a 4th parameter: number of notes to play

Time and Date

You can now grab the current local and GM time with stat():

        80..85  UTC time: year, month, day, hour, minute, second
        90..95  Local time

Check out the ClockJam!

Cart #45944 | 2017-11-06 | Code ▽ | Embed ▽ | No License

CPU Costs

There are many adjustments to the cost of calling api functions in 0.1.11. Some of them are due to fixing bugs including the ability to trick PICO-8 into giving back unlimited CPU cycles (!), some are to make costs feel more consistent with each other, to more accurately reflect the real world cost of the host machine (pffft -- like that matters), and finally to give a small bump to graphically intensive carts now that making 60fps carts is becoming more common.

I've tried to tread lightly on the heavy optimisation work done by cartridge authors. For example, kragzeg's technical articles on Dank Tomb rendering are still true. The general rule is that existing carts will run around the same speed as before, or a little faster depending on the operations they use. In a few rare cases they run slightly slower, and I am humbly offering low-cost pattern filling as compensation :P

  • Horizontal scan fills are now super-fast (rectfill, circfill)
  • sspr() is now the same speed as spr() per-pixel
  • line() is faster -- but better to use rectfill() if axis-aligned
  • bnot() and peek() cost 1 lua vm instruction more
  • Fixed cost calculation of clipped gfx operations

Cartverse Preparation

The PICO-8 cartverse is a collection of interconnected webs of PICO-8 cartridges that can (optionally) exist independently of the BBS, and in the future the BBS will provide entry points to the cartverse rather than being a container for it. This update includes some of of the features needed to achieve this, and the are also useful separately:

BBS Cart Loading

Use LOAD("#45481") to load a cartridge directly from the BBS. The number can (and normally should be) the containing post id, (not the id of the cart itself), in which case the most recent version of the cart is fetched. This can be called from a running cartridge, in which case the cartridge is immediately launched.


Breadcrumbs allows the user to return to previous carts, much like the back button on a web browser. When LOAD()ing a cart, a second parameter can be used to request that the launched cart inserts an option in the pause menu to get back. The value of the parameter is the label of that button:


Parameter Strings

The third parameter to LOAD() is an arbitrary string up to 1024 chars long that can be read by the receiving cart with STAT(6). When using a breadcrumb to get back to a cartridge, the parameter that cartridge was initially run with is restored.

The parameter string can also be set with RUN from the commandline: RUN BLAH DE BLAH

Custom BBS Functionality

This isn't a feature by itself but can implemented using these new features. Because the cartverse sits alongside the BBS, it will be (and maybe already is) a viable way to extend the functionality of the BBS. For example: when hosting a jam, instead of having customized web-based theme selection, cart listings and voting, we can do it all with carts. An invite cart could have a countdown clock + a link to a separate theme voting cart when it becomes available, and then afterwards a voting cart could link to all the entries and store results voting on itself. There isn't yet a tidy way to send data back to the jam host, but there will be later! I will try this out for P8JAM3

Cart #45507 | 2017-10-27 | Code ▽ | Embed ▽ | No License




    Fixed: time() always returns 0 when there is no _update function
    Fixed: (raspi) Keyboard stops responding after pressing CTRL-F, CTRL-Z
    Fixed: (raspi) Double keypresses in sound editor when entering notes
    Fixed: stat(6) pads parameter string with spaces


    Added: Local and UT time queries using stat()
    Added: host_framerate_control (config.txt) to improve performance on slower machines and web 
    Added: Control over cpu useage when running in background (-background_sleep_ms / config.txt)
    Added: Windows icon in exported exe
    Added: F11 to toggle fullscreen
    Added: export -c switch to indicate transparent icon colour 
    Added: show_backup_messages (config.txt) to turn off backup notifications
    Added: SFX instruments documentation in pico8.txt
    Added: Error message when trying to export carts with code size over the compressed limit
    Changed: If config.txt is not found, the same directory as the executable is searched
    Changed: If sdl_controllers.txt exists in the same directory as the executeable, it is processed first
    Changed: Shorthand if () statements must be written on a single line
    Fixed: reload() from bundled, non-primary cart in exported html multicart reads only original data
    Fixed: Exported binaries wrongly observe F7 (capture label)
    Fixed: Loading carts from earlier versions alters SFX data not intended for audio
    Fixed: Old version of fill patterns documentation near end of pico8.txt
    Fixed: 'backed up unsaved changes' message displayed during runtime for cstored() carts
    Fixed: PICO-8 runs too slowly when in background (new default background_sleep_ms: 20)
    Fixed: Saving screenshots and videos from exported binaries are named 0_*
    Fixed: Compressed size limit warning on save doesn't mention exported carts
    Fixed: btn(), btnp() don't work in infinite loops
    Fixed: btnp() timing inconsistent between 30fps / 60fps / during frame-skipping / with no _update
    Fixed: Can't move between channels while music is playing in song mode


    Fixed: Preprocessor bug regressions: "if (..) or", "a.b -= c - d"
    Fixed: Crash when pressing menu button on an empty favourites list


    Added: Binary exporters (Windows, Linux, Mac OSX)
    Added: Code tabs
    Added: Splore cart menu
    Added: Fill patterns
    Added: Custom sfx instruments
    Added: load("#1234") to load [and run] a BBS cart
    Added: -x switch // execute a cart headless, for making command-line tools
    Added: Compressed size display and limit warning lights in code editor
    Added: CTRL-L to jump to a line number in code editor
    Added: numbers can be written in binary: 0b10100010 
    Added: tostr(), tonum()
    Added: extcmd(): audio_rec, audio_end to record all audio output.
    Added: ls() returns a list of local files if called while running
    Added: getmetatable()
    Added: coroutine error reporting // wrap coresume() in assert()
    Added: sfx() can take a 4th parameter: number of notes to play
    Added: Live sfx and music editing + better navigation controls
    Added: Transpose selected sfx notes relative to C by entering a note w/ SHIFT held
    Added: Insert and delete sfx rows with enter and backspace
    Added: Hidden note data is shown in sfx editor when relevant (slide, arps)
    Added: Warning displayed when unsaved changes backed up
    Added: Separate animation for downloading vs. loading a cart
    Added: export -p switch to supply a customized html template 
    Added: Mousewheel when devkit mouse enabled: stat(36) // not supported in web
    Added: < > to change zoom level in gfx and map editors
    Changed: Rebalanced / fixed api cpu costs
    Changed: Screenshot and gif filenames based on current cart if available
    Changed: add() returns the added object
    Changed: removed global hpf on audio
    Changed: (sfx) can slide to volume 0
    Changed: removed master low pass filter
    Changed: assert() can take an optional error_message parameter
    Changed: ? (shorthand for print()) can be prefixed by whitespace 
    Changed: shl(), shr() return 0 if second parameter >= 32
    Changed: Automatically drop down to software blitting mode if opengl fails
    Changed: Lua memory limit set to 2MB (was 1MB)
    Changed: Some options (-width, -show_fps) apply only to the session; not saved to config.txt
    Updated: Internal game controller mappings from SDL_GameControllerDB
    Fixed: Pops & clicks in audio when switching between playing SFX
    Fixed: Crash in audio mixer because of bad locking
    Fixed: Crash when loading .p8 files with more than 64k of code
    Fixed: Indexing of sparse tables fails after removing n/2 elements
    Fixed: Calling stat() inside an infinite loop crashes
    Fixed: Resetting cartridge corrupts cartridge data in range 0x5e00..0x5eff
    Fixed: Can not recover from a cart error caused by glitchy data on resetting 
    Fixed: String->negative number conversion off by 0x0.0001 (-1 --> 0xffff0001)
    Fixed: Crash when running cart closed to 64k char limit
    Fixed: Cursor can't move to the right of last character in code editor
    Fixed: Missing highlighted keywords: in, add, del, menuitem
    Fixed: Preprocessor bugs: "a+=1+2\n*3", "a+=(1)ba=42", "a[(1)]+=1"
    Fixed: Preprocessor performs replacements inside a string printed with ?
    Fixed: Display freezes when terminating a program running at >100% cpu
    Fixed: Quick-running (CTRL-R) clobbers some editor state (e.g. current sprite page)
    Fixed: Loading a .p8 file with a future version reports a generic failure
    Fixed: alt-enter to toggle fullscreen also triggers pause menu
    Fixed: Splore scrolling jumps around when list gets too long

P#46039 2017-11-09 03:15 ( Edited 2017-11-09 08:15)

A heads up for Voxatron users -- the first version of the Lua api will be out next week in 0.3.5!

Pictured above is the result of drawing voxels directly into a room's map. The 0.3.5 api also provides access to actor attributes and state, spawning, camera control, and direct access to the display. The entire PICO-8 api is in there with some 3D counterparts (line3d, box, sphere), and it's possible to import a pico-8 cart into the resource tree, place it in a room, and run the cart on a single slice of the display. The .p8 cart shows up in the resource navigator, and is placeable in the room like this:

The code can also be edited to make slight adjustments for the 3d display:

In other news, I've updated the website with mobile-friendly cart listings and touch controls for the carts. It's still a work in progress -- the sound in particular is very choppy or missing altogether. But apart from that it is quite useable. If you have a modern phone or touch device please try it out!

P#34309 2016-12-27 14:46 ( Edited 2018-11-21 03:45)

Hey All -- PICO-8 0.1.10 builds are now live on Lexaloffle and Humble!

Update: 0.1.10b is up with bugfixes for the html exporter. (Changes)

Update2: 0.1.10c is up with fixed atan2()

Multicart Exporter

The EXPORT command can now be used to create a single .js (and .html) file that contains more than one cart. All of the carts can read, write, and run each other as if they were local files loaded from PICO-8. To do this, add the names of up to 15 extra cartridges you'd like to include in the export: (.p8 format only in 0.1.10)


Inside the program, you can then use RELOAD() to grab data from other carts:


Or load and run other carts:


CSTORE() also works in this context, either for a cart to save over itself or to write data to other carts. Each time a different cartridge is accessed, you'll see the spinny cart animation to show that a swap is taking place.

Multicart exports offer a way to package and distribute what you can already do with local files (e.g. zipping up a group of carts), but isn't supported on the BBS and probably never will be. I think feeling invited to design for single 32k carts is an important aspect of PICO-8, so separating multicarts to the exporter is a way to preserve that to some degree while still broadening the scope of what can be made with PICO-8. Future binary exporters (Windows, Mac, Linux) will also support multicart in the same way.

Glitchy Reset

Resetting via the pause menu (press enter) now corrupts the ram in a semi-realistic way for a moment, just like some old hardware might. Carts glitch out in different ways depending on how they use the RAM! Here's Mistigri:

New Demo Carts

Use INSTALL_DEMOS to add BOUNCE.P8 and SORT.P8. These are intended to be useful for teaching basic programming and computer science concepts. Eventually PICO-8 will come with a bunch of printable lessons that refer to the built-in demos.

Code Editor

You can select and then tab / shift-tab to control indentation the selected lines of code. Also double-click to select a word, and ctrl-left/right skips across words.


This is function can be used to control taking screenshots and videos at precise times from within the code. From the manual:

    extcmd x

        Special system command, only works when running a local cart. 
        Where x is a string:

        "label"  set cart label
        "screen" save a screenshot
        "rec"    set video start point
        "video"  save a .gif

Raspberry Pi Improvements

0.1.10 now includes wiringPi statically linked (for gpio), so you shouldn't need to install anything else in most cases. The dynamically linked binary is back too.

I couldn't get the X11 driver to work with gles, so it defaults to rpi without windowed support. If anyone is keen to try building their own SDL2 with working X11 support, you can run pico8 with:

env SDL_VIDEODRIVER="x11" ./pico8_dyn

The mapped keyboard events for text input (SDL_TEXTINPUT) also seems to be broken for some raspis (so far observed on 2nd generation units), so 0.1.10 now detects if this is happening and uses a hard-coded US layout based on keydown events instead.

Full changelog:


    Added: Multi-cart export in html
    Added: Cart reset glitch
    Added: Demo carts: bounce, sort
    Added: .p8 format can now store cart labels
    Added: Splore navigation keys: pageup/down, home, end
    Added: Splore useage hint shown on empty favourites list
    Added: Warning on boot when data folder is read-only or can't be created
    Added: Pressing tab with code selected indents those lines (shift-tab to un-indent)
    Added: Double click word to select it
    Added: Trigger screenshot/video/label capture from inside program: extcmd()
    Changed: CTRL+left/right in code editor skips to end of word or span of non-whitespace
    Changed: When a cart terminates from splore, button press is required to continue
    Changed: load("@clip") can only be called from commandline (security)
    Fixed: Can over-allocate host memory if exceed it within one frame
    Fixed: atan2(-1, -32768) crash, and error for small values of dy
    Fixed: (Web) using cstore() on self causes unloadable cart (bug introduced in 0.1.8?)
    Fixed: (web) Pressing ctrl-v crashes the player (should do nothing)
    Fixed: (Raspberry Pi) WiringPi library required in static build
    Fixed: (Raspberry Pi) Crash on exit when launching via desktop icon
    Fixed: (Raspberry Pi) keyboard input broken (observed on raspi2s)

P#33172 2016-12-07 15:07 ( Edited 2016-12-07 20:07)

PICO-8 0.1.9b builds are now live on Lexaloffle and Humble.

This is a bug-fixing update, mostly for crashes related to switching between widowed mode, full-screen and minimized windows. I've also included the dynamically linked pico8_dyn versions in the linux archives, that were missing from 0.1.9.

The Windows installer & .zip file include a more recent sdl2.dll, although there weren't any known issues relating to that.

I've switched back to shift-a..z for glyph entry in the code editor, as alt-a..z is sometimes reserved by the host operating system. If you find yourself accidentally entering the extended characters by accident, you can turn this off in config.txt (near the bottom). To enter glyphs without shift-a..z, press ctrl-k to toggle glyph mode.



        Added: Alternative function key mapping: ctrl-6..9 for F6..F9
        Added: Alternative glyph entry method: (ctrl-k) to toggle glyph mode
        Changed: Enter glyphs with shift a..z, but can be disabled in config.txt 
        Changed: Increased emscripten ram to 128MB (some carts at risk of running out)
        Fixed: Crash when window size is tiny or minified
        Fixed: Crash on toggling fullscreen mode
        Fixed: printh can write files outside filetree (security issue)
        Fixed: show_fps (can also now be toggled with ctrl-1)
        Fixed: Shorthand if/then syntax error when using the form: (functionname)(param)
        Fixed: log.txt not saved in path specified by -home switch
        Fixed: Default application data folder created even when -home specified
        Fixed: Missing dynamic builds (pico8_dyn) from linux archives
        Fixed: Removed unneeded RPATH from linux binaries
        Fixed: export foo%d.wav fails to write multiple files 
P#30148 2016-10-06 18:20 ( Edited 2016-10-06 22:20)

Hey All -- PICO-8 0.1.9 builds are now live on Lexaloffle and Humble!

Posting Carts via Clipboard

The handiest new feature is being able to post cartridges to the bbs via the clipboard, without ever saving it as a png. Use "SAVE @CLIP" to copy to the clipboard as text, and then paste it into a post (hit Preview to make sure it worked and to get rid of the wall of text). You can also copy carts from the BBS (look for 'Copy' under each cart) and paste it back into PICO-8 with "LOAD @CLIP")

Posting GFX via Clipboard

You can also do the same thing with sprites. Using CTRL-C in the sprite editor also stores a copy of the sprites as text in the clipboard, and can be pasted back and forth to BBS posts. Here's an example: (click the 40x8 and then CTRL-C the text to copy&paste it back into a cart)



There's a new category in the BBS called Jam, which shows up in SPLORE. The Jam sub-forum (along with clipboard cart&gfx pasting) will be useful for things like the Tweetjam thread and for having a natural place to discuss / post ideas for external jams like Ludumdare.

I originally envisaged Jam-related stuff going in Collaboration, but I think Jam can grow into something quite worthwhile and separate. Collaboration will also be extended at some point to include a 'snippet library' of re-useable pieces of code/gfx/audio, which feels quite different from jamming.

Raspberry Pi GPIO

If you have a Raspberry Pi and an LED, try jamming one end into GPIO1, and the other one into GND, and you can make it blink on and off with POKE(0x5f81,255) and POKE(0x5f81,0). Note that you'll need to run PICO-8 as root: sudo pico8


Exported html can now run at 60fps. To improve performance, the web player now always runs on a 128x128 rather than performing the scaling in software. If you are writing your own html shell for the exported .js, you'll need to do an unfiltered scale of the canvas to the desired size. (See the default exported 0.1.9 html shell for an example).

Pixel-Perfect Scaling

When changing the window size of PICO-8, or swapping from a window to fullscreen, PICO-8 now chooses the largest integer scaling factor that will fit inside the window to avoid blurry filtered pixels. For example, on a 1920x1080 real-world display, the largest scale is 8 which gives a 1024x1024 PICO-8 display.

PocketCHIP Update

We're working on it! I still can't give an eta on the PocketCHIP update, but the latest build is in testing and looks good across kernel versions, including GPIO access (so will likely skip to 0.1.9). It still needs to be coordinated with other things happening at Next Thing Co. though, so I'll keep you updated here.

Coming Up

There are still a bunch of small issues with the editors I'd like to improve, but PICO-8 is starting to look pretty close to beta! Next up will be website improvements to complement the clipboard & Jam category additions, and also long overdue support for touch devices. The main feature missing for beta is being able to login and submit scores from carts using SCORESUB(LEVEL, SCORE).

The next Voxatron update also has some new PICO-8 stuff -- the first version of the Voxatron API is a superset of PICO-8's and allows mapping one slice of Voxatron's display to PICO-8 video memory. (The display is basically a stack of 64 PICO-8 screen). So you'll be able to load PICO-8 cartridges into a Voxatron cartridge and make wee arcades and weird 3d ports and whatnot. It's fantasy consoles all the way down!



    Added: Copy and paste sprites and whole cartridges directly to BBS posts 
    Added: JAM category in splore
    Added: GPIO support for Raspberry Pi
    Added: Read clipboard using stat(4) after user presses CTRL-V
    Added: printh() can optionally write to a file or the host clipboard
    Added: Editor tool information and tips shown on mouseover
    Added: Set desktop path with -desktop (screenshots and gifs are saved here)
    Added: Warning on saving .p8 when compressed code size exceeds .p8.png limit
    Added: Alternative editor colours // config.txt: gui_theme 1
    Added: Dotted line every 8 rows in song view
    Added: -screenshot_scale (default: 3) and -gif_scale (default: 2)
    Added: Can use ctrl-up, ctrl-down to jump to start and end of code
    Added: CTRL-M to mute/unmute sound
    Added: HTML5-exported carts support 60fps
    Added: Timeout switch for splore downloads: -timeout
    Changed: Glyph characters typed with alt + a..z 
    Changed: stat(0) does not include allocations waiting to be garbage collected
    Changed: Unfiltered screen stretching at integer scales by default
    Changed: Removed -aspect and -scale settings (use draw_rect instead)
    Fixed: -home has no effect under Windows
    Fixed: Sometimes frame skipping starts before CPU useage has reached 100%
    Fixed: Double-speed BTNP() timing in 60fps mode
    Fixed: Exported HTML fails when _update60 is used instead of _update
    Fixed: Can't copy and paste button glyphs
    Fixed: Lines containing glyphs do not scroll far enough horizontally 
    Fixed: Loading .p8 renamed as .p8.png from splore freezes
    Fixed: Bucketfill in map doesn't sync to shared memory
    Fixed: fset fails when de-setting flags
    Fixed: Syntax error when beginning with the form: IF (..) [OR|AND]\n  
    Fixed: cls() costs twice as much cpu as it should
    Fixed: wav file exporter missing some data / writing truncated buffers
    Fixed: Entering new notes in song view doesn't observe current volume, instrument
    Fixed: alt-tab sometimes generates alt character text entry event
    Fixed: Resuming a cancelled download in splore causes crash
    Fixed: Controller attributes in log.txt always shown as -1  

P#28326 2016-09-11 15:55 ( Edited 2016-11-29 10:48)

View Older Posts
Follow Lexaloffle:        
Generated 2020-10-20 03:15 | 0.371s | 2097k | Q:189