Log In  
[back to top]

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)

Cart #26194 | 2016-07-31 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Here's a 7500 word dictionary cart for making word games and whatnot. It contains the most common 3-6 letter words according to wiktionary.com, including proper names. The loader is 264 tokens, and the data is 11317, stored over the full map (including shared gfx), plus the last 44 SFX. So there are just 128 sprites and 20 SFX spare. The 5 most common and 10 least common words on the list are:



Technical details..

The data is generated using a convoluted toolchain process, that I'll post later on if I find time to organize it into something useful.

The compression works by enumerating every possible word in order of word size first, and then alphabetical order. So, A is 0, B is 1, AA is 26, and so on. This means that to store the whole dictionary, only the distances between each word's index is needed. There are many clusters of close words (e.g the distance between CAN and CAP is only 2), so the distances are sorted into range categories depending on how many bits are needed to store each range. Repeated categories are common and so can be encoded with a single bit -- otherwise a 3-bit value is used to store the category for each distance. The encoding utility greedy-searches sets of 5 category bit-lengths and a roman cypher to try to optimize the encoded size, which saved around 1k compared with hand-optimizing the parameter set.

P#26196 2016-07-31 02:23 ( Edited 2018-09-30 16:15)


PX8 has been replaced by PX9: https://www.lexaloffle.com/bbs/?tid=34058

But I'll leave this here for reference, and for existing projects using PX8.

Cart #25919 | 2016-07-26 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This is a library mostly for compressing graphics and maps, but can also be adapted to compress sfx. It is designed for data-heavy carts and requires around 450 tokens for decompression, although this can be reduced if needed by removing remap(), hard-coding parameters, and/or removing predicted spans at the cost of compression performance. If someone wants a smaller/weaker version, let me know!

To use it, compress a 2D rectangle to an address in memory, and supply a function for fetching the source values (normally SGET or MGET). For map data, you probably want to set p.cbits to something like 4 first.

COMP(0, 0, 128, 64, 0x2000, SGET)

0x2000 is the address of the top half of the map, so this will compress the top half of the sprite sheet (128 sprites) and write the compresed data over the map data.

DECOMP() takes the memory address of the compressed data, the top left corner of where to decompress to, and functions for getting and setting decompressed values. So to decompress this data at 0x2000 back to the screen, starting 32 pixels down:

DECOMP(0x2000, 0, 32, PGET, PSET)

Only the decompression section of the code is needed once you have compressed data stored on a cart. A typical workflow would be to make a utility cartridge that grabs data from multiple source cartridges (using RELOAD() with a 4th parameter to indicate where to read from), and then CSTORE them to a single cartridge (again, using CSTORE()'s 4th external cart parameter).

Here's an example that stores 2-byte lengths at the start of each compressed block, to allow seeking out the start of any given gfx. I've commented the cstore and reload lines so that it will work if you paste it at the end of the main PX8 cart example:

-- px8 workflow example:
-- storing multiple compressed images and fetching them

-- 1. make a utility cart that
-- compresses all the needed
-- data to a single cart

local base_offset = 0x2000
local offset = base_offset

-- compress some gfx and
-- add the length of the compressed
-- data at the start (2 bytes)
function add_gfx(x,y,w,h)

 local len = comp(x,y,w,h,offset+2,sget)
 printh("wrote "..offset)
 offset += len+2


-- jelpi frames + mushroom

-- could load another cart's
-- spritesheet at any time
-- reload(0,0,0x1000,"blah.p8")

-- vegetation

-- store in target cart
-- cstore(0x2000,0x2000,(offset-base_offset),"out.p8")


-- 2. load the compressed data
-- (from the cart it was
-- compressed to)

base_offset = 0x2000

-- skip through compressed data
-- blocks and load the one at
-- index
function load_gfx(index,x,y)

 local offset=base_offset
 for i=0,index-1 do
  offset += peek(offset+0) + peek(offset+1)*256 + 2

 -- use sget,sset to write back
 -- to the spritesheet instead
 -- of the screen


-- test

load_gfx(0, 20,10)
load_gfx(1, 20,40)
load_gfx(2, 80,10)

The Algorithm

I started working on PX8 while working on PICO-8's specs, as an important question was how large a game could theoretically be for hard-core users who want to go to the trouble of compressing stuff. It became something of a brainworm, and releasing PX8 is a way to get this out of my system. I hope it is also useful to someone, or at least interesting.

PX8 is (AFAIK) a novel algorithm that appears to work well for typical PICO-8 data, and out-performs pngcrush -brute for the few 16-colour images I tested. Alternating spans of predicted and non-predicted values are stored:

  1. Predicted values (colours) are calculated by maintaing a table of the last encountered matching neighbours: if a match top & left is found, that is taken to be the prediction. Otherwise, a match for only top, and then only left are considered. Failing those, the value is taken to be non-predicted.

  2. Non-predicted values are stored as indexes into CLIST; a list of literal values that are stored in the order they were last encountered. This means that recently encountered values have smaller indexes, and the encoding exploits this, along with the fact that each index can not possibly be for the failed prediction (in which case it would be part of a predicted span).

Each span is strictly made of either all predicted or all non-predicted values. This means that for predicted spans, no additional information needs to be stored except the length of the span itself. And conversely for unpredicted values, the index into CLIST is known to not point at the predicted value. This means that no colour index data needs to be stored for 2 colour images at all, and the compressed data is composed entirely of span lengths.

P#25922 2016-07-26 12:59 ( Edited 2019-04-26 18:43)

Hey All -- PICO-8 0.1.8 builds are now live on Lexaloffle and Humble! Note that there was no 0.1.7 release for Desktop; there were in-development versions of 0.1.7 released early for web and Pocket C.H.I.P. to resolve pressing issues, so I'm calling this 0.1.8 to keep version numbers in sync across platforms. New stuff:

60 FPS support

This breaks the 'every cart runs the same on all PICO-8s' rule of PICO-8's design philosophy a little bit, but I think it's worth it! On all of the desktop host platforms, it is now possible to make cartridges that display and update at 60 frames per second instead of 30. You don't get any more CPU though, so that means half the usual CPU allowance per frame. From the manual:

:: Running PICO-8 at 60fps

If _update60() is defined instead of _update(), PICO-8 will run in 60fps mode:
    - both _update60() and _draw() are called at 60fps
    - half the PICO-8 CPU is available per frame before dropping down to 30fps

** please note that not all PICO-8s support 60fps. On machines that do not support it, _update60() will instead be called twice per frame and _draw() at 30fps. You can check the behaviour of your program running at 30fps by adding the following snippet to the bottom of your code:

    u60=_update60 _update60=nil function _update() u60() u60() end

Button Glyphs

The two action buttons on the PICO-8 controller are called O (BTN(4)) and X (BTN(5)). To make it easier to print instruction in-game explaining the controls, you can now insert glyph characters directly into strings in your code with Shift - U D L R O X.

Long GIFs

Adjust the maximum GIF length in config.txt or by running PICO-8 with -gif_len n switch, where n is the number of seconds to record for (maximum: 120). The GIF output is not optimized, so you might want to run it through an optimizer to get smaller file sizes.

Custom Menu Items

It is now also possible to add your own items to the pause menu to trigger things like 'RESTART PUZZLE' or 'EXIT TO OVERWORLD'. Here's an example program:


function _draw()

function changecol()
  col = (col+1)

menuitem(1, "change colour", changecol)

The first parameter is the position (1-5) in the menu to insert the item, the second is the item's label, and the 3rd is a function to be called when the item is selected. I opted to keep this simple and quite rigid, so there's no way to have extra stuff going on in the background while the cart is paused, or to re-appropriate the pause button as an in-game button.

Music Exporter

To record a .wav of a PICO-8 tune, first navigate to the pattern you'd like to start from in the music editing mode, then press escape to enter the console and type:


If the song is looping, it will export around 4:30 that you can then manually trim in a [sound editing program](http s://sourceforge.net/projects/audacity/).

Pre-installed Games

There are now 5 BBS games that ship included with PICO-8, so that it's easy to get up and playing something more than the demo carts, even when internet access is not immediately available. To install them, use INSTALL_GAMES -- they will be accessible from your favourites list in SPLORE. The games are Celeste, Frog Home, Tower of Archeos, Hug Arena, and Dusk Child.

Linux Builds

I've included both statically and dynamically linked versions of the executables for i386, amd64 and Raspberry Pi. The RasPi build still depends on bcm, so it is tricky (impossible?) to get it up and running on Chromebooks.
I plan to look at better Chromebook support at some point, but it will probably have to be during beta. Pocket C.H.I.P. owners, and later on regular C.H.I.P. owners can expect updates too, of course --- but we are still sorting out details and it will take a while. o( )o

Next up, 0.1.9 will be mostly ongoing bugfixes, and improvements to the web player (optimization, fold-out touch controls for mobile, and controller instructions).

Full Changelog:


        Added: 60fps support
        Added: Music exporter
        Added: Custom GIF length (maximum 120 seconds)
        Added: -,+ to navigate sprite tabs, sfx, music patterns
        Added: sfx editor: navigate with home, end, pageup/down, mousewheel
        Added: <, > to modify sfx speed, or click and drag
        Added: Middle mouse button to pan around spritesheet / map
        Added: Shortcut command for splore: S
        Added: Pre-installed selection of BBS cart (use INSTALL_GAMES)
        Added: Warning when saving .p8.png with no label 
        Added: (OSX) logging to ~/Library/Logs (viewable with Console.app)
        Changed: Can not CTRL-S save over a loaded bbs cart
        Changed: Only .p8 files listed by dir() and by splore
        Changed: Command history increased to 256
        Changed: exit() / shutdown() have no effect while running cart
        Fixed: Memory useage (stat(0)) inconsistent across host platforms
        Fixed: Spinny disks shows when reloading current cart with load()
        Fixed: GIF saver does not respect 64x64 / mirrored modes
        Fixed: Miscellaneous multi-line comments / strings issues
        Fixed: Empty map cels cost cpu in mapdraw()
        Fixed: mapdraw() slowdown when drawing bottom half of map
        Fixed: preprocess changes semantics when += and : operators on same line
        Fixed: Identifiers starting with underscore counted as extra token
        Fixed: Saving .png exceeding compressed code limit fails silently
        Fixed: Right-clicking a sprite does not set the currently edited sprite
        Fixed: (Windows) extra space added to pasted lines
        Fixed: spr() expensive when drawn with low negative coordinates
        Fixed: pipe character identical to colon character
        Fixed: (Raspberry Pi) shift key appends a character when entering text
        Fixed: Editor mode buttons are still clickable during cart runtime
        Fixed: When loading a .p8.png file, label is reset and needs to be re-captured
        Fixed: export() does not report failure
        Fixed: mset()'d changes in shared memory not readable via peek() / sget()
        Fixed: cstore() saving edited code
        Fixed: audio pop between patterns during music playback


        Added: menuitem()
        Added: button glyphs in code (shift-L, R, U, D, X, O)
        Added: Customisable data directory (e.g. pico8 -home mydata)
        Added: Web gpio pins: read and write pico8_gpio[] in javscript 
        Fixed: SPLORE search doesn't reset
        Fixed: Splore skipping 33rd cart listing after loading more items
        Fixed: Crash when selecting a local binary file in splore
        Fixed: Semicolon can't be used as a list or statement separator 
        Fixed: Exported html can not cstore self

P#23669 2016-06-26 10:41 ( Edited 2016-08-01 19:29)

The theme for the second PICO-8 Jam was Chain Reaction, and there were 35 entries. Thanks to everyone who contributed and made this jam a another splendid event. I hope you'll join me in congratulating the winning entry, which received a whopping 7.3 PICO-8 star average.. theatrically opens invisible envelope

NuSan! With Combo Pool.

Cart #21659 | 2016-05-29 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

As a token of gratitude for laying down this most excellent cartridge, NuSan will be receiving a commemorative cross-stitch based on the cart.

Also highly rated by participants was another disarming production by JTE: Nora's Mouse Chase, and the beautifully chaotic SPACETANK 9000 by arnodick.

You can play all of the entries by clicking on this montage:

That was fun -- let's do it again sometime soon!

P#22395 2016-06-06 06:11 ( Edited 2017-12-09 14:29)

If you'd like to take part in P8JAM2, please select one or more themes by clicking on the PICO-8 star next to it (you need to be logged in). You can change it anytime before the 24h voting phase ends -- at 00:00 PST on Saturday the 21st. Check out the jam thread for more details.

Edit: times's up! The winning theme is Chain Reaction. You have 9 days! Good luck!

P#20883 2016-05-20 03:00 ( Edited 2016-05-20 07:00)

Hey All

I'm in the process of simplifying the website a little. In particular, I wanted to improve the experience of playing cartridges in threads by removing clutter. They now look more like a page dedicated to the cart:

  • The player starts open
  • There's a big obvious play button and large thumbnail
  • There's no banner at the top of each page

Cart #20430 | 2016-05-11 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

I removed the PLAY buttons from the thread previews, and autoplay, as I think they're no longer needed -- the whole playable region of a cart is now visible without scrolling after opening the cart's thread, and it's more obvious to new visitors what to do next.

There are still a few small things to finish, but let me know what you think of the new layout, and if there's anything that bugs you.

P#20716 2016-05-17 16:25 ( Edited 2016-05-17 20:25)

Time for another jam! EDIT: The theme is Chain Reaction.

and... that's time! Thanks everyone who contributed a cartridge! If you submitted something with the p8jam2 tag, you can now rate other p8jam2-tagged carts at the top of the cart's thread.


If you'd like to continue working on your cartridges, feel free -- but please leave the compo version at the top of the p8jam2-tagged threads until voting finishes in one week (June 5, 24:00 PST). Good luck!

Cart #20430 | 2016-05-11 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Same deal as last time, except with some limited theme voting:

Duration: The Jam will take place from 00:00 PST on Saturday the 21st of May 2016 and will finish at 24:00 PST on Sunday the 29th. So, it spans 2 weekends and 5 weekdays. You can spend as much or little time on your carts as you like. Tiny silly cartridges are more than welcome.

Theme: As is customary with other jams, a theme will be posted at the start and the goal is simply to make a cart (or some carts) during the jam that reflect your interpretation of the theme. Any type of cartridge is ok: games, toys, demos, music carts or pixels.

This time, the theme will be selected by a small twitter poll that begins 24 hours before the jam starts.

Submitting: To submit or update a jam cart before the deadline, just tag it with p8jam2. You can update your cartridge as often as you like before the deadline.

Voting: Jam participants will be able to use a voting widget on all p8jam2-tagged carts, and exactly 1 week after the jam finished, ratings will be tallied.

There will be a small mystery prize for the highest rated cart, but you should enter for glory and honor (or just for kicks).

During the jam, you'll be able to view all carts and posts tagged with p8jam2.

Rules: Teams / collaborations are allowed, in which case you should nominate one user to be the submitter (and voter). Re-using existing PICO-8 cart material is allowed as long as it is ok by the author, and that the carts are publicly available before the jam starts. Submissions should be mostly new material created during the jam, but it's ultimately up to other participants making ratings to decide what's cool and what's not.

P#20432 2016-05-11 09:06 ( Edited 2016-05-11 13:06)

If you're looking for a complete portable PICO-8 solution, good news! PICO-8 is going to ship pre-installed on Next Thing Co.'s upcoming PocketC.H.I.P. -- a complete portable mini-computer with built-in storage, wifi, keyboard, battery, touchscreen and everything else PICO-8 needs! The last few months, I've been working closely with the team at Next Thing Co. to create "PICO-8 C" -- a fully functioning and compatible edition designed to integrate nicely with NTC's hardware and software. It will be available to Kickstarter backers, or you can also pre-order one for just $49 bucks.

You can read more about the PocketC.H.I.P. over at getchip.com

P#20121 2016-05-03 09:19 ( Edited 2016-10-02 00:48)

Here's 0.1.6! You can download it from your updates page while you're logged in, or from your Humble Store Library. Just a reminder, that if you're a Voxatron alpha customer, you also own PICO-8! (it should show up automatically in both places).

By far the biggest change is the addition of SPLORE, a complete bbs and local cartridge explorer. You can run it by typing SPLORE, or start PICO-8 with "pico-8 -splore". If you plug a joystick in and auto-boot into splore, it's possible to navigate everything using only the 6 buttons + menu button.

This version also has a lot of new data storage functionality. Cartridges can cstore() to themselves in order to save extra data, and this is now officially supported on the web, so don't feel like it's a weird hack that's going to break! (actually it might break, but it's supported, so I'll fix it :p). Here's a demo:

Cart #19844 | 2016-04-17 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Notes on cartridge storage, and the full change log:

    Cartridge Data

    Each cartidge is able to store 64 numbers (256 bytes) of persistent data 
    on the user's PICO-8 (rather than on the cart itself). This can be used as
    a lightweight way to store things like high scores or to save player progress.

    If you need more than 256 bytes, it is also possible to write directly to the
    cartridge using cstore(). The disadvantage is that the data is tied to that
    particular version of the cartridge. e.g. if a game is updated, players will
    lose their savegames.

    Another alternative is to write directly to a second cartridge by specifying
    a fourth parameter to cstore(). This requires a cart swap though (so is 
    slightly slower), and leaves data-cart litter when run from a local folder.


        Added: SPLORE local & bbs cartridge explorer
        Added: setmetatable(), cocreate(), coresume(), costatus(), yield()
        Added: Spinning cart icon to show when a cart is swapped / written to
        Added: Permanent storage when carts played in a browser
        Added: Adjustable aspect ratio (-aspect 420 for 1:1)
        Changed: Lua memory limit: 1024k (was 512k)
        Changed: Music channel now resumes after being clobbered by an sfx 
        Changed: Arpeggios double speed when SFX speed <= 8
        Changed: Exceeding compressed code limit does not block saving in .p8 format 
        Changed: spr() half as expensive, to be consistent with map()
        Changed: Fractional hex number notation: 0x0.3 == 0x0.3000, (was 0x0.0003)
        Changed: : operator doesn't count as an extra token (same as .)
        Changed: cstore() writes directly to disk
        Changed: cstore(), reload() return number of bytes read / written
        Changed: save() while running does nothing. (use cstore() instead)
        Changed: load() while running loads and runs the specified cartridge 
        Fixed: Small pops in audio mixer caused by sound wave discontinuities
        Fixed: HTML5-exported sound clicks badly under Chrome
        Fixed: Display palette is not oberserved when exporting GIFs
        Fixed: Rapid keypresses causes duplicate readings in tracker & text editor
        Fixed: += inside comments breaks preprocessor
        Fixed: sspr() cpu cost the same when clipped
        Fixed: cartdata() with bad parameters crashes
        Fixed: EXPORT from commandline can not be used without brackets and quotes

P#19847 2016-04-17 18:48 ( Edited 2016-06-03 02:10)

Cart #19844 | 2016-04-17 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

This is a demo of the new cartridge storing in 0.1.6. (you'll need to update to 0.1.6 if you load this in PICO-8)

Press O (mapped to Z or C) to save the screen, and X to restore it. The cursor position is not saved.

To save, the screen is copied to the sprite sheet and then stored for clarity -- but it could have just been a straight cstore(0x0, 0x6000, 0x2000), and same again in reverse when restoring.

 if (btn(4)) then

 if (btn(5)) then
  len = reload()

This should also work in your browser, even if you close it and run the cartridge again. Please let me know if it doesn't!

Note that in 0.1.6 you can also cstore to separate cartridge files, meaning we can have quite large save games, and also saved data shared between carts on the bbs.

P#19845 2016-04-17 18:41 ( Edited 2016-06-10 10:20)

A build of PICO-8 0.1.5 is now available for Raspberry Pi! Check your updates page or look in your Humble library under the Linux downloads section.

It works in fullscreen under either X Windows or directly from the terminal (using directfb). For speed, the default resolution is 280,280; you can set this with the -width and -height switches:

pico8 -width 720 -height 480

Known issues:

  • After quitting, keypresses during the session are sometimes dumped to terminal (annoying if you quit by typing shutdown instead of CTRL-Q!)
  • Freeze on exit (observed on a zero)
  • Some math-heavy cartridges (e.g. /demos/cast.p8) don't run at full speed on first generation models.

There are two builds included in the archive. pico8 is compiled statically (so no need to install SDL2), and pico8_dyn dynamically loads libraries, in case you'd like to supply your own SDL2.

Have fun, and please post pictures if you get pico-8 running on any cute displays!

P#18975 2016-02-26 17:14 ( Edited 2016-02-26 22:14)

View Older Posts
Follow Lexaloffle:        
Generated 2021-10-20 19:58:36 | 0.225s | Q:65