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
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):
> EXPORT JELPI.BIN -I 48 JELPI.BIN JELPI.BIN/WINDOWS JELPI.BIN/LINUX JELPI.BIN/JELPI.APP
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.
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!):
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: FILLP(0b0011010101101000) 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
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.
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:
-- BUILD.P8 CD("MYPROJ") LOAD("TITLE.P8") EXPORT("MYGAME.BIN -I 1 LEVEL1.P8 LEVEL2.P8 LEVEL3.P8")
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
The template (in this example, one_button.html) can then be used when exporting like so:
>EXPORT FOO.HTML -P ONE_BUTTON
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.
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.
- 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))
- 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!
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
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
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:
LOAD("#45481","BACK TO LAUNCHER")
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
v0.1.11d 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 v0.1.11c 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 v0.1.11b Fixed: Preprocessor bug regressions: "if (..) or", "a.b -= c - d" Fixed: Crash when pressing menu button on an empty favourites list v0.1.11 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
Woah, that is a lot of changes! Thank you for all! I really enjoy code tabs! Also, I'm really happy, that pico-8 will go into beta soon!
Yay, a new "release post" :D
Normally I love seeing these, if only for the cute characters, but this release... is special. Thank you for all your hard work Zep, much appreciated! :o)
With regards to the "Cartverse"; I'm glad you already coined a name for this, coz I've been wondering what to call the ideas I've been having...
I've been thinking for a while now that, with this functionality, we can essentially create mini "PICO-8 Internet", where each cart can be the entry point to other cart "pico-sites", which link to other cart/pico-sites... etc. etc.
Some carts could be like mini websites (info about a topic/yourself/etc. perhaps with code examples/tutorials/etc. all linked together by Post/Cart ID's.
I'm picturing something like a cross-between the old Teletext/Ceefax system that used to be on TV's (pre-internet) and kinda like a good ol' dial-up BBS system. Where you have a few linked carts that represent your mini-site and other people's carts (in this whole Cartverse) can offer up links to yours.
Either way... this is all very, VERY interesting times! :D
.★❤ \(#.#)/ ❤★.
I love it all so much
whoaaa this cartverse concept is blowin my mind
what a great update! The API feels quite well-rounded now, with e.g. date/time access, the sfx length parameter, and that 1 remaining sfx bit used :D
Just a heads up, there are two more stray bugs in 0.1.11d that I'll patch in 0.1.11e soon:
- line numbers in error messages are broken for multiple tabs
- btn() with no parameters returns the same as btnp() // doesn't affect many carts, but is very confusing!
A mini cart internet, yes! There is a lot to take from this analogy -- homepages, hyperlinks, webrings all transfer in cute ways. The parameter strings in this context act like everything after the '?' in web urls, which is why the they are restored when popping back up the stack of previously visited carts -- they are part of the locator.
Something that feels like door games (with or without the cartverse) is something I'm also indirectly aiming for. Expandable MUDs, board games, turned based strategy games. It would be great! The online scores scheme is designed to be abused in order to store small amounts of persistent world data so that we can make such things.
0.1.12 won't be a very big update -- likely sometime in December to scoop up leftover bugs, add some html templates and an in-game options menu.
All sounds good to me (& thx for the heads-up) :D
Please take a peek at this...?
If you think it has any merit, it would be better to consider it sooner rather than later before the current implementation gets too ingrained...
btn() w/o parameters acting as btnp() is a problem in many of my carts. For example in tweetcarts I use
as a shorten syntax for setting player position when pressing left or right. Now it is suuuuper slow. :(
Same in other games where I just check if player press any arrow with
if band(btn(),15)>0 then
which is kinda broken now.
EDIT: oh, just saw it'd be part of next version bugfixes, cool then!
also btnp() bit 6 is gone (menu button). it could be used with poke(0x5f30,1) to enable a custom pause menu.
well, it wasn't documented, but I was hoping for it to be at some point...
This is super cool, started playing with it on my retropie rig.
Being able to exit without using a keyboard or forcing a reboot over putty is AWESOME!!! It fits perfectly into my retropie now!
Unfortunately I'm having a weird bug with the audio where it just cuts out every 10-15 seconds. I don't remember this happening on the last version I used, so it may be new.
Thanks for the hard work, this cartverse stuff is going to be AMAZING.
Assorted bugs I've noticed in 0.1.11d:
- occasionally the editor will start interpreting the "X" key as a left-mouse click instead of a key press. When this happens, it's necessary to quit and restart the program. (Toggling the "keyboard cursor" option does nothing.)
- two of my favorite older carts—Postcards from the Fringe and Endless Sky, both by @electricgryphon—are broken in 0.1.11. Both feature similar visual artifacts and Postcards from the Fringe will occasionally crash on load.
(I'm on a 2017 MacBook Pro / OS X Sierra)
Any update on a Pocket CHIP build?
How do I update? I Cant wait to make an OS. Something I wanted to do for so long!!
It seems like the i386 version is actually x86-64. It would be nice to get a real i386 version. :-)
pico-8/pico8: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=a589ada4e62f733db872d5a55494f1af37f66726, with debug_info, not stripped
I really like the -x addition. I’ve used Pico-8 to draw some stuff and create maps for some c64 tests. It’s nice to be able to put the exporting into the build process.
I’ve only got my iPad here with me now. Does anyone know if -x and stat(6) work together? I.e. is it possible to give the cart parameters from the command line?
0.1.11g is now available at Lexaloffle and Humble.
More bug fixes, correct 32-bit Linux executeable this time, and I've included pico8_dyn in all 3 linux versions should you want to provide your own SDL.
Also, a NextThing build of 0.1.11g for PocketCHIP / CHIP is available! You can update by opening terminal and doing:
sudo apt update && sudo apt install chip-pico-8
(password is chip)
Alternatively, it's also included in the list of packages to update when upgrading:
sudo apt upgrade
Because of improved adaptive framerate handling introduced earlier in 0.1.11, there is much less slowdown on heavier carts running on the PocketCHIP.
There are a couple of features (content filter, cartverse id support) that aren't live yet, but will become operational after the next BBS update.
If there are no serious issues, this will be the last time the file version is bumped for a while, so we can get some future compatibility going again. But you'll need to update to this version in order to play any carts made in 0.1.11g.
v0.1.11g Added: CTRL-C to copy contents of commandline Added: stat(100..102) for current breadcrumb label, bbs cart id, and hostname (web) Added: content_filter in config.txt Added: Cartverse cart id support (not live server-side yet though) Fixed: Tab preview does not show on mouseover Fixed: Can't paste uppercase characters into commandline Fixed: Preprocessor can't handle glyphs in form: "♥.x += 1" Fixed: Unsaved changes sometimes reported when filename is not set Fixed: Pause menu doesn't open inside infinite loop inside _draw Fixed: load() crashes when "parameter string" parameter is not a string Fixed: cstore(),reload() crash when external cart filename is not a string Fixed: printh(str, "@clip") fails for glyph characters in str
Hey zep, I have an issue. I think it's been around for quite a while, but since you're close to locking some stuff down, I think I should get it on your radar:
Background: if I run the app windowed, on Windows 7 x64 in my case, with my monitor set to a refresh rate of 60Hz, it holds vsync as steady as a rock. I can flip between red and green and get a uniform khaki color. No tearing, no dropping, just a little bit of blood from my eyes.
However, if I up the desktop refresh rate to 120Hz, which is becoming much more common among gamers, and which I would prefer to do all of the time, pico-8 starts tearing very badly and dropping frames all over the place. It's a real mess. My eyes have exploded so many times that I've had to ask our waste disposal company for an extra biomass container.
I'd expect it to handle an even multiple of 60 gracefully. I know 144Hz or 90Hz isn't going to work cleanly, but if the desktop is running at an even multiple of 60, it really ought to be able to work flawlessly.
If it helps, the FPS counter wibbles around the neighborhood of 110-115fps, but I've seen it go as low as 107 and as high as 120.
Also, this is irrespective of window size and scaling, and I'm running it on a very capable cpu with an extremely capable gpu.
Finally, this is the program I test with:
function _update60() end c=8 function _draw() rectfill(c-8,0,c+116,127,c) c=19-c end
Also, this other bug persists in 0.1.11g:
Thanks for the update so I can use assert(coresume( feels cleaner than the workaround I had been using before to printout errors from within coroutines!
I'm very happy with this update.
Specially with the command line option -x.
This will open the way for tool making.
it still requires SDL2 (along with the video/audio driver) -- e.g. you can still play sound from it
I tried playing sounds with the -x option but it crashes :C.
I hope there will be a way to create a command line utility for playing music only carts.
Plays Music 0 All Channels
pico8 -m 0 music.p8
Plays Music 0 Channel 1
pico8 -m 0 -c 1 music.p8
Plays Music 0 Channels 1 2
pico8 -m 0 -c 1,2 music.p8
Thanks for all your efforts zep :)
Was messing around with 0.1.11G in the music editor and I noticed some oddities in SFX editing. Putting a value in the volume column automatically makes a note appear there (usually C1); and then trying to backspace that value or note would result in the entire lineup of notes being bumped up a space, without any noticable way to "insert" a blank note in its' place. The backspacing issue happens on existing notes now, too; so it's not limited to just that. But there doesn't seem to be a way to eliminate accidental note placements in ways that doesn't screw up the rest of the SFX's structure.
Unless I'm missing some new hotkeys now, which I might be. Good thing I had saved before that!
I think the key you are looking for to insert a blank note is Enter.
To delete without moving other notes, you can highlight some part of the note's row of numbers (using Shift + left/right) and then push either Backspace or Delete.
When entering notes and making a mistake, though, I usually just push Up (to go to the previous note) and and then retype the note, because entering new things overwrites whatever is under the cursor.
As for entering a volume value and making a note appear, keep in mind that the determining factor that indicates if a note is played or not is the volume being greater than 0, so when you set the volume to anything other than 0, you are declaring that there is a note there now :) (and in cases of arpeggiation, the pitch is actually still used in the arpeggio, even if that note has 0 volume, which is why such notes now show up as visible if they are within an arpeggio group)
Ahhh, okay. I was trying "Insert" which wasn't doing anything; and expecting Enter to do the same as the spacebar, to play/pause the section. Thank you!
[Please log in to post a comment]